Use UpperBoundRef and LowerBoundRef; relax int vars

master
Alinson S. Xavier 4 years ago
parent be0cd98e9d
commit acaa8c3bee

@ -10,7 +10,7 @@ struct Variable
end
mutable struct MIP
constructor
constructor::Any
optimizers::Vector
binary_variables::Vector{Variable}
sense::Float64

@ -43,10 +43,7 @@ function find_branching_var(
else
if var in keys(pool.var_history)
varhist = pool.var_history[var]
hlength = min(
length(varhist.obj_ratio_up),
length(varhist.obj_ratio_down),
)
hlength = min(length(varhist.obj_ratio_up), length(varhist.obj_ratio_down))
if hlength >= rule.min_samples
use_strong_branch = false
end

@ -16,6 +16,7 @@ Base.@kwdef mutable struct JuMPSolverData
optimizer_factory::Any
basis_status::Dict{ConstraintRef,MOI.BasisStatusCode} = Dict()
bin_vars::Vector{JuMP.VariableRef} = []
int_vars::Vector{JuMP.VariableRef} = []
cb_data::Any = nothing
cname_to_constr::Dict{String,JuMP.ConstraintRef} = Dict()
dual_values::Dict{JuMP.ConstraintRef,Float64} = Dict()
@ -24,8 +25,6 @@ Base.@kwdef mutable struct JuMPSolverData
reduced_costs::Vector{Float64} = []
sensitivity_report::Any = nothing
solution::Dict{JuMP.VariableRef,Float64} = Dict()
var_lb_constr::Dict{MOI.VariableIndex,ConstraintRef} = Dict()
var_ub_constr::Dict{MOI.VariableIndex,ConstraintRef} = Dict()
varname_to_var::Dict{String,VariableRef} = Dict()
x::Vector{Float64} = Float64[]
end
@ -104,18 +103,6 @@ function _update_solution!(data::JuMPSolverData)
data.basis_status = Dict()
end
end
# Build map between variables and bound constraints
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
@ -124,8 +111,6 @@ function _update_solution!(data::JuMPSolverData)
data.dual_values = Dict()
data.sensitivity_report = nothing
data.basis_status = Dict()
data.var_lb_constr = Dict()
data.var_ub_constr = Dict()
end
end
@ -282,37 +267,44 @@ end
function solve_lp(data::JuMPSolverData; tee::Bool = false)
model, bin_vars = data.model, data.bin_vars
for var in bin_vars
for var in data.bin_vars
~is_fixed(var) || continue
unset_binary(var)
set_upper_bound(var, 1.0)
set_lower_bound(var, 0.0)
end
for var in data.int_vars
~is_fixed(var) || continue
unset_integer(var)
end
# If the optimizer is Cbc, we need to replace it by Clp,
# otherwise dual values are not available.
# https://github.com/jump-dev/Cbc.jl/issues/50
is_cbc = (data.optimizer_factory == Cbc.Optimizer)
if is_cbc
set_optimizer(model, Clp.Optimizer)
set_optimizer(data.model, Clp.Optimizer)
end
wallclock_time = @elapsed begin
log = _optimize_and_capture_output!(model, tee = tee)
log = _optimize_and_capture_output!(data.model, tee = tee)
end
if is_infeasible(data)
data.solution = Dict()
obj_value = nothing
else
_update_solution!(data)
obj_value = objective_value(model)
obj_value = objective_value(data.model)
end
if is_cbc
set_optimizer(model, data.optimizer_factory)
set_optimizer(data.model, data.optimizer_factory)
end
for var in bin_vars
for var in data.bin_vars
~is_fixed(var) || continue
set_binary(var)
end
for var in data.int_vars
~is_fixed(var) || continue
set_integer(var)
end
return miplearn.solvers.internal.LPSolveStats(
lp_value = obj_value,
lp_log = log,
@ -332,6 +324,7 @@ function set_instance!(
end
data.model = model
data.bin_vars = [var for var in JuMP.all_variables(model) if JuMP.is_binary(var)]
data.int_vars = [var for var in JuMP.all_variables(model) if JuMP.is_integer(var)]
data.varname_to_var = Dict(JuMP.name(var) => var for var in JuMP.all_variables(model))
JuMP.set_optimizer(model, data.optimizer_factory)
data.cname_to_constr = Dict()
@ -419,8 +412,8 @@ function get_variables(data::JuMPSolverData; with_static::Bool, with_sa::Bool)
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]
if has_lower_bound(v)
constr = LowerBoundRef(v)
(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)
@ -430,8 +423,8 @@ function get_variables(data::JuMPSolverData; with_static::Bool, with_sa::Bool)
end
# Upper bound
if v.index in keys(data.var_ub_constr)
constr = data.var_ub_constr[v.index]
if has_upper_bound(v)
constr = JuMP.UpperBoundRef(v)
(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)
@ -447,14 +440,14 @@ function get_variables(data::JuMPSolverData; with_static::Bool, with_sa::Bool)
basis_status = []
for v in vars
basis_status_v = "B"
if v.index in keys(data.var_lb_constr)
constr = data.var_lb_constr[v.index]
if has_lower_bound(v)
constr = LowerBoundRef(v)
if data.basis_status[constr] == MOI.NONBASIC
basis_status_v = "L"
end
end
if v.index in keys(data.var_ub_constr)
constr = data.var_ub_constr[v.index]
if has_upper_bound(v)
constr = UpperBoundRef(v)
if data.basis_status[constr] == MOI.NONBASIC
basis_status_v = "U"
end

@ -51,12 +51,7 @@ function runtests(optimizer_name, optimizer; large = true)
@test round(obj, digits = 6) == 62.714777
# Probe (up is infeasible, down is feasible)
BB.set_bounds!(
mip,
mip.binary_variables[1:3],
[1.0, 1.0, 0.0],
[1.0, 1.0, 1.0],
)
BB.set_bounds!(mip, mip.binary_variables[1:3], [1.0, 1.0, 0.0], [1.0, 1.0, 1.0])
status, obj = BB.solve_relaxation!(mip)
@test status == :Optimal
probe_up, probe_down = BB.probe(mip, mip.binary_variables[3])

@ -7,14 +7,25 @@ using MIPLearn
using Cbc
@testset "FileInstance" begin
@testset "Solve" begin
@testset "Solve (knapsack)" begin
data = KnapsackData()
filename = tempname()
MIPLearn.save_data(filename, data)
instance = FileInstance(filename, build_knapsack_model)
solver = LearningSolver(Cbc.Optimizer)
solve!(solver, instance)
h5 = Hdf5Sample("$filename.h5")
@test h5.get_scalar("mip_wallclock_time") > 0
end
@testset "Solve (vpm2)" begin
data = Dict("filename" => joinpath(@__DIR__, "../fixtures/danoint.mps.gz"))
build_model(data) = read_from_file(data["filename"])
filename = tempname()
MIPLearn.save_data(filename, data)
instance = FileInstance(filename, build_model)
solver = LearningSolver(optimizer_with_attributes(Cbc.Optimizer, "seconds" => 1.0))
solve!(solver, instance)
h5 = Hdf5Sample("$filename.h5")
@test h5.get_scalar("mip_wallclock_time") > 0
end

Loading…
Cancel
Save