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

Tests for ColGen with identical subproblems #795

Merged
merged 10 commits into from
Mar 30, 2023
2 changes: 1 addition & 1 deletion test/parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ function create_subproblems!(env::Env{ClMP.VarId}, reform::ClMP.Reformulation, c
if isnothing(spform)
spform = ClMP.create_formulation!(
env,
ClMP.DwSp(nothing, nothing, nothing, var.kind);
ClMP.DwSp(nothing, nothing, nothing, ClMP.Integ);
obj_sense = sp.sense
)
end
Expand Down
176 changes: 175 additions & 1 deletion test/unit/ColGen/colgen_default.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,146 @@ function toy_gap_with_obj_const()
return env, master, sps, reform
end

function check_identical_subproblems()
# Used to check the output of identical_subproblem. The two formulations should be equivalent.
# Subproblem 5 is introduced twice.
form = """
master
min
100.0 local_art_of_cov_5 + 100.0 local_art_of_cov_4 + 100.0 local_art_of_cov_6 + 100.0 local_art_of_cov_7 + 100.0 local_art_of_cov_2 + 100.0 local_art_of_cov_3 + 100.0 local_art_of_cov_1 + 100.0 local_art_of_sp_lb_5 + 100.0 local_art_of_sp_ub_5 + 100.0 local_art_of_sp_lb_4 + 100.0 local_art_of_sp_ub_4 + 1000.0 global_pos_art_var + 1000.0 global_neg_art_var + 8.0 x_11 + 5.0 x_12 + 11.0 x_13 + 21.0 x_14 + 6.0 x_15 + 5.0 x_16 + 19.0 x_17 + 8.0 x_21 + 5.0 x_22 + 11.0 x_23 + 21.0 x_24 + 6.0 x_25 + 5.0 x_26 + 19.0 x_27 + PricingSetupVar_sp_5 + 0.0 PricingSetupVar_sp_4
s.t.
1.0 x_11 + 1.0 x_21 + 1.0 local_art_of_cov_1 + 1.0 global_pos_art_var >= 1.0
1.0 x_12 + 1.0 x_22 + 1.0 local_art_of_cov_2 + 1.0 global_pos_art_var >= 1.0
1.0 x_13 + 1.0 x_23 + 1.0 local_art_of_cov_3 + 1.0 global_pos_art_var >= 1.0
1.0 x_14 + 1.0 x_24 + 1.0 local_art_of_cov_4 + 1.0 global_pos_art_var >= 1.0
1.0 x_15 + 1.0 x_25 + 1.0 local_art_of_cov_5 + 1.0 global_pos_art_var >= 1.0
1.0 x_16 + 1.0 x_26 + 1.0 local_art_of_cov_6 + 1.0 global_pos_art_var >= 1.0
1.0 x_17 + 1.0 x_27 + 1.0 local_art_of_cov_7 + 1.0 global_pos_art_var >= 1.0
1.0 PricingSetupVar_sp_5 + 1.0 local_art_of_sp_lb_5 >= 0.0 {MasterConvexityConstr}
1.0 PricingSetupVar_sp_5 - 1.0 local_art_of_sp_ub_5 <= 1.0 {MasterConvexityConstr}
1.0 PricingSetupVar_sp_4 + 1.0 local_art_of_sp_lb_4 >= 0.0 {MasterConvexityConstr}
1.0 PricingSetupVar_sp_4 - 1.0 local_art_of_sp_ub_4 <= 1.0 {MasterConvexityConstr}

dw_sp
min
x_11 + x_12 + x_13 + x_14 + x_15 + x_16 + x_17 + 0.0 PricingSetupVar_sp_5
s.t.
2.0 x_11 + 3.0 x_12 + 3.0 x_13 + 1.0 x_14 + 2.0 x_15 + 1.0 x_16 + 1.0 x_17 <= 5.0

dw_sp
min
x_21 + x_22 + x_23 + x_24 + x_25 + x_26 + x_27 + 0.0 PricingSetupVar_sp_4
s.t.
2.0 x_21 + 3.0 x_22 + 3.0 x_23 + 1.0 x_24 + 2.0 x_25 + 1.0 x_26 + 1.0 x_27 <= 5.0

continuous
artificial
local_art_of_cov_5, local_art_of_cov_4, local_art_of_cov_6, local_art_of_cov_7, local_art_of_cov_2, local_art_of_cov_3, local_art_of_cov_1, local_art_of_sp_lb_5, local_art_of_sp_ub_5, local_art_of_sp_lb_4, local_art_of_sp_ub_4, global_pos_art_var, global_neg_art_var

integer
pricing_setup
PricingSetupVar_sp_4, PricingSetupVar_sp_5

binary
representatives
x_11, x_21, x_12, x_22, x_13, x_23, x_14, x_24, x_15, x_25, x_16, x_26, x_17, x_27

bounds
0.0 <= x_11 <= 1.0
0.0 <= x_21 <= 1.0
0.0 <= x_12 <= 1.0
0.0 <= x_22 <= 1.0
0.0 <= x_13 <= 1.0
0.0 <= x_23 <= 1.0
0.0 <= x_14 <= 1.0
0.0 <= x_24 <= 1.0
0.0 <= x_15 <= 1.0
0.0 <= x_25 <= 1.0
0.0 <= x_16 <= 1.0
0.0 <= x_26 <= 1.0
0.0 <= x_17 <= 1.0
0.0 <= x_27 <= 1.0
1.0 <= PricingSetupVar_sp_4 <= 1.0
1.0 <= PricingSetupVar_sp_5 <= 1.0
local_art_of_cov_5 >= 0.0
local_art_of_cov_4 >= 0.0
local_art_of_cov_6 >= 0.0
local_art_of_cov_7 >= 0.0
local_art_of_cov_2 >= 0.0
local_art_of_cov_3 >= 0.0
local_art_of_cov_1 >= 0.0
local_art_of_sp_lb_5 >= 0.0
local_art_of_sp_ub_5 >= 0.0
local_art_of_sp_lb_4 >= 0.0
local_art_of_sp_ub_4 >= 0.0
global_pos_art_var >= 0.0
global_neg_art_var >= 0.0
"""

env, master, sps, _, reform = reformfromstring(form)
return env, master, sps, reform

end

function identical_subproblems()
form = """
master
min
100.0 local_art_of_cov_5 + 100.0 local_art_of_cov_4 + 100.0 local_art_of_cov_6 + 100.0 local_art_of_cov_7 + 100.0 local_art_of_cov_2 + 100.0 local_art_of_cov_3 + 100.0 local_art_of_cov_1 + 100.0 local_art_of_sp_lb_5 + 100.0 local_art_of_sp_ub_5 + 1000.0 global_pos_art_var + 1000.0 global_neg_art_var + 8.0 x_11 + 5.0 x_12 + 11.0 x_13 + 21.0 x_14 + 6.0 x_15 + 5.0 x_16 + 19.0 x_17 + 0.0 PricingSetupVar_sp_5
s.t.
1.0 x_11 + 1.0 local_art_of_cov_1 + 1.0 global_pos_art_var >= 1.0
1.0 x_12 + 1.0 local_art_of_cov_2 + 1.0 global_pos_art_var >= 1.0
1.0 x_13 + 1.0 local_art_of_cov_3 + 1.0 global_pos_art_var >= 1.0
1.0 x_14 + 1.0 local_art_of_cov_4 + 1.0 global_pos_art_var >= 1.0
1.0 x_15 + 1.0 local_art_of_cov_5 + 1.0 global_pos_art_var >= 1.0
1.0 x_16 + 1.0 local_art_of_cov_6 + 1.0 global_pos_art_var >= 1.0
1.0 x_17 + 1.0 local_art_of_cov_7 + 1.0 global_pos_art_var >= 1.0
1.0 PricingSetupVar_sp_5 + 1.0 local_art_of_sp_lb_5 >= 0.0 {MasterConvexityConstr}
1.0 PricingSetupVar_sp_5 - 1.0 local_art_of_sp_ub_5 <= 2.0 {MasterConvexityConstr}

dw_sp
min
x_11 + x_12 + x_13 + x_14 + x_15 + x_16 + x_17 + 0.0 PricingSetupVar_sp_5
s.t.
2.0 x_11 + 3.0 x_12 + 3.0 x_13 + 1.0 x_14 + 2.0 x_15 + 1.0 x_16 + 1.0 x_17 <= 5.0

continuous
artificial
local_art_of_cov_5, local_art_of_cov_4, local_art_of_cov_6, local_art_of_cov_7, local_art_of_cov_2, local_art_of_cov_3, local_art_of_cov_1, local_art_of_sp_lb_5, local_art_of_sp_ub_5, global_pos_art_var, global_neg_art_var

integer
pricing_setup
PricingSetupVar_sp_5

binary
representatives
x_11, x_12, x_13, x_14, x_15, x_16, x_17

bounds
0.0 <= x_11 <= 1.0
0.0 <= x_12 <= 1.0
0.0 <= x_13 <= 1.0
0.0 <= x_14 <= 1.0
0.0 <= x_15 <= 1.0
0.0 <= x_16 <= 1.0
0.0 <= x_17 <= 1.0
1.0 <= PricingSetupVar_sp_5 <= 1.0
local_art_of_cov_5 >= 0.0
local_art_of_cov_4 >= 0.0
local_art_of_cov_6 >= 0.0
local_art_of_cov_7 >= 0.0
local_art_of_cov_2 >= 0.0
local_art_of_cov_3 >= 0.0
local_art_of_cov_1 >= 0.0
local_art_of_sp_lb_5 >= 0.0
local_art_of_sp_ub_5 >= 0.0
global_pos_art_var >= 0.0
global_neg_art_var >= 0.0
"""
env, master, sps, _, reform = reformfromstring(form)
return env, master, sps, reform
end

### Implementation of ColGen API to test and call the default implementation
struct TestColGenIterationContext <: ColGen.AbstractColGenContext
context::ClA.ColGenContext
Expand Down Expand Up @@ -765,7 +905,7 @@ function test_colgen_iteration_pure_master_vars()
@test output.infeasible_subproblem == false
@test output.unbounded_subproblem == false
end
#register!(unit_tests, "colgen_default", test_colgen_iteration_pure_master_vars)
register!(unit_tests, "colgen_default", test_colgen_iteration_pure_master_vars)

function test_colgen_iteration_obj_const()
env, master, sps, reform = toy_gap_with_obj_const()
Expand Down Expand Up @@ -1189,6 +1329,40 @@ function min_toy_gap_for_colgen()
return env, master, sps, reform
end



function test_identical_subproblems()
env, master, sps, reform = identical_subproblems()
ClMP.push_optimizer!(master, () -> ClA.MoiOptimizer(GLPK.Optimizer())) # we need warm start
ClMP.relax_integrality!(master)
for sp in sps
ClMP.push_optimizer!(sp, () -> ClA.MoiOptimizer(GLPK.Optimizer()))
end
println("\e[35m results: :\e[0m")
ctx = ClA.ColGenPrinterContext(reform, ClA.ColumnGeneration())
output = ColGen.run!(ctx, env)
@show output.mlp
@show output.db
println("\e[35m ************************************ :\e[0m")
end
register!(unit_tests, "colgen_default", test_identical_subproblems)

function expected_output_identical_subproblems()
env, master, sps, reform = check_identical_subproblems()
ClMP.push_optimizer!(master, () -> ClA.MoiOptimizer(GLPK.Optimizer())) # we need warm start
ClMP.relax_integrality!(master)
for sp in sps
ClMP.push_optimizer!(sp, () -> ClA.MoiOptimizer(GLPK.Optimizer()))
end
println("\e[35m expected value: :\e[0m")
ctx = ClA.ColGenPrinterContext(reform, ClA.ColumnGeneration())
output = ColGen.run!(ctx, env)
@show output.mlp
@show output.db
println("\e[35m *********************************** \e[0")
end
register!(unit_tests, "colgen_default", expected_output_identical_subproblems)

function test_colgen()
env, master, sps, reform = min_toy_gap_for_colgen()
# We need subsolvers to optimize the master and subproblems.
Expand Down