Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MasterIpHeur -> IpForm #289

Merged
merged 4 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Algorithm/Algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ include("record.jl")
# Here include slave algorithms used by conquer algorithms
include("colgen.jl")
include("benders.jl")
include("masteripheur.jl")
include("ipform.jl")
include("masterlp.jl")
include("preprocessing.jl")

Expand All @@ -57,7 +57,7 @@ include("treesearch.jl")

# Types
export AbstractOptimizationAlgorithm, TreeSearchAlgorithm, ColGenConquer, ColumnGeneration,
BendersConquer, BendersCutGeneration, MasterIpHeuristic, ExactBranchingPhase,
BendersConquer, BendersCutGeneration, IpForm, ExactBranchingPhase,
OnlyRestrictedMasterBranchingPhase

end
4 changes: 2 additions & 2 deletions src/Algorithm/benders.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ function run!(algo::BendersCutGeneration, reform::Reformulation, input::Optimiza

result = OptimizationResult(
getmaster(reform),
data.is_feasible ? FEASIBLE : INFEASIBLE,
data.has_converged ? OPTIMAL : OTHER_LIMIT,
feasibility_status = data.is_feasible ? FEASIBLE : INFEASIBLE,
termination_status = data.has_converged ? OPTIMAL : OTHER_LIMIT,
ip_dual_bound = get_ip_dual_bound(data.incumbents),
lp_dual_bound = get_lp_dual_bound(data.incumbents)
)
Expand Down
38 changes: 21 additions & 17 deletions src/Algorithm/colgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ function run!(algo::ColumnGeneration, reform::Reformulation, input::Optimization

result = OptimizationResult(
masterform,
data.is_feasible ? FEASIBLE : INFEASIBLE,
data.has_converged ? OPTIMAL : OTHER_LIMIT,
feasibility_status = data.is_feasible ? FEASIBLE : INFEASIBLE,
termination_status = data.has_converged ? OPTIMAL : OTHER_LIMIT,
ip_primal_bound = get_ip_primal_bound(data.incumbents),
ip_dual_bound = get_lp_dual_bound(data.incumbents), # TODO : check if objective function is integer
lp_dual_bound = get_lp_dual_bound(data.incumbents)
Expand Down Expand Up @@ -185,32 +185,36 @@ function solve_sp_to_gencol!(

# Solve sub-problem and insert generated columns in master
# @logmsg LogLevel(-3) "optimizing pricing prob"
ipform = IpForm(deactivate_artificial_vars = false, enforce_integrality = false, log_level = 2)
TO.@timeit Coluna._to "Pricing subproblem" begin
opt_result = optimize!(spform)
sp_output = run!(ipform, spform, IpFormInput(ObjValues(spform)))
end
sp_result = getresult(sp_output)

pricing_db_contrib = compute_pricing_db_contrib(
spform, getprimalbound(opt_result), sp_lb, sp_ub
spform, get_ip_primal_bound(sp_result), sp_lb, sp_ub
)

if !isfeasible(opt_result)
if !isfeasible(sp_result)
sp_is_feasible = false
# @logmsg LogLevel(-3) "pricing prob is infeasible"
return sp_is_feasible, recorded_solution_ids, PrimalBound(spform)
end

for sol in getprimalsols(opt_result)
if contrib_improves_mlp(getobjsense(spform), getvalue(sol)) # has negative reduced cost
insertion_status, col_id = setprimalsol!(spform, sol)
if insertion_status
push!(recorded_solution_ids, col_id)
elseif !insertion_status && !iscuractive(masterform, col_id)
push!(sp_solution_ids_to_activate, col_id)
else
msg = """
Column already exists as $(getname(masterform, col_id)) and is already active.
"""
@warn string(msg)
if nb_ip_primal_sols(sp_result) > 0
for sol in get_ip_primal_sols(sp_result)
if contrib_improves_mlp(getobjsense(spform), getvalue(sol)) # has negative reduced cost
insertion_status, col_id = setprimalsol!(spform, sol)
if insertion_status
push!(recorded_solution_ids, col_id)
elseif !insertion_status && !iscuractive(masterform, col_id)
push!(sp_solution_ids_to_activate, col_id)
else
msg = """
Column already exists as $(getname(masterform, col_id)) and is already active.
"""
@warn string(msg)
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/Algorithm/conquer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ end

Base.@kwdef struct ColGenConquer <: AbstractConquerAlgorithm
colgen::ColumnGeneration = ColumnGeneration()
mastipheur::MasterIpHeuristic = MasterIpHeuristic()
mastipheur::IpForm = IpForm()
preprocess::PreprocessAlgorithm = PreprocessAlgorithm()
run_mastipheur::Bool = true
run_preprocessing::Bool = false
Expand Down
2 changes: 1 addition & 1 deletion src/Algorithm/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ abstract type AbstractOptimizationAlgorithm <: AbstractAlgorithm end

function run!(
algo::AbstractOptimizationAlgorithm, form::AbstractFormulation, input::OptimizationInput
)::OldOutput
)::OptimizationOutput
algotype = typeof(algo)
error("Method run! which takes formulation and Incumbents as input returns OldOutput
is not implemented for algorithm $algotype.")
Expand Down
102 changes: 102 additions & 0 deletions src/Algorithm/ipform.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""
IpForm

todo
Solve ip formulation
"""
Base.@kwdef struct IpForm <: AbstractOptimizationAlgorithm
time_limit::Int = 600
deactivate_artificial_vars = true
enforce_integrality = true
log_level = 1
end

struct IpFormInput{S} <: AbstractInput
incumbents::ObjValues{S}
end


# TO DO : create an Algorithm Logger
# function Logging.shouldlog(logger::ConsoleLogger, level, _module, group, id)
# println("*******")
# @show level _module group id
# println("log = ", get(logger.message_limits, id, 1))
# println("******")
# return get(logger.message_limits, id, 1) > 0
# end

function run!(algo::IpForm, form::Formulation, input::IpFormInput)::OptimizationOutput
logger = ConsoleLogger(stderr, LogLevel(algo.log_level))
with_logger(logger) do
return run_ipform!(algo, form, input)
end
end

function run_ipform!(algo::IpForm, form::Formulation, input::IpFormInput)::OptimizationOutput
@logmsg LogLevel(1) "Algorithm IpForm"

algoresult = OptimizationResult(
form, ip_primal_bound = get_ip_primal_bound(input.incumbents)
)

ip_supported = check_if_optimizer_supports_ip(getoptimizer(form))
if !ip_supported
@warn "Optimizer of formulation with id =", getuid(form) ," does not support integer variables. Skip IpForm algorithm."
return OptimizationOutput(algoresult)
end

optimizer_result = optimize_ip_form!(algo, getoptimizer(form), form)

setfeasibilitystatus!(algoresult, getfeasibilitystatus(optimizer_result))
setterminationstatus!(algoresult, getterminationstatus(optimizer_result))

bestprimalsol = getbestprimalsol(optimizer_result)
if bestprimalsol !== nothing
add_ip_primal_sol!(algoresult, bestprimalsol)

@logmsg LogLevel(1) string(
"Found primal solution of ",
@sprintf "%.4f" getvalue(get_ip_primal_bound(algoresult))
)
@logmsg LogLevel(-3) get_best_ip_primal_sol(algoresult)
else
@logmsg LogLevel(1) string(
"No primal solution found. Termination status is ",
getterminationstatus(algoresult), ". Feasibility status is ",
getfeasibilitystatus(algoresult), "."
)
end
return OptimizationOutput(algoresult)
end

function check_if_optimizer_supports_ip(optimizer::MoiOptimizer)
return MOI.supports_constraint(optimizer.inner, MOI.SingleVariable, MOI.Integer)
end
check_if_optimizer_supports_ip(optimizer::UserOptimizer) = true

function optimize_ip_form!(algo::IpForm, optimizer::MoiOptimizer, form::Formulation)
MOI.set(optimizer.inner, MOI.TimeLimitSec(), algo.time_limit)
# No way to enforce upper bound through MOI.
# Add a constraint c'x <= UB in form ?

if algo.deactivate_artificial_vars
deactivate!(form, vcid -> isanArtificialDuty(getduty(vcid)))
end
if algo.enforce_integrality
enforce_integrality!(form)
end

optimizer_result = optimize!(form)

if algo.enforce_integrality
relax_integrality!(form)
end
if algo.deactivate_artificial_vars
activate!(form, vcid -> isanArtificialDuty(getduty(vcid)))
end
return optimizer_result
end

function optimize_ip_form!(algo::IpForm, optimizer::UserOptimizer, form::Formulation)
return optimize!(form)
end
39 changes: 0 additions & 39 deletions src/Algorithm/masteripheur.jl

This file was deleted.

6 changes: 5 additions & 1 deletion src/Containers/nestedenum.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
abstract type NestedEnum end

function Base.:(<=)(a::T, b::T) where {T <: NestedEnum}
function Base.:(<=)(a::T, b::T) where {T<:NestedEnum}
return a.value % b.value == 0
end

function Base.:(<=)(a::T, b::U) where {T<:NestedEnum,U<:NestedEnum}
return false
end

# Store the item defined in expr at position i
function _store!(expr::Symbol, i, names, parent_pos, depths)
names[i] = expr
Expand Down
2 changes: 1 addition & 1 deletion src/MathProg/MathProg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export getperenecost,
reset!

# methods related to solutions
export OptimizationResult
export OptimizationResult, ObjValues

export getterminationstatus,
getfeasibilitystatus,
Expand Down
23 changes: 8 additions & 15 deletions src/MathProg/new_varconstr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ function _setiscuractive!(form::Formulation, constrid::ConstrId, is_active::Bool
return
end

"Activates a variable in the formulation"
"Activate a variable in the formulation"
function activate!(form::Formulation, varconstrid::Id{VC}) where {VC<:AbstractVarConstr}
if iscurexplicit(form, varconstrid)
add!(form.buffer, varconstrid)
Expand All @@ -267,20 +267,18 @@ function activate!(form::Formulation, varconstrid::Id{VC}) where {VC<:AbstractVa
end
activate!(form::Formulation, varconstr::AbstractVarConstr) = activate!(form, getid(varconstr))

function activate!(form::Formulation, duty::Duty{Variable})
function activate!(form::Formulation, f::Function)
for (varid, _) in getvars(form)
if iscuractive(form, varid) && getduty(varid) <= duty
if iscuractive(form, varid) && f(varid)
activate!(form, varid)
end
end
end

function activate!(form::Formulation, duty::Duty{Constraint})
for (constrid, _) in getconstrs(form)
if iscuractive(form, constrid) && getduty(constrid) <= duty
if iscuractive(form, constrid) && f(constrid)
activate!(form, constrid)
end
end
return
end

"""
Expand All @@ -295,25 +293,20 @@ function deactivate!(form::Formulation, varconstrid::Id{VC}) where {VC<:Abstract
end
deactivate!(form::Formulation, varconstr::AbstractVarConstr) = deactivate!(form, getid(varconstr))

function deactivate!(form::Formulation, duty::Duty{Variable})
function deactivate!(form::Formulation, f::Function)
for (varid, _) in getvars(form)
if iscuractive(form, varid) && getduty(varid) <= duty
if iscuractive(form, varid) && f(varid)
deactivate!(form, varid)
end
end
return
end

function deactivate!(form::Formulation, duty::Duty{Constraint})
for (constrid, _) in getconstrs(form)
if iscuractive(form, constrid) && getduty(constrid) <= duty
if iscuractive(form, constrid) && f(constrid)
deactivate!(form, constrid)
end
end
return
end


## explicit
"""
todo
Expand Down
Loading