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

Update Formulation docstring #484

Merged
merged 6 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions docs/src/dev/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Coluna.MathProg.get_ip_dual_bound
Coluna.Algorithm.ReformData
Coluna.Algorithm.ModelData
Coluna.MathProg.get_optimization_target
Coluna.MathProg.create_formulation!
```

```@meta
Expand Down
9 changes: 5 additions & 4 deletions src/Coluna.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,21 @@ include("parameters.jl")
include("ColunaBase/ColunaBase.jl")
using .ColunaBase

include("MathProg/MathProg.jl")
using .MathProg

mutable struct Env
env_starting_time::DateTime
optim_starting_time::Union{Nothing, DateTime}
params::Params
kpis::Kpis
form_counter::Int # 0 is for original form
end
Env(params::Params) = Env(now(), nothing, params, Kpis(nothing, nothing))
Env(params::Params) = Env(now(), nothing, params, Kpis(nothing, nothing), 0)
set_optim_start_time!(env::Env) = env.optim_starting_time = now()
elapsed_optim_time(env::Env) = Dates.toms(now() - env.optim_starting_time) / Dates.toms(Second(1))
Base.isinteger(x::Float64, tol::Float64) = abs(round(x) - x) < tol

include("MathProg/MathProg.jl")
using .MathProg

include("Algorithm/Algorithm.jl")
using .Algorithm

