From de77e84b4d2a0ada23316b64911e3a14c35a3cf7 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 20 Aug 2025 13:11:58 +1200 Subject: [PATCH 1/2] Improve code coverage --- src/algorithms/TambyVanderpooten.jl | 4 ++++ test/algorithms/Lexicographic.jl | 27 ++++++++++++++++++++++++ test/algorithms/TambyVanderpooten.jl | 31 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/algorithms/TambyVanderpooten.jl b/src/algorithms/TambyVanderpooten.jl index 48128b4..a3c7901 100644 --- a/src/algorithms/TambyVanderpooten.jl +++ b/src/algorithms/TambyVanderpooten.jl @@ -160,6 +160,8 @@ function minimize_multiobjective!( optimize_inner!(model) if !_is_scalar_status_optimal(model) MOI.delete.(model, ε_constraints) + # If this fails, it likely means that the solver experienced a + # numerical error with this box. Just skip it. return status, nothing end y_k = MOI.get(model.inner, MOI.ObjectiveValue()) @@ -172,6 +174,8 @@ function minimize_multiobjective!( ) optimize_inner!(model) if !_is_scalar_status_optimal(model) + # If this fails, it likely means that the solver experienced a + # numerical error with this box. Just skip it. MOI.delete.(model, ε_constraints) MOI.delete(model, y_k_constraint) return status, nothing diff --git a/test/algorithms/Lexicographic.jl b/test/algorithms/Lexicographic.jl index 2238995..0cc4461 100644 --- a/test/algorithms/Lexicographic.jl +++ b/test/algorithms/Lexicographic.jl @@ -49,6 +49,33 @@ function test_knapsack() return end +function test_caching_optimizer_knapsack() + model = MOI.instantiate( + () -> MOA.Optimizer(HiGHS.Optimizer); + with_cache_type = Float64, + ) + P = Float64[1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0] + MOI.set(model, MOA.Algorithm(), MOA.Lexicographic()) + @test MOI.supports(model, MOA.LexicographicAllPermutations()) + @test MOI.supports(model, MOA.ObjectiveRelativeTolerance(1)) + MOI.set(model, MOA.LexicographicAllPermutations(), false) + MOI.set(model, MOA.ObjectiveRelativeTolerance(1), 0.1) + MOI.set(model, MOI.Silent(), true) + x = MOI.add_variables(model, 4) + MOI.add_constraint.(model, x, MOI.GreaterThan(0.0)) + MOI.add_constraint.(model, x, MOI.LessThan(1.0)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + f = MOI.Utilities.operate(vcat, Float64, P * x...) + f.constants[4] = 1_000.0 + MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) + MOI.add_constraint(model, sum(1.0 * x[i] for i in 1:4), MOI.LessThan(2.0)) + MOI.optimize!(model) + @test MOI.get(model, MOI.ResultCount()) == 1 + x_sol = MOI.get(model, MOI.VariablePrimal(), x) + @test ≈(x_sol, [0.9, 1, 0, 0.1]; atol = 1e-3) + return +end + function test_knapsack_default() P = Float64[1 0 0 0; 0 1 0 0; 0 0 0 1] model = MOA.Optimizer(HiGHS.Optimizer) diff --git a/test/algorithms/TambyVanderpooten.jl b/test/algorithms/TambyVanderpooten.jl index 48cbf6b..bc2046e 100644 --- a/test/algorithms/TambyVanderpooten.jl +++ b/test/algorithms/TambyVanderpooten.jl @@ -11,6 +11,7 @@ import HiGHS import MultiObjectiveAlgorithms as MOA import MultiObjectiveAlgorithms: MOI +include(joinpath(dirname(@__DIR__), "mock_optimizer.jl")) include(joinpath(dirname(@__DIR__), "problems.jl")) include(joinpath(dirname(@__DIR__), "vOptLib.jl")) @@ -146,6 +147,36 @@ function test_vector_of_variables_objective() return end +function test_solve_failures() + m, n = 2, 10 + p1 = [5.0 1 10 8 3 5 3 3 7 2; 10 6 1 6 8 3 2 10 6 1] + p2 = [4.0 6 4 3 1 6 8 2 9 7; 8 8 8 2 4 8 8 1 10 1] + w = [5.0 9 3 5 10 5 7 10 7 8; 4 8 8 6 10 8 10 7 5 1] + b = [34.0, 33.0] + for fail_after in 0:5 + model = MOA.Optimizer(mock_optimizer(fail_after)) + MOI.set(model, MOA.Algorithm(), MOA.TambyVanderpooten()) + x_ = MOI.add_variables(model, m * n) + x = reshape(x_, m, n) + MOI.add_constraint.(model, x, MOI.Interval(0.0, 1.0)) + f = MOI.Utilities.operate(vcat, Float64, sum(p1 .* x), sum(p2 .* x)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) + for i in 1:m + f_i = sum(w[i, j] * x[i, j] for j in 1:n) + MOI.add_constraint(model, f_i, MOI.LessThan(b[i])) + end + for j in 1:n + MOI.add_constraint(model, sum(1.0 .* x[:, j]), MOI.EqualTo(1.0)) + end + MOI.optimize!(model) + @test MOI.get(model, MOI.TerminationStatus()) == + (fail_after <= 3 ? MOI.NUMERICAL_ERROR : MOI.OPTIMAL) + @test MOI.get(model, MOI.ResultCount()) == 0 + end + return +end + end # module TestTambyVanderpooten TestTambyVanderpooten.run_tests() From e749d21ead56d59e6c8356f4db594b560d94462f Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 20 Aug 2025 13:17:32 +1200 Subject: [PATCH 2/2] Update --- src/algorithms/TambyVanderpooten.jl | 10 ++++------ test/algorithms/TambyVanderpooten.jl | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/algorithms/TambyVanderpooten.jl b/src/algorithms/TambyVanderpooten.jl index a3c7901..ffc29a3 100644 --- a/src/algorithms/TambyVanderpooten.jl +++ b/src/algorithms/TambyVanderpooten.jl @@ -158,10 +158,9 @@ function minimize_multiobjective!( end end optimize_inner!(model) - if !_is_scalar_status_optimal(model) + status = MOI.get(model.inner, MOI.TerminationStatus()) + if !_is_scalar_status_optimal(status) MOI.delete.(model, ε_constraints) - # If this fails, it likely means that the solver experienced a - # numerical error with this box. Just skip it. return status, nothing end y_k = MOI.get(model.inner, MOI.ObjectiveValue()) @@ -173,9 +172,8 @@ function minimize_multiobjective!( MOI.EqualTo(y_k), ) optimize_inner!(model) - if !_is_scalar_status_optimal(model) - # If this fails, it likely means that the solver experienced a - # numerical error with this box. Just skip it. + status = MOI.get(model.inner, MOI.TerminationStatus()) + if !_is_scalar_status_optimal(status) MOI.delete.(model, ε_constraints) MOI.delete(model, y_k_constraint) return status, nothing diff --git a/test/algorithms/TambyVanderpooten.jl b/test/algorithms/TambyVanderpooten.jl index bc2046e..6c3b1bd 100644 --- a/test/algorithms/TambyVanderpooten.jl +++ b/test/algorithms/TambyVanderpooten.jl @@ -170,8 +170,7 @@ function test_solve_failures() MOI.add_constraint(model, sum(1.0 .* x[:, j]), MOI.EqualTo(1.0)) end MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == - (fail_after <= 3 ? MOI.NUMERICAL_ERROR : MOI.OPTIMAL) + @test MOI.get(model, MOI.TerminationStatus()) == MOI.NUMERICAL_ERROR @test MOI.get(model, MOI.ResultCount()) == 0 end return