From acd622a63209ba70f21d79565feea5668792eaf3 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Fri, 14 May 2021 23:04:19 +0200 Subject: [PATCH] Improve ST test coverage. --- .../st_budgeted_lagrangian_refined.jl | 2 +- src/interface/instance.jl | 4 + src/interface/variants.jl | 2 + test/st.jl | 83 +++++++++++++++++-- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/SpanningTree/st_budgeted_lagrangian_refined.jl b/src/SpanningTree/st_budgeted_lagrangian_refined.jl index e01ad35..b0e5114 100644 --- a/src/SpanningTree/st_budgeted_lagrangian_refined.jl +++ b/src/SpanningTree/st_budgeted_lagrangian_refined.jl @@ -2,7 +2,7 @@ function approximation_term( i::MinimumBudget{SpanningTreeInstance{T, Maximise}, U}, ::LagrangianRefinementAlgorithm, ) where {T, U} - return maximum(values(i.rewards)) + return maximum(values(i.instance.rewards)) end function approximation_ratio( ::MinimumBudget{SpanningTreeInstance{T, Maximise}, U}, diff --git a/src/interface/instance.jl b/src/interface/instance.jl index abc4f03..ac55529 100644 --- a/src/interface/instance.jl +++ b/src/interface/instance.jl @@ -132,6 +132,10 @@ function reward(i::CombinatorialInstance, var) return i.rewards[var] end +function reward(i::MinimumBudget, var) + return reward(i.instance, var) +end + """ value(s::CombinatorialSolution) diff --git a/src/interface/variants.jl b/src/interface/variants.jl index c2c3d5b..0ef707f 100644 --- a/src/interface/variants.jl +++ b/src/interface/variants.jl @@ -102,6 +102,8 @@ of `i`). """ abstract type MultipleMinBudgetedSolution <: MinBudgetedSolution end +# TODO: weight interface for a solution (like value). + # # Maximum budget. # """ diff --git a/test/st.jl b/test/st.jl index 8c55814..eadc33f 100644 --- a/test/st.jl +++ b/test/st.jl @@ -157,11 +157,84 @@ @testset "Budgeted maximum spanning tree" begin @testset "Interface" begin + graph = complete_graph(3) + rewards = Dict(Edge(1, 2) => 1.0, Edge(1, 3) => 0.5, Edge(2, 3) => 3.0) + weights = Dict(Edge(1, 2) => 0, Edge(1, 3) => 2, Edge(2, 3) => 0) + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + + @testset "Global interface" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + @test objective(i) == Maximise() + end + + @testset "Copying" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + i2 = copy(i) + @test i.weights == i2.weights + @test i.min_budget == i2.min_budget + @test i.compute_all_values == i2.compute_all_values + @test i.instance.graph == i2.instance.graph + @test i.instance.rewards == i2.instance.rewards + @test i.instance.objective == i2.instance.objective + end + + @testset "Reward accessor" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + + @test reward(i, Edge(1, 2)) == reward(i, Edge(2, 1)) + end + + @testset "Approximation" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + + @test approximation_ratio(i, DynamicProgramming()) == 1.0 + @test approximation_term(i, DynamicProgramming()) == 0.0 + + @test approximation_ratio(i, DefaultLinearFormulation(Cbc.Optimizer)) == 1.0 + @test approximation_term(i, DefaultLinearFormulation(Cbc.Optimizer)) == 0.0 + + @test isnan(approximation_ratio(i, LagrangianAlgorithm())) + @test isnan(approximation_term(i, LagrangianAlgorithm())) + + @test isnan(approximation_ratio(i, LagrangianRefinementAlgorithm())) + @test approximation_term(i, LagrangianRefinementAlgorithm()) == 3.0 # Depends on the instance. + + @test approximation_ratio(i, IteratedLagrangianRefinementAlgorithm()) == 0.5 + @test isnan(approximation_term(i, IteratedLagrangianRefinementAlgorithm())) + end + + @testset "Make solution" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + d = Dict(Edge(1, 2) => 0.8, Edge(1, 3) => 0.2, Edge(2, 3) => 1.0) + s = make_solution(i, d) + + @test s.instance == i + @test length(s.variables) == 2 + @test Edge(1, 2) ∈ s.variables + @test Edge(1, 3) ∉ s.variables + @test Edge(2, 3) ∈ s.variables + + @test value(s) == 4.0 + end + + @testset "Solution helpers" begin + i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) + + # Infeasible solution. + s = SimpleBudgetedSpanningTreeSolution(i, Edge{Int}[]) + @test value(s) == -Inf + + # Valid solution. + d = Dict(Edge(1, 2) => 0.8, Edge(1, 3) => 0.2, Edge(2, 3) => 1.0) + s = make_solution(i, d) + @test value(s) == 4 + + # Valid solution with reversed edges. + s = SimpleBudgetedSpanningTreeSolution(i, [Edge(2, 1), Edge(3, 2)]) + @test value(s) == 4 + end + @testset "Value of a tree" begin - graph = complete_graph(3) - rewards = - Dict(Edge(1, 2) => 1.0, Edge(1, 3) => 0.5, Edge(2, 3) => 3.0) - weights = Dict(Edge(1, 2) => 0, Edge(1, 3) => 2, Edge(2, 3) => 0) i = MinimumBudget(SpanningTreeInstance(graph, rewards), weights, 0) @test Kombinator.SpanningTree._budgeted_spanning_tree_compute_value( @@ -327,8 +400,6 @@ end end - # More advanced tests to ensure the algorithm works as expected. - @testset "Conformity" begin graph = complete_graph(2) r = Dict(Edge(1, 2) => 0.0)