Expand Down
18 changes: 8 additions & 10 deletions src/MOIwrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const SupportedConstrSets = Union{
mutable struct Optimizer <: MOI.AbstractOptimizer
inner::Problem
objective_type::ObjectiveType
params::Params
annotations::Annotations
#varmap::Dict{MOI.VariableIndex,VarId} # For the user to get VariablePrimal
vars::CleverDicts.CleverDict{MOI.VariableIndex, Variable}
Expand All @@ -32,14 +31,13 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
default_optimizer_builder::Union{Nothing, Function}

feasibility_sense::Bool # Coluna supports only Max or Min.

kpis::Union{Nothing, Kpis}
guimarqu marked this conversation as resolved.
Show resolved Hide resolved
env::Env


function Optimizer()
model = new()
model.inner = Problem()
model.params = Params()
model.annotations = Annotations()
model.vars = CleverDicts.CleverDict{MOI.VariableIndex, Variable}()
model.varids = CleverDicts.CleverDict{MOI.VariableIndex, VarId}() # TODO : check if necessary to have two dicts for variables
Expand All @@ -51,7 +49,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
model.names_to_constrs = Dict{String, MOI.ConstraintIndex}()
model.default_optimizer_builder = nothing
model.feasibility_sense = false
model.kpis = nothing
model.env = Env(Params())
return model
end
end
Expand All @@ -69,7 +67,7 @@ MOI.supports(::Optimizer, ::MOI.ConstraintDualStart) = false
# Parameters
function MOI.set(model::Optimizer, param::MOI.RawParameter, val)
if param.name == "params"
model.params = val
model.env.params = val
elseif param.name == "default_optimizer"
optimizer_builder = () -> MoiOptimizer(MOI._instantiate_and_check(val))
model.default_optimizer_builder = optimizer_builder
Expand Down Expand Up @@ -98,8 +96,8 @@ end
MOI.get(optimizer::Coluna.Optimizer, ::MOI.SolverName) = "Coluna"

function MOI.optimize!(optimizer::Optimizer)
optimizer.result, optimizer.kpis = optimize!(
optimizer.inner, optimizer.annotations, optimizer.params
optimizer.result = optimize!(
optimizer.env, optimizer.inner, optimizer.annotations
)
return
end
Expand Down Expand Up @@ -674,8 +672,8 @@ function MOI.get(optimizer::Optimizer, ::MOI.ConstraintPrimal, index::MOI.Constr
return constraint_primal(best_primal_sol, getid(constrid))
end

MOI.get(optimizer::Optimizer, ::MOI.NodeCount) = optimizer.kpis.node_count
MOI.get(optimizer::Optimizer, ::MOI.SolveTime) = optimizer.kpis.elapsed_optimization_time
MOI.get(optimizer::Optimizer, ::MOI.NodeCount) = optimizer.env.kpis.node_count
MOI.get(optimizer::Optimizer, ::MOI.SolveTime) = optimizer.env.kpis.elapsed_optimization_time

# function MOI.get(optimizer::Optimizer, ::MOI.ConstraintDual, index::MOI.ConstraintIndex)
# return 0.0
Expand Down
4 changes: 2 additions & 2 deletions src/MathProg/MathProg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ export Reformulation, getmaster, add_dw_pricing_sp!, add_benders_sep_sp!, get_dw
get_dw_pricing_sp_lb_constrid, setmaster!

# Methods related to formulations
export AbstractFormulation, Formulation, getreformulation, getvar, getvars, getconstr,
getconstrs, getelem, getcoefmatrix, getprimalsolmatrix, getprimalsolcosts,
export AbstractFormulation, Formulation, create_formulation!, getreformulation, getvar, getvars,
getconstr, getconstrs, getelem, getcoefmatrix, getprimalsolmatrix, getprimalsolcosts,
getdualsolmatrix, getdualsolrhss, setvar!, setconstr!, setprimalsol!, setdualsol!,
set_robust_constr_generator!, get_robust_constr_generators,
setcol_from_sp_primalsol!, setcut_from_sp_dualsol!, # TODO : merge with setvar! & setconstr
Expand Down
36 changes: 24 additions & 12 deletions src/MathProg/formulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,42 @@ end
"""
`Formulation` stores a mixed-integer linear program.

Formulation{Duty}(
form_counter::Counter;
create_formulation!(
env::Coluna.Env,
duty::Type{<:AbstractFormDuty};
parent_formulation = nothing,
obj_sense::Type{<:Coluna.AbstractSense} = MinSense
) where {Duty<:AbstractFormDuty}
)

Construct a `Formulation` of duty `Duty` with objective sense `obj_sense` and parent formulation
`parent_formulation`.
Create a new formulation in the Coluna's environment `env` with duty `duty`,
parent formulation `parent_formulation`, and objective sense `obj_sense`.
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

I would say "Create a new formulation in the Coluna's environment env with duty duty, parent formulation parent_formulation, and objective sense obj_sense.

function Formulation{D}(
form_counter::Counter;
function create_formulation!(
env::Coluna.Env,
duty::Type{<:AbstractFormDuty};
parent_formulation = nothing,
obj_sense::Type{<:Coluna.AbstractSense} = MinSense
) where {D<:AbstractFormDuty}
if form_counter.value >= MAX_NB_FORMULATIONS
)
if env.form_counter >= MAX_NB_FORMULATIONS
error("Maximum number of formulations reached.")
end
return Formulation{D}(
getnewuid(form_counter), Counter(), Counter(), parent_formulation, NoOptimizer(),
return Formulation{duty}(
env.form_counter += 1, Counter(), Counter(), parent_formulation, NoOptimizer(),
FormulationManager(), obj_sense, FormulationBuffer()
)
end

"""
Formulation{Original}()

Construct a `Formulation` of duty `Original`, when there is no environment.
"""
Formulation{Original}() = Formulation{Original}(
0, Counter(), Counter(),
nothing, NoOptimizer(), FormulationManager(),
MinSense, FormulationBuffer()
)

Copy link
Contributor

Choose a reason for hiding this comment

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

This method should not exist. Do we create the original formulation before instanciating the Env ?

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 think so. Isn't Env instantiated in optimize! ("optimize.jl")?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we can instanciate it when we create Optimizer, what do you think ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that makes sense.

"""
haskey(formulation, id) -> Bool

Expand Down Expand Up @@ -85,7 +98,6 @@ getprimalsolcosts(form::Formulation) = form.manager.primal_sol_costs
getdualsolmatrix(form::Formulation) = form.manager.dual_sols
getdualsolrhss(form::Formulation) = form.manager.dual_sol_rhss


"Returns the `uid` of `Formulation` `form`."
getuid(form::Formulation) = form.uid

Expand Down
6 changes: 2 additions & 4 deletions src/MathProg/problem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ mutable struct Problem <: AbstractProblem
initial_dual_bound::Union{Nothing, Float64}
original_formulation::Formulation
re_formulation::Union{Nothing, Reformulation}
form_counter::Counter # 0 is for original form
default_optimizer_builder::Function
end

Expand All @@ -13,10 +12,9 @@ end
Constructs an empty `Problem`.
"""
function Problem()
counter = Counter(-1)
original_formulation = Formulation{Original}(counter)
original_formulation = Formulation{Original}()
return Problem(
nothing, nothing, original_formulation, nothing, counter,
nothing, nothing, original_formulation, nothing,
no_optimizer_builder
)
end
Expand Down
32 changes: 18 additions & 14 deletions src/decomposition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ function create_global_art_vars!(masterform::Formulation, env::Env)
end

function instantiatemaster!(
prob::Problem, reform::Reformulation, ::Type{BD.Master},
env::Env, prob::Problem, reform::Reformulation, ::Type{BD.Master},
::Type{BD.DantzigWolfe}
)
form = Formulation{DwMaster}(
prob.form_counter;
form = create_formulation!(
env,
MathProg.DwMaster;
parent_formulation = reform,
obj_sense = getobjsense(get_original_formulation(prob))
)
Expand All @@ -41,10 +42,11 @@ function instantiatemaster!(
end

function instantiatemaster!(
prob::Problem, reform::Reformulation, ::Type{BD.Master}, ::Type{BD.Benders}
env::Env, prob::Problem, reform::Reformulation, ::Type{BD.Master}, ::Type{BD.Benders}
)
masterform = Formulation{BendersMaster}(
prob.form_counter;
masterform = create_formulation!(
env,
MathProg.BendersMaster;
parent_formulation = reform,
obj_sense = getobjsense(get_original_formulation(prob))
)
Expand All @@ -53,11 +55,12 @@ function instantiatemaster!(
end

function instantiatesp!(
prob::Problem, reform::Reformulation, masterform::Formulation{DwMaster},
env::Env, reform::Reformulation, masterform::Formulation{DwMaster},
::Type{BD.DwPricingSp}, ::Type{BD.DantzigWolfe}
)
spform = Formulation{DwSp}(
prob.form_counter;
spform = create_formulation!(
env,
MathProg.DwSp;
parent_formulation = masterform,
obj_sense = getobjsense(masterform)
)
Expand All @@ -66,11 +69,12 @@ function instantiatesp!(
end

function instantiatesp!(
prob::Problem, reform::Reformulation, masterform::Formulation{BendersMaster},
env::Env, reform::Reformulation, masterform::Formulation{BendersMaster},
::Type{BD.BendersSepSp}, ::Type{BD.Benders}
)
spform = Formulation{BendersSp}(
prob.form_counter;
spform = create_formulation!(
env,
MathProg.BendersSp;
parent_formulation = masterform,
obj_sense = getobjsense(masterform)
)
Expand Down Expand Up @@ -438,7 +442,7 @@ function buildformulations!(
ann = BD.annotation(node)
form_type = BD.getformulation(ann)
dec_type = BD.getdecomposition(ann)
masterform = instantiatemaster!(prob, reform, form_type, dec_type)
masterform = instantiatemaster!(env, prob, reform, form_type, dec_type)
store!(annotations, masterform, ann)
origform = get_original_formulation(prob)
for (id, child) in BD.subproblems(node)
Expand All @@ -461,7 +465,7 @@ function buildformulations!(
form_type = BD.getformulation(ann)
dec_type = BD.getdecomposition(ann)
masterform = getmaster(reform)
spform = instantiatesp!(prob, reform, masterform, form_type, dec_type)
spform = instantiatesp!(env, reform, masterform, form_type, dec_type)
store!(annotations, spform, ann)
origform = get_original_formulation(prob)
assign_orig_vars_constrs!(spform, origform, env, annotations, ann)
Expand Down
8 changes: 3 additions & 5 deletions src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ end
"""
Starting point of the solver.
"""
function optimize!(prob::MathProg.Problem, annotations::Annotations, params::Params)
function optimize!(env::Env, prob::MathProg.Problem, annotations::Annotations)
_welcome_message()

buffer_reset = prob.original_formulation.buffer
Expand All @@ -49,9 +49,7 @@ function optimize!(prob::MathProg.Problem, annotations::Annotations, params::Par
## Retrieve initial bounds on the objective given by the user
init_pb = get_initial_primal_bound(prob)
init_db = get_initial_dual_bound(prob)
_adjust_params(params, init_pb)

env = Env(params)
_adjust_params(env.params, init_pb)

# Apply decomposition
reformulate!(prob, annotations, env)
Expand All @@ -75,7 +73,7 @@ function optimize!(prob::MathProg.Problem, annotations::Annotations, params::Par
@logmsg LogLevel(0) "Terminated"
@logmsg LogLevel(0) string("Primal bound: ", get_ip_primal_bound(optstate))
@logmsg LogLevel(0) string("Dual bound: ", get_ip_dual_bound(optstate))
return optstate, env.kpis
return optstate
end

function optimize!(
Expand Down
7 changes: 1 addition & 6 deletions test/unit/MathProg/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ function variables_unit_tests()
return
end

function createformulation()
counter = ClF.Counter()
return ClF.Formulation{ClF.Original}(counter)
end

function getset_variables()
form = createformulation()
form = Formulation{Original}()
var = ClF.setvar!(
form, "var1", ClF.OriginalVar, cost = 2.0, lb = -1.0, ub = 1.0,
kind = ClF.Integ, inc_val = 4.0
Expand Down
2 changes: 1 addition & 1 deletion test/unit/constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ end

function constraint_getters_and_setters_tests()

form = createformulation()
form = Formulation{Original}()

c = ClF.setconstr!(form, "fake_constr", ClF.MasterBranchOnOrigVarConstr,
rhs = -13.0, kind = ClF.Facultative, sense = ClF.Equal,
Expand Down
2 changes: 1 addition & 1 deletion test/unit/variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function moi_var_record_getters_and_setters_tests()
end

function variable_getters_and_setters_tests()
form = createformulation()
form = Formulation{Original}()

v_data = ClF.VarData(
; cost = 13.0, lb = -10.0, ub = 100.0, kind = ClF.Continuous,
Expand Down