mirror of
https://github.com/ANL-CEEESA/MIPLearn.jl.git
synced 2025-12-06 08:28:52 -06:00
JuMPSolver: Collect sa_obj, sa_lb, sa_ub
This commit is contained in:
@@ -12,10 +12,7 @@ mutable struct FileInstance <: Instance
|
|||||||
h5::PyCall.PyObject
|
h5::PyCall.PyObject
|
||||||
build_model::Function
|
build_model::Function
|
||||||
|
|
||||||
function FileInstance(
|
function FileInstance(filename::AbstractString, build_model::Function)::FileInstance
|
||||||
filename::AbstractString,
|
|
||||||
build_model::Function,
|
|
||||||
)::FileInstance
|
|
||||||
instance = new(nothing, nothing, filename, nothing, build_model)
|
instance = new(nothing, nothing, filename, nothing, build_model)
|
||||||
instance.py = PyFileInstance(instance)
|
instance.py = PyFileInstance(instance)
|
||||||
instance.h5 = Hdf5Sample(filename)
|
instance.h5 = Hdf5Sample(filename)
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ mutable struct JuMPSolverData
|
|||||||
solution::Dict{JuMP.VariableRef,Float64}
|
solution::Dict{JuMP.VariableRef,Float64}
|
||||||
reduced_costs::Vector{Float64}
|
reduced_costs::Vector{Float64}
|
||||||
dual_values::Dict{JuMP.ConstraintRef,Float64}
|
dual_values::Dict{JuMP.ConstraintRef,Float64}
|
||||||
|
sensitivity_report::Any
|
||||||
cb_data::Any
|
cb_data::Any
|
||||||
|
var_lb_constr::Dict{MOI.VariableIndex,ConstraintRef}
|
||||||
|
var_ub_constr::Dict{MOI.VariableIndex,ConstraintRef}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -54,7 +57,6 @@ function _update_solution!(data::JuMPSolverData)
|
|||||||
vars = JuMP.all_variables(data.model)
|
vars = JuMP.all_variables(data.model)
|
||||||
data.solution = Dict(var => JuMP.value(var) for var in vars)
|
data.solution = Dict(var => JuMP.value(var) for var in vars)
|
||||||
|
|
||||||
# Reduced costs
|
|
||||||
if has_duals(data.model)
|
if has_duals(data.model)
|
||||||
data.reduced_costs = []
|
data.reduced_costs = []
|
||||||
for var in vars
|
for var in vars
|
||||||
@@ -77,11 +79,31 @@ function _update_solution!(data::JuMPSolverData)
|
|||||||
for constr in JuMP.all_constraints(data.model, ftype, stype)
|
for constr in JuMP.all_constraints(data.model, ftype, stype)
|
||||||
# FIXME: Remove negative sign
|
# FIXME: Remove negative sign
|
||||||
data.dual_values[constr] = -JuMP.dual(constr)
|
data.dual_values[constr] = -JuMP.dual(constr)
|
||||||
|
|
||||||
|
if ftype == VariableRef
|
||||||
|
var = MOI.get(data.model, MOI.ConstraintFunction(), constr).variable
|
||||||
|
if stype == MOI.GreaterThan{Float64}
|
||||||
|
data.var_lb_constr[var] = constr
|
||||||
|
elseif stype == MOI.LessThan{Float64}
|
||||||
|
data.var_ub_constr[var] = constr
|
||||||
|
else
|
||||||
|
error("Unsupported constraint: $(ftype)-in-$(stype)")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
data.sensitivity_report = lp_sensitivity_report(data.model)
|
||||||
|
catch
|
||||||
|
# solver does not support sensitivity analysis; ignore
|
||||||
|
end
|
||||||
else
|
else
|
||||||
data.reduced_costs = []
|
data.reduced_costs = []
|
||||||
data.dual_values = Dict()
|
data.dual_values = Dict()
|
||||||
|
data.sensitivity_report = nothing
|
||||||
|
data.var_lb_constr = Dict()
|
||||||
|
data.var_ub_constr = Dict()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -329,7 +351,10 @@ end
|
|||||||
|
|
||||||
function get_variables(data::JuMPSolverData; with_static::Bool)
|
function get_variables(data::JuMPSolverData; with_static::Bool)
|
||||||
vars = JuMP.all_variables(data.model)
|
vars = JuMP.all_variables(data.model)
|
||||||
lb, ub, types, obj_coeffs = nothing, nothing, nothing, nothing
|
lb, ub, types = nothing, nothing, nothing
|
||||||
|
sa_obj_down, sa_obj_up = nothing, nothing
|
||||||
|
sa_lb_down, sa_lb_up = nothing, nothing
|
||||||
|
sa_ub_down, sa_ub_up = nothing, nothing
|
||||||
values, rc = nothing, nothing
|
values, rc = nothing, nothing
|
||||||
|
|
||||||
# Variable names
|
# Variable names
|
||||||
@@ -340,6 +365,10 @@ function get_variables(data::JuMPSolverData; with_static::Bool)
|
|||||||
values = [data.solution[v] for v in vars]
|
values = [data.solution[v] for v in vars]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Objective function coefficients
|
||||||
|
obj = objective_function(data.model)
|
||||||
|
obj_coeffs = [v ∈ keys(obj.terms) ? obj.terms[v] : 0.0 for v in vars]
|
||||||
|
|
||||||
if with_static
|
if with_static
|
||||||
# Lower bounds
|
# Lower bounds
|
||||||
lb = [
|
lb = [
|
||||||
@@ -353,10 +382,42 @@ function get_variables(data::JuMPSolverData; with_static::Bool)
|
|||||||
|
|
||||||
# Variable types
|
# Variable types
|
||||||
types = [JuMP.is_binary(v) ? "B" : JuMP.is_integer(v) ? "I" : "C" for v in vars]
|
types = [JuMP.is_binary(v) ? "B" : JuMP.is_integer(v) ? "I" : "C" for v in vars]
|
||||||
|
end
|
||||||
|
|
||||||
# Objective function coefficients
|
# Sensitivity analysis
|
||||||
obj = objective_function(data.model)
|
if data.sensitivity_report !== nothing
|
||||||
obj_coeffs = [v ∈ keys(obj.terms) ? obj.terms[v] : 0.0 for v in vars]
|
sa_obj_down, sa_obj_up = Float64[], Float64[]
|
||||||
|
sa_lb_down, sa_lb_up = Float64[], Float64[]
|
||||||
|
sa_ub_down, sa_ub_up = Float64[], Float64[]
|
||||||
|
|
||||||
|
for (i, v) in enumerate(vars)
|
||||||
|
# Objective function
|
||||||
|
(delta_down, delta_up) = data.sensitivity_report[v]
|
||||||
|
push!(sa_obj_down, delta_down + obj_coeffs[i])
|
||||||
|
push!(sa_obj_up, delta_up + obj_coeffs[i])
|
||||||
|
|
||||||
|
# Lower bound
|
||||||
|
if v.index in keys(data.var_lb_constr)
|
||||||
|
constr = data.var_lb_constr[v.index]
|
||||||
|
(delta_down, delta_up) = data.sensitivity_report[constr]
|
||||||
|
push!(sa_lb_down, lower_bound(v) + delta_down)
|
||||||
|
push!(sa_lb_up, lower_bound(v) + delta_up)
|
||||||
|
else
|
||||||
|
push!(sa_lb_down, -Inf)
|
||||||
|
push!(sa_lb_up, -Inf)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Upper bound
|
||||||
|
if v.index in keys(data.var_ub_constr)
|
||||||
|
constr = data.var_ub_constr[v.index]
|
||||||
|
(delta_down, delta_up) = data.sensitivity_report[constr]
|
||||||
|
push!(sa_ub_down, upper_bound(v) + delta_down)
|
||||||
|
push!(sa_ub_up, upper_bound(v) + delta_up)
|
||||||
|
else
|
||||||
|
push!(sa_ub_down, Inf)
|
||||||
|
push!(sa_ub_up, Inf)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
rc = isempty(data.reduced_costs) ? nothing : data.reduced_costs
|
rc = isempty(data.reduced_costs) ? nothing : data.reduced_costs
|
||||||
@@ -366,9 +427,15 @@ function get_variables(data::JuMPSolverData; with_static::Bool)
|
|||||||
lower_bounds = lb,
|
lower_bounds = lb,
|
||||||
upper_bounds = ub,
|
upper_bounds = ub,
|
||||||
types = to_str_array(types),
|
types = to_str_array(types),
|
||||||
obj_coeffs = obj_coeffs,
|
obj_coeffs = with_static ? obj_coeffs : nothing,
|
||||||
reduced_costs = rc,
|
reduced_costs = rc,
|
||||||
values = values,
|
values = values,
|
||||||
|
sa_obj_down = sa_obj_down,
|
||||||
|
sa_obj_up = sa_obj_up,
|
||||||
|
sa_lb_down = sa_lb_down,
|
||||||
|
sa_lb_up = sa_lb_up,
|
||||||
|
sa_ub_down = sa_ub_down,
|
||||||
|
sa_ub_up = sa_ub_up,
|
||||||
)
|
)
|
||||||
return vf
|
return vf
|
||||||
end
|
end
|
||||||
@@ -471,7 +538,10 @@ function __init_JuMPSolver__()
|
|||||||
Dict(), # solution
|
Dict(), # solution
|
||||||
[], # reduced_costs
|
[], # reduced_costs
|
||||||
Dict(), # dual_values
|
Dict(), # dual_values
|
||||||
|
nothing, # sensitivity_report
|
||||||
nothing, # cb_data
|
nothing, # cb_data
|
||||||
|
Dict(), # var_lb_constr
|
||||||
|
Dict(), # var_ub_constr
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -541,24 +611,34 @@ function __init_JuMPSolver__()
|
|||||||
get_variables(self; with_static = true, with_sa = true) =
|
get_variables(self; with_static = true, with_sa = true) =
|
||||||
get_variables(self.data; with_static = with_static)
|
get_variables(self.data; with_static = with_static)
|
||||||
|
|
||||||
get_variable_attrs(self) = [
|
function get_variable_attrs(self)
|
||||||
"names",
|
attrs = [
|
||||||
# "basis_status",
|
"names",
|
||||||
"categories",
|
# "basis_status",
|
||||||
"lower_bounds",
|
"categories",
|
||||||
"obj_coeffs",
|
"lower_bounds",
|
||||||
"reduced_costs",
|
"obj_coeffs",
|
||||||
# "sa_lb_down",
|
"reduced_costs",
|
||||||
# "sa_lb_up",
|
"types",
|
||||||
# "sa_obj_down",
|
"upper_bounds",
|
||||||
# "sa_obj_up",
|
"user_features",
|
||||||
# "sa_ub_down",
|
"values",
|
||||||
# "sa_ub_up",
|
]
|
||||||
"types",
|
if repr(self.data.optimizer_factory) in ["Gurobi.Optimizer"]
|
||||||
"upper_bounds",
|
append!(
|
||||||
"user_features",
|
attrs,
|
||||||
"values",
|
[
|
||||||
]
|
"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)
|
is_infeasible(self) = is_infeasible(self.data)
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ MIPLearn.setup_logger()
|
|||||||
include("solvers/jump_solver_test.jl")
|
include("solvers/jump_solver_test.jl")
|
||||||
include("solvers/learning_solver_test.jl")
|
include("solvers/learning_solver_test.jl")
|
||||||
# include("utils/benchmark_test.jl")
|
# include("utils/benchmark_test.jl")
|
||||||
|
include("utils/parse_test.jl")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user