Skip to content

Commit

Permalink
Unit tests for OptimizationState (#548)
Browse files Browse the repository at this point in the history
* add optstate tests and reverse sort for dual sols

* add tests for MaxSense

* improve solutions comparison
  • Loading branch information
laradicp authored Jun 25, 2021
1 parent e25353e commit 68829cb
Show file tree
Hide file tree
Showing 3 changed files with 362 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/Algorithm/utilities/optimizationstate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mutable struct OptimizationState{F<:AbstractFormulation,S<:Coluna.AbstractSense}
end

_sort!(sols::Vector{PrimalSolution{F}}, f::Function) where {F} = sort!(sols, by = x -> f(PrimalBound(x.model, x.bound)))
_sort!(sols::Vector{DualSolution{F}}, f::Function) where {F} = sort!(sols, by = x -> f(DualBound(x.model, x.bound)))
_sort!(sols::Vector{DualSolution{F}}, f::Function) where {F} = sort!(sols, by = x -> f(DualBound(x.model, x.bound)), rev = true)

function bestbound!(solutions::Vector{Sol}, max_len::Int, new_sol::Sol) where {Sol<:Solution}
push!(solutions, new_sol)
Expand All @@ -42,7 +42,7 @@ end
lp_primal_bound = nothing,
lp_dual_bound = nothing,
max_length_ip_primal_sols = 1,
max_length_lp_dual_sols = 1,
max_length_lp_primal_sols = 1,
max_length_lp_dual_sols = 1,
insert_function_ip_primal_sols = bestbound!,
insert_function_lp_primal_sols = bestbound!,
Expand Down
355 changes: 355 additions & 0 deletions test/unit/optimizationstate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,355 @@
function optstate_unit_tests()
update_sol_tests()
add_sol_tests()
set_sol_tests()
end

function update_sol_tests()
############################################################################################
# MinSense #
############################################################################################
form = create_formulation!(Env(Coluna.Params()), Original())
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(
form, max_length_ip_primal_sols = 2.0,
max_length_lp_primal_sols = 2.0, max_length_lp_dual_sols = 2.0
)
primalsol = PrimalSolution(form, [getid(var)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
update_ip_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_ip_primal_bound(state) == 2.0
update_ip_primal_sol!(state, PrimalSolution(
form, [getid(var)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `primalsol` is NOT added to `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
###

### lp primal
update_lp_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 2.0
update_lp_primal_sol!(
state, PrimalSolution(form, [getid(var)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `primalsol` is NOT added to `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
###

### lp dual
update_lp_dual_sol!(state, dualsol)
# check that `dualsol` is added to `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 1.0
update_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `dualsol` is NOT added to `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
###

############################################################################################
# MaxSense #
############################################################################################
form = create_formulation!(
Env(Coluna.Params()), Original(), obj_sense = Coluna.MathProg.MaxSense
)
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(
form, max_length_ip_primal_sols = 2.0,
max_length_lp_primal_sols = 2.0, max_length_lp_dual_sols = 2.0
)
primalsol = PrimalSolution(form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
update_ip_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_ip_primal_bound(state) == 1.0
update_ip_primal_sol!(state, PrimalSolution(
form, [getid(var)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `primalsol` is NOT added to `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
###

### lp primal
update_lp_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 1.0
update_lp_primal_sol!(
state, PrimalSolution(form, [getid(var)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `primalsol` is NOT added to `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
###

### lp dual
update_lp_dual_sol!(state, dualsol)
# check that `dualsol` is added to `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 2.0
update_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY
))
# check that solution worse than `dualsol` is NOT added to `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
###
end

function add_sol_tests()
############################################################################################
# MinSense #
############################################################################################
form = create_formulation!(Env(Coluna.Params()), Original())
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(form)
primalsol = PrimalSolution(form, [getid(var)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
add_ip_primal_sols!(
state,
PrimalSolution(form, [getid(var)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY),
primalsol
)
# check that `primalsol` is added to `state.ip_primal_sols` and worst solution is removed
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_ip_primal_bound(state) == 2.0
###

### lp primal
add_lp_primal_sol!(state, PrimalSolution(
form, [getid(var)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY
))
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 3.0
add_lp_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.lp_primal_sols` and worst solution is removed
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 2.0
###

### lp dual
add_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY
))
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 0.0
add_lp_dual_sol!(state, dualsol)
# check that `dualsol` is added to `state.lp_dual_sols` and worst solution is removed
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 1.0
###

############################################################################################
# MaxSense #
############################################################################################
form = create_formulation!(
Env(Coluna.Params()), Original(), obj_sense = Coluna.MathProg.MaxSense
)
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(form)
primalsol = PrimalSolution(form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
add_ip_primal_sols!(
state,
PrimalSolution(form, [getid(var)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY),
primalsol
)
# check that `primalsol` is added to `state.ip_primal_sols` and worst solution is removed
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_ip_primal_bound(state) == 1.0
###

### lp primal
add_lp_primal_sol!(state, PrimalSolution(
form, [getid(var)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY
))
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 0.0
add_lp_primal_sol!(state, primalsol)
# check that `primalsol` is added to `state.lp_primal_sols` and worst solution is removed
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is updated
@test get_lp_primal_bound(state) == 1.0
###

### lp dual
add_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [3.0], 3.0, CB.UNKNOWN_FEASIBILITY
))
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 3.0
add_lp_dual_sol!(state, dualsol)
# check that `dualsol` is added to `state.lp_dual_sols` and worst solution is removed
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is updated
@test get_lp_dual_bound(state) == 2.0
###
end

function set_sol_tests()
############################################################################################
# MinSense #
############################################################################################
form = create_formulation!(Env(Coluna.Params()), Original())
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(
form, ip_primal_bound = 3.0, lp_primal_bound = 3.0, lp_dual_bound = -1.0
)
primalsol = PrimalSolution(form, [getid(var)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
set_ip_primal_sol!(state, PrimalSolution(
form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_ip_primal_sol!(state, primalsol)
# check that only the solution which was set last is in `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is NOT updated
@test get_ip_primal_bound(state) == 3.0
###

### lp primal
set_lp_primal_sol!(state, PrimalSolution(
form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_lp_primal_sol!(state, primalsol)
# check that only the solution which was set last is in `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is NOT updated
@test get_lp_primal_bound(state) == 3.0
###

### lp dual
set_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_lp_dual_sol!(state, dualsol)
# check that only the solution which was set last is in `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is NOT updated
@test get_lp_dual_bound(state) == -1.0
###

############################################################################################
# MaxSense #
############################################################################################
form = create_formulation!(
Env(Coluna.Params()), Original(), obj_sense = Coluna.MathProg.MaxSense
)
var = ClMP.setvar!(form, "var1", ClMP.OriginalVar)
constr = ClMP.setconstr!(form, "constr1", ClMP.OriginalConstr)
state = OptimizationState(
form, ip_primal_bound = -1.0, lp_primal_bound = -1.0, lp_dual_bound = 3.0
)
primalsol = PrimalSolution(form, [getid(var)], [0.0], 0.0, CB.UNKNOWN_FEASIBILITY)
dualsol = DualSolution(form, [getid(constr)], [2.0], 2.0, CB.UNKNOWN_FEASIBILITY)

### ip primal
set_ip_primal_sol!(state, PrimalSolution(
form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_ip_primal_sol!(state, primalsol)
# check that only the solution which was set last is in `state.ip_primal_sols`
@test length(get_ip_primal_sols(state)) == 1
@test keys(get_ip_primal_sols(state)[1]) == keys(primalsol)
@test values(get_ip_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is NOT updated
@test get_ip_primal_bound(state) == -1.0
###

### lp primal
set_lp_primal_sol!(state, PrimalSolution(
form, [getid(var)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_lp_primal_sol!(state, primalsol)
# check that only the solution which was set last is in `state.lp_primal_sols`
@test length(get_lp_primal_sols(state)) == 1
@test keys(get_lp_primal_sols(state)[1]) == keys(primalsol)
@test values(get_lp_primal_sols(state)[1]) == values(primalsol)
# check that incumbent bound is NOT updated
@test get_lp_primal_bound(state) == -1.0
###

### lp dual
set_lp_dual_sol!(state, DualSolution(
form, [getid(constr)], [1.0], 1.0, CB.UNKNOWN_FEASIBILITY
))
set_lp_dual_sol!(state, dualsol)
# check that only the solution which was set last is in `state.lp_dual_sols`
@test length(get_lp_dual_sols(state)) == 1
@test keys(get_lp_dual_sols(state)[1]) == keys(dualsol)
@test values(get_lp_dual_sols(state)[1]) == values(dualsol)
# check that incumbent bound is NOT updated
@test get_lp_dual_bound(state) == 3.0
###
end
5 changes: 5 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("MathProg/bounds.jl")

include("variable.jl")
include("constraint.jl")
include("optimizationstate.jl")

function unit_tests()
@testset "ColunaBase submodule" begin
Expand All @@ -33,5 +34,9 @@ function unit_tests()
constraint_unit_tests()
end

@testset "optimizationstate.jl" begin
optstate_unit_tests()
end

return
end

0 comments on commit 68829cb

Please sign in to comment.