Skip to content

Commit

Permalink
fix empty optimization result + test of infeasible ip restricted mast…
Browse files Browse the repository at this point in the history
…er (#173)

* fix empty optres get

* deactivate & activate art vars; GLPK exception.

* does not call solver if 0 vars

* add unsafe_getsolutions
  • Loading branch information
guimarqu authored Aug 28, 2019
1 parent 94db792 commit 54779ad
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/MOIinterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ function fill_primal_result!(optimizer::MoiOptimizer,
end
result.primal_bound = PrimalBound{S}()
if nbprimalsols(result) > 0
result.primal_bound = getbound(getbestprimalsol(result))
result.primal_bound = getbound(unsafe_getbestprimalsol(result))
end
@logmsg LogLevel(-2) string("Primal bound is ", getprimalbound(result))
return
Expand Down Expand Up @@ -240,7 +240,7 @@ function fill_dual_result!(optimizer::MoiOptimizer,
end
result.dual_bound = DualBound{S}()
if nbdualsols(result) > 0
result.dual_bound = getbound(getbestdualsol(result))
result.dual_bound = getbound(unsafe_getbestdualsol(result))
end
@logmsg LogLevel(-2) string("Dual bound is ", getdualbound(result))
return
Expand Down
4 changes: 2 additions & 2 deletions src/MOIwrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,13 @@ end
function MOI.get(optimizer::Optimizer, object::MOI.VariablePrimal,
ref::MOI.VariableIndex)
id = optimizer.varmap[ref] # This gets a coluna Id{Variable}
var_val_dict = getsol(getbestprimalsol(optimizer.result))
var_val_dict = getsol(unsafe_getbestprimalsol(optimizer.result))
return get(var_val_dict, id, 0.0)
end

function MOI.get(optimizer::Optimizer, object::MOI.VariablePrimal,
refs::Vector{MOI.VariableIndex})
var_val_dict = getsol(getbestprimalsol(optimizer.result))
var_val_dict = getsol(unsafe_getbestprimalsol(optimizer.result))
return [get(var_val_dict, optimizer.varmap[ref], 0.0) for ref in refs]
end

Expand Down
2 changes: 2 additions & 0 deletions src/algorithms/masteripheur.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ function run!(::Type{MasterIpHeuristic}, form, node, strategy_rec, params)
@logmsg LogLevel(1) "Applying Master IP heuristic"
master = getmaster(form)
algorithm_data = MasterIpHeuristicData(getobjsense(master))
deactivate!(master, MasterArtVar)
enforce_integrality!(master)
opt_result = optimize!(master)
relax_integrality!(master)
activate!(master, MasterArtVar)
set_ip_primal_sol!(algorithm_data.incumbents, getbestprimalsol(opt_result))
@logmsg LogLevel(1) string("Found primal solution of ", get_ip_primal_bound(algorithm_data.incumbents))
@logmsg LogLevel(-3) get_ip_primal_sol(algorithm_data.incumbents)
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/reformulationsolver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ end
function setup_node!(n::Node, treat_order::Int, res::OptimizationResult)
@logmsg LogLevel(0) string("Setting up node ", treat_order, " before apply")
set_treat_order!(n, treat_order)
nbprimalsols(res) >= 1 && set_ip_primal_sol!(getincumbents(n), getbestprimalsol(res))
nbprimalsols(res) >= 1 && set_ip_primal_sol!(getincumbents(n), unsafe_getbestprimalsol(res))
@logmsg LogLevel(-1) string("Node IP DB: ", get_ip_dual_bound(getincumbents(n)))
@logmsg LogLevel(-1) string("Tree IP PB: ", get_ip_primal_bound(getincumbents(n)))
if (ip_gap(getincumbents(n)) <= 0.0 + 0.00000001)
Expand Down
34 changes: 32 additions & 2 deletions src/formulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,43 @@ function deactivate!(f::Formulation, varconstr::AbstractVarConstr)
end
deactivate!(f::Formulation, id::Id) = deactivate!(f, getelem(f, id))

function deactivate!(f::Formulation, Duty::Type{<:AbstractVarDuty})
vars = filter(id_v -> get_cur_is_active(id_v[2]) && getduty(id_v[2]) <: Duty, getvars(f))
for (id, var) in vars
deactivate!(f, var)
end
return
end

function deactivate!(f::Formulation, Duty::Type{<:AbstractConstrDuty})
constrs = filter(id_c -> get_cur_is_active(id_c[2]) && getduty(id_c[2]) <: Duty, getconstrs(f))
for (id, constr) in constrs
deactivate!(f, constr)
end
return
end

"Activates a variable in the formulation"
function activate!(f::Formulation, id::Id)
varconstr = getelem(f, id)
function activate!(f::Formulation, varconstr::AbstractVarConstr)
add!(f.buffer, varconstr)
set_cur_is_active(varconstr, true)
return
end
activate!(f::Formulation, id::Id) = activate!(f, getelem(f, id))

function activate!(f::Formulation, Duty::Type{<:AbstractVarDuty})
vars = filter(id_v -> !get_cur_is_active(id_v[2]) && getduty(id_v[2]) <: Duty, getvars(f))
for (id, var) in vars
activate!(f, var)
end
end

function activate!(f::Formulation, Duty::Type{<:AbstractConstrDuty})
constrs = filter(id_c -> !get_cur_is_active(id_c[2]) && getduty(id_c[2]) <: Duty, getconstrs(f))
for (id, constr) in constrs
activate!(f, constr)
end
end

function addprimalspsol!(f::Formulation, var::Variable)
return addprimalspsol!(f.manager, var)
Expand Down
3 changes: 3 additions & 0 deletions src/incumbents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function set_ip_primal_sol!(inc::Incumbents{S},
end
return false
end
set_ip_primal_sol!(inc::Incumbents, ::Nothing) = false

"""
Updates the best primal solution to the linear program if the new one is better
Expand All @@ -88,6 +89,7 @@ function set_lp_primal_sol!(inc::Incumbents{S},
end
return false
end
set_lp_primal_sol!(inc::Incumbents, ::Nothing) = false

"""
Updates the dual bound of the mixed-integer program if the new one is better than
Expand Down Expand Up @@ -123,6 +125,7 @@ function set_lp_dual_sol!(inc::Incumbents{S},
end
return false
end
set_lp_dual_sol!(inc::Incumbents, ::Nothing) = false

"Updates the fields of `dest` that are worse than those of `src`."
function set!(dest::Incumbents{S}, src::Incumbents{S}) where {S}
Expand Down
10 changes: 8 additions & 2 deletions src/optimizationresults.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ getprimalsols(res::OptimizationResult) = res.primal_sols
getdualsols(res::OptimizationResult) = res.dual_sols
nbprimalsols(res::OptimizationResult) = length(res.primal_sols)
nbdualsols(res::OptimizationResult) = length(res.dual_sols)
getbestprimalsol(res::OptimizationResult) = res.primal_sols[1]
getbestdualsol(res::OptimizationResult) = res.dual_sols[1]

# For documentation : Only unsafe methods must be used to retrieve best
# solutions in the core of Coluna.
unsafe_getbestprimalsol(res::OptimizationResult) = res.primal_sols[1]
unsafe_getbestdualsol(res::OptimizationResult) = res.dual_sols[1]
getbestprimalsol(res::OptimizationResult) = get(res.primal_sols, 1, nothing)
getbestdualsol(res::OptimizationResult) = get(res.dual_sols, 1, nothing)

setprimalbound!(res::OptimizationResult, b::PrimalBound) = res.primal_bound = b
setdualbound!(res::OptimizationResult, b::DualBound) = res.dual_bound = b
setterminationstatus!(res::OptimizationResult, status::TerminationStatus) = res.termination_status = status
Expand Down
5 changes: 5 additions & 0 deletions src/optimizerwrappers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ function optimize!(form::Formulation, optimizer::MoiOptimizer)
sync_solver!(getoptimizer(form), form)
@logmsg LogLevel(-3) "MOI formulation after synch: "
@logmsg LogLevel(-3) getoptimizer(form)
nbvars = MOI.get(form.optimizer.inner, MOI.NumberOfVariables())
if nbvars <= 0
@warn "No variable in the formulation. Coluna does not call the solver."
return retrieve_result(form, optimizer)
end
call_moi_optimize_with_silence(form.optimizer)
status = MOI.get(form.optimizer.inner, MOI.TerminationStatus())
@logmsg LogLevel(-2) string("Optimization finished with status: ", status)
Expand Down
3 changes: 3 additions & 0 deletions test/unit/algorithms/algorithm.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
include("masteripheur.jl")

function algorithm_unit_tests()
algorithm_fallbacks_tests()
masteripheur_tests()
end

function algorithm_fallbacks_tests()
Expand Down
32 changes: 32 additions & 0 deletions test/unit/algorithms/masteripheur.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
function masteripheur_tests()
infeasible_master_ip_heur_tests()
end

CL.to_be_pruned(n::CL.Node) = true # issue 166

struct InfeasibleMasterIpHeur <: CL.AbstractConquerStrategy end

function CL.apply!(::Type{InfeasibleMasterIpHeur}, reform, node, strategy_rec::CL.StrategyRecord, params)
# Apply directly master ip heuristic => infeasible
mip_rec = CL.apply!(CL.MasterIpHeuristic, reform, node, strategy_rec, params)
return
end

function infeasible_master_ip_heur_tests()
@testset "play gap" begin
data = CLD.GeneralizedAssignment.data("play2.txt")

coluna = JuMP.with_optimizer(
Coluna.Optimizer,
params = CL.Params(
global_strategy = CL.GlobalStrategy(InfeasibleMasterIpHeur, CL.NoBranching, CL.DepthFirst)
),
default_optimizer = with_optimizer(GLPK.Optimizer)
)

problem, x, dec = CLD.GeneralizedAssignment.model(data, coluna)

JuMP.optimize!(problem)
@test JuMP.objective_value(problem) == Inf
end
end
11 changes: 11 additions & 0 deletions test/unit/optimizationresults.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function optimizationresults_unit_test()
emptyresults_tests()
end

function emptyresults_tests()
result = CL.OptimizationResult{CL.MinSense}()
@test CL.getprimalbound(result) == Inf
@test CL.getdualbound(result) == -Inf
@test CL.getbestprimalsol(result) == nothing
@test CL.getbestdualsol(result) == nothing
end
4 changes: 4 additions & 0 deletions test/unit/unit_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ include("variable.jl")
include("constraint.jl")
include("varconstr.jl")
# include("manager.jl")
include("optimizationresults.jl")
include("filters.jl")
include("solsandbounds.jl")
include("incumbents.jl")
Expand Down Expand Up @@ -65,6 +66,9 @@ function unit_tests()
@testset "solsandbounds.jl" begin
solsandbounds_unit_tests()
end
@testset "optimizationresults.jl" begin
optimizationresults_unit_test()
end
@testset "incumbents.jl" begin
incumbents_unit_tests()
end
Expand Down

0 comments on commit 54779ad

Please sign in to comment.