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

Follow up of "custom data" #538

Merged
merged 5 commits into from
Jun 10, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 3 additions & 3 deletions src/Algorithm/colgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,12 @@ function solve_sps_to_gencols!(
updatereducedcosts!(reform, redcostshelper, smooth_dual_sol)
end

# udate the incumbent values of constraints
# update the incumbent values of constraints
for (_, constr) in getconstrs(masterform)
constr.curdata.inc_val = 0.0
MathProg.setcurincval!(masterform, constr, 0.0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can export this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I got the right meaning of this, but I've seen now that I duplicated these functions. They already existed and they are already exported.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok perfect then. If it's exported you can remove the MathProg prefix. If tests pass on your computer, we can merge then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many things were wrong and I didn't notice because there was an unrelated test failing before custom_var_cuts_test, which therefore never ran. Now I fixed some of the bugs but can't get the right result yet, I'll keep trying. Also I had to move addcustomvars! and addcustomconstrs! to a function where custom_data is reachable so it could give the right key to the dictionary, is that ok? I think it's possible to search for the key AbstractCustomData instead, if that's better.

end
for (constrid, val) in smooth_dual_sol
getconstr(masterform, constrid).curdata.inc_val = val
MathProg.setcurincval!(masterform, constrid, val)
end

### BEGIN LOOP TO BE PARALLELIZED
Expand Down
2 changes: 1 addition & 1 deletion src/ColunaBase/ColunaBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Printf

# interface.jl
export AbstractModel, AbstractProblem, AbstractSense, AbstractMinSense, AbstractMaxSense,
AbstractSpace, AbstractPrimalSpace, AbstractDualSpace, getstorage
AbstractSpace, AbstractPrimalSpace, AbstractDualSpace, AbstractCustomData, getstorage

# nestedenum.jl
export NestedEnum, @nestedenum, @exported_nestedenum
Expand Down
8 changes: 5 additions & 3 deletions src/ColunaBase/solsandbounds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,15 @@ function convert_status(coluna_status::SolutionStatus)
return MOI.OTHER_RESULT_STATUS
end

abstract type AbstractCustomData end

# Solution
struct Solution{Model<:AbstractModel,Decision,Value} <: AbstractDict{Decision,Value}
model::Model
bound::Float64
status::SolutionStatus
sol::DynamicSparseArrays.PackedMemoryArray{Decision,Value}
custom_data
custom_data::Union{Nothing, AbstractCustomData}
end

"""
Expand All @@ -226,7 +228,7 @@ end
values::Vector,
solution_values::Float64,
status::SolutionStatus,
[custom_data]
[custom_data]::Union{Nothing, AbstractCustomData}
)

Create a solution to the `model`. Other arguments are:
Expand All @@ -237,7 +239,7 @@ Create a solution to the `model`. Other arguments are:
"""
function Solution{Mo,De,Va}(
model::Mo, decisions::Vector{De}, values::Vector{Va}, solution_value::Float64,
status::SolutionStatus, custom_data = nothing
status::SolutionStatus, custom_data::Union{Nothing, AbstractCustomData} = nothing
) where {Mo<:AbstractModel,De,Va}
sol = DynamicSparseArrays.dynamicsparsevec(decisions, values)
return Solution(model, solution_value, status, sol, custom_data)
Expand Down
4 changes: 2 additions & 2 deletions src/MOIcallbacks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function MOI.submit(
cost::Float64,
variables::Vector{MOI.VariableIndex},
values::Vector{Float64},
custom_data = nothing
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
)
form = cb.callback_data.form
S = getobjsense(form)
Expand Down Expand Up @@ -100,7 +100,7 @@ function MOI.submit(
cb::Union{MOI.UserCut{Algorithm.RobustCutCallbackContext}, MOI.LazyConstraint{Algorithm.RobustCutCallbackContext}},
func::MOI.ScalarAffineFunction{Float64},
set::Union{MOI.LessThan{Float64}, MOI.GreaterThan{Float64}, MOI.EqualTo{Float64}},
custom_data = nothing
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
)
form = cb.callback_data.form
rhs = MathProg.convert_moi_rhs_to_coluna(set)
Expand Down
4 changes: 2 additions & 2 deletions src/MathProg/constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ mutable struct Constraint <: AbstractVarConstr
curdata::ConstrData
moirecord::MoiConstrRecord
art_var_ids::Vector{VarId}
custom_data::Any
custom_data::Union{Nothing, ColunaBase.AbstractCustomData}
end

const ConstrId = Id{Constraint}

function Constraint(
id::ConstrId, name::String;
constr_data = ConstrData(), moi_index::MoiConstrIndex = MoiConstrIndex(),
custom_data = nothing
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
)
return Constraint(
id, name, constr_data, ConstrData(constr_data), MoiConstrRecord(index = moi_index),
Expand Down
6 changes: 3 additions & 3 deletions src/MathProg/formulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function setvar!(
is_explicit::Bool = true,
moi_index::MoiVarIndex = MoiVarIndex(),
members::Union{ConstrMembership,Nothing} = nothing,
custom_data = nothing,
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing,
id = generatevarid(duty, form),
branching_priority::Float64 = 1.0
)
Expand Down Expand Up @@ -300,7 +300,7 @@ function setcol_from_sp_primalsol!(
masterform::Formulation, spform::Formulation, sol_id::VarId, name::String,
duty::Duty{Variable}; lb::Float64 = 0.0, ub::Float64 = Inf, kind::VarKind = Continuous,
inc_val::Float64 = 0.0, is_active::Bool = true, is_explicit::Bool = true,
moi_index::MoiVarIndex = MoiVarIndex(), custom_data = nothing
moi_index::MoiVarIndex = MoiVarIndex(), custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
)
cost = getprimalsolcosts(spform)[sol_id]
master_coef_matrix = getcoefmatrix(masterform)
Expand Down Expand Up @@ -411,7 +411,7 @@ function setconstr!(
moi_index::MoiConstrIndex = MoiConstrIndex(),
members = nothing, # todo Union{AbstractDict{VarId,Float64},Nothing}
loc_art_var_abs_cost::Float64 = 0.0,
custom_data = nothing,
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing,
id = generateconstrid(duty, form)
)
if getduty(id) != duty
Expand Down
2 changes: 1 addition & 1 deletion src/MathProg/manager.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct FormulationManager
coefficients::ConstrVarMatrix # rows = constraints, cols = variables
expressions::VarVarMatrix # cols = variables, rows = expressions
primal_sols::VarVarMatrix # cols = primal solutions with varid, rows = variables
primal_sols_custom_data::Dict{VarId,Any}
primal_sols_custom_data::Dict{VarId, ColunaBase.AbstractCustomData}
primal_sol_costs::DynSparseVector{VarId} # primal solutions with varid map to their cost
dual_sols::ConstrConstrMatrix # cols = dual solutions with constrid, rows = constrs
dual_sol_rhss::DynSparseVector{ConstrId} # dual solutions with constrid map to their rhs
Expand Down
4 changes: 2 additions & 2 deletions src/MathProg/solutions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ const DualSolution{M} = Solution{M, ConstrId, Float64}

function PrimalSolution(
form::M, decisions::Vector{De}, vals::Vector{Va}, val::Float64, status::SolutionStatus,
custom_data = nothing
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
) where {M<:AbstractFormulation,De,Va}
return Solution{M,De,Va}(form, decisions, vals, val, status, custom_data)
end

function DualSolution(
form::M, decisions::Vector{De}, vals::Vector{Va}, val::Float64, status::SolutionStatus,
custom_data = nothing
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing
) where {M<:AbstractFormulation,De,Va}
return Solution{M,De,Va}(form, decisions, vals, val, status, custom_data)
end
Expand Down
27 changes: 27 additions & 0 deletions src/MathProg/varconstr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,33 @@ function setcurrhs!(form::Formulation, constr::Constraint, rhs::Float64)
end
setcurrhs!(form::Formulation, constrid::ConstrId, rhs::Float64) = setcurrhs!(form, getconstr(form, constrid), rhs)

## inc_val
"""
getperenincval(formulation, constraint)
getperenincval(formulation, constrid)

Return the incumbent value as defined by the user of a constraint in a formulation.
"""
getperenincval(::Formulation, constr::Constraint) = constr.perendata.inc_val
getperenincval(form::Formulation, constrid::ConstrId) = getperenincval(form, getconstr(form, constrid))

"""
setcurincval!(formulation, constraint, inc_val::Float64)
setcurincval!(formulation, constrid, inc_val::Float64)

Set the current incumbent value of a constraint in a formulation.
"""
setcurincval!(::Formulation, constr::Constraint, inc_val::Float64) = constr.curdata.inc_val = inc_val
setcurincval!(form::Formulation, constrid::ConstrId, inc_val::Float64) = setcurincval!(form, getconstr(form, constrid), inc_val)

"""
getcurincval(formulation, constraint)
getcurincval(formulation, constrid)

Return the current incumbent value of a constraint in a formulation.
"""
getcurincval(::Formulation, constr::Constraint) = constr.curdata.inc_val
getcurincval(form::Formulation, constrid::ConstrId) = getcurincval(form, getconstr(form, constrid))

# Variable & Constraints
## kind
Expand Down
4 changes: 2 additions & 2 deletions src/MathProg/variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ mutable struct Variable <: AbstractVarConstr
curdata::VarData
branching_priority::Float64
moirecord::MoiVarRecord
custom_data::Any
custom_data::Union{Nothing, ColunaBase.AbstractCustomData}
end

const VarId = Id{Variable}
Expand All @@ -87,7 +87,7 @@ getid(var::Variable) = var.id

function Variable(
id::VarId, name::String; var_data = VarData(), moi_index::MoiVarIndex = MoiVarIndex(),
custom_data = nothing, branching_priority = 1.0
custom_data::Union{Nothing, ColunaBase.AbstractCustomData} = nothing, branching_priority = 1.0
)
return Variable(
id, name, var_data, VarData(var_data), branching_priority,
Expand Down
4 changes: 4 additions & 0 deletions src/decomposition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ function instantiatemaster!(
)
setobjconst!(form, getobjconst(get_original_formulation(prob)))
setmaster!(reform, form)
Coluna.MathProg.addcustomvars!(reform.master, ColunaBase.AbstractCustomData)
Coluna.MathProg.addcustomconstrs!(reform.master, ColunaBase.AbstractCustomData)
return form
end

Expand All @@ -51,6 +53,8 @@ function instantiatemaster!(
obj_sense = getobjsense(get_original_formulation(prob))
)
setmaster!(reform, masterform)
Coluna.MathProg.addcustomvars!(reform.master, ColunaBase.AbstractCustomData)
Coluna.MathProg.addcustomconstrs!(reform.master, ColunaBase.AbstractCustomData)
laradicp marked this conversation as resolved.
Show resolved Hide resolved
return masterform
end

Expand Down
21 changes: 4 additions & 17 deletions test/custom_var_cuts_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ given by length(s). The custom cut used to cut the fractional solution is
sum(λ_s for s in sols if length(s) >= 2) <= 1.0
where sols is the set of possible combinations of items in a bin.
=#
struct MyCustomVarData
struct MyCustomVarData <: ColunaBase.AbstractCustomData
nb_items::Int
end

struct MyCustomCutData
struct MyCustomCutData <: ColunaBase.AbstractCustomData
min_items::Int
end

Expand Down Expand Up @@ -72,15 +72,7 @@ function custom_var_cuts_test()

model, x, y, dec = build_toy_model(coluna)

custom_var_is_added = false
custom_cut_is_added = false

function my_pricing_callback(cbdata)
if !custom_var_is_added
Coluna.MathProg.addcustomvars!(cbdata.form.parent_formulation, MyCustomVarData)
custom_var_is_added = true
end

# Get the reduced costs of the original variables
I = [1, 2, 3]
b = BD.callback_spid(cbdata, model)
Expand All @@ -89,9 +81,9 @@ function custom_var_cuts_test()

# Get the dual values of the custom cuts
custduals = Tuple{Int, Float64}[]
for (_, constr) in getconstrs(cbdata.form.parent_formulation)
for (form, constr) in getconstrs(cbdata.form.parent_formulation)
if typeof(constr.custom_data) == MyCustomCutData
push!(custduals, (constr.custom_data.min_items, constr.curdata.inc_val))
push!(custduals, (constr.custom_data.min_items, MathProg.getcurincval(form, constr)))
end
end

Expand Down Expand Up @@ -135,11 +127,6 @@ function custom_var_cuts_test()
)

function custom_cut_sep(cbdata)
if !custom_cut_is_added
Coluna.MathProg.addcustomconstrs!(cbdata.form, MyCustomCutData)
custom_cut_is_added = true
end

# compute the constraint violation
viol = -1.0
for (varid, varval) in cbdata.orig_sol
Expand Down