mirror of
https://github.com/ANL-CEEESA/MIPLearn.jl.git
synced 2025-12-06 16:38:51 -06:00
Update to JuMP 1.2 and MOI 1.7
This commit is contained in:
36
src/bb/lp.jl
36
src/bb/lp.jl
@@ -16,6 +16,7 @@ end
|
||||
function read!(mip::MIP, filename::AbstractString)::Nothing
|
||||
@threads for t = 1:nthreads()
|
||||
model = read_from_file(filename)
|
||||
set_optimizer(model, mip.constructor)
|
||||
mip.optimizers[t] = backend(model)
|
||||
_replace_zero_one!(mip.optimizers[t])
|
||||
if t == 1
|
||||
@@ -24,21 +25,20 @@ function read!(mip::MIP, filename::AbstractString)::Nothing
|
||||
mip.sense = _get_objective_sense(mip.optimizers[t])
|
||||
end
|
||||
_relax_integrality!(mip.optimizers[t])
|
||||
set_optimizer(model, mip.constructor)
|
||||
set_silent(model)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function _assert_supported(optimizer::MOI.AbstractOptimizer)::Nothing
|
||||
types = MOI.get(optimizer, MOI.ListOfConstraints())
|
||||
types = MOI.get(optimizer, MOI.ListOfConstraintTypesPresent())
|
||||
for (F, S) in types
|
||||
_assert_supported(F, S)
|
||||
end
|
||||
end
|
||||
|
||||
function _assert_supported(F::DataType, S::DataType)::Nothing
|
||||
if F in [MOI.ScalarAffineFunction{Float64}, MOI.SingleVariable] && S in [
|
||||
function _assert_supported(F::Type, S::Type)::Nothing
|
||||
if F in [MOI.ScalarAffineFunction{Float64}, MOI.VariableIndex] && S in [
|
||||
MOI.LessThan{Float64},
|
||||
MOI.GreaterThan{Float64},
|
||||
MOI.EqualTo{Float64},
|
||||
@@ -46,7 +46,7 @@ function _assert_supported(F::DataType, S::DataType)::Nothing
|
||||
]
|
||||
return
|
||||
end
|
||||
if F in [MOI.SingleVariable] && S in [MOI.Integer, MOI.ZeroOne]
|
||||
if F in [MOI.VariableIndex] && S in [MOI.Integer, MOI.ZeroOne]
|
||||
return
|
||||
end
|
||||
error("MOI constraint not supported: $F in $S")
|
||||
@@ -64,19 +64,19 @@ function _get_objective_sense(optimizer::MOI.AbstractOptimizer)::Float64
|
||||
end
|
||||
|
||||
_bounds_constraint(v::Variable) =
|
||||
MOI.ConstraintIndex{MOI.SingleVariable,MOI.Interval{Float64}}(v.index)
|
||||
MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{Float64}}(v.index)
|
||||
|
||||
function _replace_zero_one!(optimizer::MOI.AbstractOptimizer)::Nothing
|
||||
constrs_to_delete = MOI.ConstraintIndex[]
|
||||
funcs = MOI.SingleVariable[]
|
||||
funcs = MOI.VariableIndex[]
|
||||
sets = Union{MOI.Interval,MOI.Integer}[]
|
||||
for ci in
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.SingleVariable,MOI.ZeroOne}())
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.ZeroOne}())
|
||||
func = MOI.get(optimizer, MOI.ConstraintFunction(), ci)
|
||||
var = func.variable
|
||||
var = func.value
|
||||
push!(constrs_to_delete, ci)
|
||||
push!(funcs, MOI.SingleVariable(var))
|
||||
push!(funcs, MOI.SingleVariable(var))
|
||||
push!(funcs, MOI.VariableIndex(var))
|
||||
push!(funcs, MOI.VariableIndex(var))
|
||||
push!(sets, MOI.Interval{Float64}(0.0, 1.0))
|
||||
push!(sets, MOI.Integer())
|
||||
end
|
||||
@@ -88,9 +88,9 @@ end
|
||||
function _get_binary_variables(optimizer::MOI.AbstractOptimizer)::Vector{Variable}
|
||||
vars = Variable[]
|
||||
for ci in
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.SingleVariable,MOI.Integer}())
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.Integer}())
|
||||
func = MOI.get(optimizer, MOI.ConstraintFunction(), ci)
|
||||
var = Variable(func.variable.value)
|
||||
var = Variable(func.value)
|
||||
|
||||
MOI.is_valid(optimizer, _bounds_constraint(var)) ||
|
||||
error("$var is not interval-constrained")
|
||||
@@ -105,7 +105,7 @@ end
|
||||
|
||||
function _relax_integrality!(optimizer::MOI.AbstractOptimizer)::Nothing
|
||||
indices =
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.SingleVariable,MOI.Integer}())
|
||||
MOI.get(optimizer, MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.Integer}())
|
||||
MOI.delete(optimizer, indices)
|
||||
end
|
||||
|
||||
@@ -146,7 +146,7 @@ function values(mip::MIP, vars::Vector{Variable})::Array{Float64}
|
||||
return MOI.get(
|
||||
mip.optimizers[threadid()],
|
||||
MOI.VariablePrimal(),
|
||||
convert.(MOI.VariableIndex, vars),
|
||||
[MOI.VariableIndex(v.index) for v in vars],
|
||||
)
|
||||
end
|
||||
|
||||
@@ -170,10 +170,10 @@ function set_bounds!(
|
||||
)::Nothing
|
||||
t = threadid()
|
||||
MOI.delete(mip.optimizers[t], _bounds_constraint.(vars))
|
||||
funcs = MOI.SingleVariable[]
|
||||
funcs = MOI.VariableIndex[]
|
||||
sets = MOI.Interval[]
|
||||
for j = 1:length(vars)
|
||||
push!(funcs, MOI.SingleVariable(vars[j]))
|
||||
push!(funcs, MOI.VariableIndex(vars[j].index))
|
||||
push!(sets, MOI.Interval(lb[j], ub[j]))
|
||||
end
|
||||
MOI.add_constraints(mip.optimizers[t], funcs, sets)
|
||||
@@ -187,7 +187,7 @@ Return the name of the decision variable `var`.
|
||||
"""
|
||||
function name(mip::MIP, var::Variable)::String
|
||||
t = threadid()
|
||||
return MOI.get(mip.optimizers[t], MOI.VariableName(), convert(MOI.VariableIndex, var))
|
||||
return MOI.get(mip.optimizers[t], MOI.VariableName(), MOI.VariableIndex(var.index))
|
||||
end
|
||||
|
||||
convert(::Type{MOI.VariableIndex}, v::Variable) = MOI.VariableIndex(v.index)
|
||||
|
||||
@@ -14,7 +14,7 @@ import JuMP: value
|
||||
|
||||
Base.@kwdef mutable struct JuMPSolverData
|
||||
optimizer_factory::Any
|
||||
basis_status::Dict{ConstraintRef,MOI.BasisStatusCode} = Dict()
|
||||
basis_status::Dict = Dict()
|
||||
bin_vars::Vector{JuMP.VariableRef} = []
|
||||
int_vars::Vector{JuMP.VariableRef} = []
|
||||
cb_data::Any = nothing
|
||||
@@ -64,6 +64,7 @@ function _update_solution!(data::JuMPSolverData)
|
||||
data.reduced_costs = []
|
||||
data.basis_status = Dict()
|
||||
|
||||
# Reduced costs
|
||||
for var in vars
|
||||
rc = 0.0
|
||||
if has_upper_bound(var)
|
||||
@@ -77,6 +78,13 @@ function _update_solution!(data::JuMPSolverData)
|
||||
rc += shadow_price(FixRef(var))
|
||||
end
|
||||
push!(data.reduced_costs, rc)
|
||||
|
||||
# Basis status
|
||||
data.basis_status[var] = MOI.get(
|
||||
data.model,
|
||||
MOI.VariableBasisStatus(),
|
||||
var,
|
||||
)
|
||||
end
|
||||
|
||||
try
|
||||
@@ -85,27 +93,18 @@ function _update_solution!(data::JuMPSolverData)
|
||||
@warn "Sensitivity analysis is unavailable; ignoring" maxlog = 1
|
||||
end
|
||||
|
||||
basis_status_supported = true
|
||||
data.dual_values = Dict()
|
||||
for (ftype, stype) in JuMP.list_of_constraint_types(data.model)
|
||||
ftype != VariableRef || continue
|
||||
for constr in JuMP.all_constraints(data.model, ftype, stype)
|
||||
# Dual values (FIXME: Remove negative sign)
|
||||
data.dual_values[constr] = -JuMP.dual(constr)
|
||||
|
||||
# Basis status
|
||||
if basis_status_supported
|
||||
try
|
||||
data.basis_status[constr] =
|
||||
MOI.get(data.model, MOI.ConstraintBasisStatus(), constr)
|
||||
catch
|
||||
@warn "Basis status is unavailable; ignoring" maxlog = 1
|
||||
basis_status_supported = false
|
||||
data.basis_status = Dict()
|
||||
end
|
||||
end
|
||||
data.basis_status[constr] =
|
||||
MOI.get(data.model, MOI.ConstraintBasisStatus(), constr)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
data.reduced_costs = []
|
||||
data.dual_values = Dict()
|
||||
@@ -439,18 +438,15 @@ function get_variables(data::JuMPSolverData; with_static::Bool, with_sa::Bool)
|
||||
if !isempty(data.basis_status)
|
||||
basis_status = []
|
||||
for v in vars
|
||||
basis_status_v = "B"
|
||||
if has_lower_bound(v)
|
||||
constr = LowerBoundRef(v)
|
||||
if data.basis_status[constr] == MOI.NONBASIC
|
||||
basis_status_v = "L"
|
||||
end
|
||||
end
|
||||
if has_upper_bound(v)
|
||||
constr = UpperBoundRef(v)
|
||||
if data.basis_status[constr] == MOI.NONBASIC
|
||||
basis_status_v = "U"
|
||||
end
|
||||
bstatus = data.basis_status[v]
|
||||
if bstatus == MOI.BASIC
|
||||
basis_status_v = "B"
|
||||
elseif bstatus == MOI.NONBASIC_AT_LOWER
|
||||
basis_status_v = "L"
|
||||
elseif bstatus == MOI.NONBASIC_AT_UPPER
|
||||
basis_status_v = "U"
|
||||
else
|
||||
error("Unknown basis status: $(bstatus)")
|
||||
end
|
||||
push!(basis_status, basis_status_v)
|
||||
end
|
||||
@@ -530,7 +526,7 @@ function get_constraints(
|
||||
end
|
||||
push!(rhs, rhs_c)
|
||||
for term in cf.terms
|
||||
push!(lhs_cols, term.variable_index.value)
|
||||
push!(lhs_cols, term.variable.value)
|
||||
push!(lhs_rows, constr_index)
|
||||
push!(lhs_values, term.coefficient)
|
||||
end
|
||||
@@ -631,7 +627,7 @@ function __init_JuMPSolver__()
|
||||
)
|
||||
|
||||
function get_constraint_attrs(self)
|
||||
attrs = [
|
||||
return [
|
||||
"categories",
|
||||
"dual_values",
|
||||
"lazy",
|
||||
@@ -641,18 +637,18 @@ function __init_JuMPSolver__()
|
||||
"senses",
|
||||
"user_features",
|
||||
"slacks",
|
||||
"basis_status",
|
||||
"sa_rhs_down",
|
||||
"sa_rhs_up",
|
||||
]
|
||||
if repr(self.data.optimizer_factory) in ["Gurobi.Optimizer"]
|
||||
append!(attrs, ["basis_status", "sa_rhs_down", "sa_rhs_up"])
|
||||
end
|
||||
return attrs
|
||||
end
|
||||
|
||||
get_variables(self; with_static = true, with_sa = true) =
|
||||
get_variables(self.data; with_static = with_static, with_sa = with_sa)
|
||||
|
||||
function get_variable_attrs(self)
|
||||
attrs = [
|
||||
return [
|
||||
"basis_status",
|
||||
"names",
|
||||
"categories",
|
||||
"lower_bounds",
|
||||
@@ -662,22 +658,13 @@ function __init_JuMPSolver__()
|
||||
"upper_bounds",
|
||||
"user_features",
|
||||
"values",
|
||||
"sa_obj_down",
|
||||
"sa_obj_up",
|
||||
"sa_lb_down",
|
||||
"sa_lb_up",
|
||||
"sa_ub_down",
|
||||
"sa_ub_up",
|
||||
]
|
||||
if repr(self.data.optimizer_factory) in ["Gurobi.Optimizer"]
|
||||
append!(
|
||||
attrs,
|
||||
[
|
||||
"basis_status",
|
||||
"sa_obj_down",
|
||||
"sa_obj_up",
|
||||
"sa_lb_down",
|
||||
"sa_lb_up",
|
||||
"sa_ub_down",
|
||||
"sa_ub_up",
|
||||
],
|
||||
)
|
||||
end
|
||||
return attrs
|
||||
end
|
||||
|
||||
is_infeasible(self) = is_infeasible(self.data)
|
||||
|
||||
Reference in New Issue
Block a user