Skip to content

Commit 21b42d7

Browse files
authored
Add tests for solve failures in Chalmet (#124)
1 parent b4c016a commit 21b42d7

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed

src/algorithms/Chalmet.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
6767
MOI.LessThan(y1[2]),
6868
)
6969
MOI.optimize!(model.inner)
70+
status = MOI.get(model.inner, MOI.TerminationStatus())
71+
if !_is_scalar_status_optimal(status)
72+
return status, nothing
73+
end
7074
x1, y1[1] = _compute_point(model, variables, f1)
7175
MOI.delete(model.inner, y1_constraint)
7276
push!(solutions, SolutionPoint(x1, y1))
@@ -87,6 +91,10 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
8791
MOI.LessThan(y2[1]),
8892
)
8993
MOI.optimize!(model.inner)
94+
status = MOI.get(model.inner, MOI.TerminationStatus())
95+
if !_is_scalar_status_optimal(status)
96+
return status, nothing
97+
end
9098
x2, y2[2] = _compute_point(model, variables, f2)
9199
MOI.delete(model.inner, y2_constraint)
92100
push!(solutions, SolutionPoint(x2, y2))

test/algorithms/Chalmet.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import HiGHS
1111
import MultiObjectiveAlgorithms as MOA
1212
import MultiObjectiveAlgorithms: MOI
1313

14+
include(joinpath(dirname(@__DIR__), "mock_optimizer.jl"))
15+
1416
function run_tests()
1517
for name in names(@__MODULE__; all = true)
1618
if startswith("$name", "test_")
@@ -253,6 +255,34 @@ function test_single_point()
253255
return
254256
end
255257

258+
function test_solve_failures()
259+
m, n = 2, 10
260+
p1 = [5.0 1 10 8 3 5 3 3 7 2; 10 6 1 6 8 3 2 10 6 1]
261+
p2 = [4.0 6 4 3 1 6 8 2 9 7; 8 8 8 2 4 8 8 1 10 1]
262+
w = [5.0 9 3 5 10 5 7 10 7 8; 4 8 8 6 10 8 10 7 5 1]
263+
b = [34.0, 33.0]
264+
for fail_after in 0:3
265+
model = MOA.Optimizer(mock_optimizer(fail_after))
266+
MOI.set(model, MOA.Algorithm(), MOA.Chalmet())
267+
x_ = MOI.add_variables(model, m * n)
268+
x = reshape(x_, m, n)
269+
MOI.add_constraint.(model, x, MOI.Interval(0.0, 1.0))
270+
f = MOI.Utilities.operate(vcat, Float64, sum(p1 .* x), sum(p2 .* x))
271+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
272+
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
273+
for i in 1:m
274+
f_i = sum(w[i, j] * x[i, j] for j in 1:n)
275+
MOI.add_constraint(model, f_i, MOI.LessThan(b[i]))
276+
end
277+
for j in 1:n
278+
MOI.add_constraint(model, sum(1.0 .* x[:, j]), MOI.EqualTo(1.0))
279+
end
280+
MOI.optimize!(model)
281+
@test MOI.get(model, MOI.TerminationStatus()) == MOI.NUMERICAL_ERROR
282+
end
283+
return
284+
end
285+
256286
end # module TestChalmet
257287

258288
TestChalmet.run_tests()

test/algorithms/Dichotomy.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import Ipopt
1212
import MultiObjectiveAlgorithms as MOA
1313
import MultiObjectiveAlgorithms: MOI
1414

15+
include(joinpath(dirname(@__DIR__), "mock_optimizer.jl"))
16+
1517
function run_tests()
1618
for name in names(@__MODULE__; all = true)
1719
if startswith("$name", "test_")
@@ -407,6 +409,34 @@ function test_vector_of_variables_objective()
407409
return
408410
end
409411

412+
function test_solve_failures()
413+
m, n = 2, 10
414+
p1 = [5.0 1 10 8 3 5 3 3 7 2; 10 6 1 6 8 3 2 10 6 1]
415+
p2 = [4.0 6 4 3 1 6 8 2 9 7; 8 8 8 2 4 8 8 1 10 1]
416+
w = [5.0 9 3 5 10 5 7 10 7 8; 4 8 8 6 10 8 10 7 5 1]
417+
b = [34.0, 33.0]
418+
for fail_after in 0:3
419+
model = MOA.Optimizer(mock_optimizer(fail_after))
420+
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
421+
x_ = MOI.add_variables(model, m * n)
422+
x = reshape(x_, m, n)
423+
MOI.add_constraint.(model, x, MOI.Interval(0.0, 1.0))
424+
f = MOI.Utilities.operate(vcat, Float64, sum(p1 .* x), sum(p2 .* x))
425+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
426+
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
427+
for i in 1:m
428+
f_i = sum(w[i, j] * x[i, j] for j in 1:n)
429+
MOI.add_constraint(model, f_i, MOI.LessThan(b[i]))
430+
end
431+
for j in 1:n
432+
MOI.add_constraint(model, sum(1.0 .* x[:, j]), MOI.EqualTo(1.0))
433+
end
434+
MOI.optimize!(model)
435+
@test MOI.get(model, MOI.TerminationStatus()) == MOI.NUMERICAL_ERROR
436+
end
437+
return
438+
end
439+
410440
end # module TestDichotomy
411441

412442
TestDichotomy.run_tests()

test/algorithms/EpsilonConstraint.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Ipopt
1212
import MultiObjectiveAlgorithms as MOA
1313
import MultiObjectiveAlgorithms: MOI
1414

15+
include(joinpath(dirname(@__DIR__), "mock_optimizer.jl"))
1516
include(joinpath(dirname(@__DIR__), "vOptLib.jl"))
1617

1718
function run_tests()
@@ -502,6 +503,34 @@ function test_too_many_objectives()
502503
return
503504
end
504505

506+
function test_solve_failures()
507+
m, n = 2, 10
508+
p1 = [5.0 1 10 8 3 5 3 3 7 2; 10 6 1 6 8 3 2 10 6 1]
509+
p2 = [4.0 6 4 3 1 6 8 2 9 7; 8 8 8 2 4 8 8 1 10 1]
510+
w = [5.0 9 3 5 10 5 7 10 7 8; 4 8 8 6 10 8 10 7 5 1]
511+
b = [34.0, 33.0]
512+
for fail_after in 0:3
513+
model = MOA.Optimizer(mock_optimizer(fail_after))
514+
MOI.set(model, MOA.Algorithm(), MOA.EpsilonConstraint())
515+
x_ = MOI.add_variables(model, m * n)
516+
x = reshape(x_, m, n)
517+
MOI.add_constraint.(model, x, MOI.Interval(0.0, 1.0))
518+
f = MOI.Utilities.operate(vcat, Float64, sum(p1 .* x), sum(p2 .* x))
519+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
520+
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
521+
for i in 1:m
522+
f_i = sum(w[i, j] * x[i, j] for j in 1:n)
523+
MOI.add_constraint(model, f_i, MOI.LessThan(b[i]))
524+
end
525+
for j in 1:n
526+
MOI.add_constraint(model, sum(1.0 .* x[:, j]), MOI.EqualTo(1.0))
527+
end
528+
MOI.optimize!(model)
529+
@test MOI.get(model, MOI.TerminationStatus()) == MOI.NUMERICAL_ERROR
530+
end
531+
return
532+
end
533+
505534
end # module TestEpsilonConstraint
506535

507536
TestEpsilonConstraint.run_tests()

test/mock_optimizer.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2019, Oscar Dowson and contributors
2+
# This Source Code Form is subject to the terms of the Mozilla Public License,
3+
# v.2.0. If a copy of the MPL was not distributed with this file, You can
4+
# obtain one at http://mozilla.org/MPL/2.0/.
5+
6+
function _solve_mock(mock)
7+
highs = HiGHS.Optimizer()
8+
MOI.set(highs, MOI.Silent(), true)
9+
index_map = MOI.copy_to(highs, mock)
10+
MOI.optimize!(highs)
11+
x = [index_map[xi] for xi in MOI.get(mock, MOI.ListOfVariableIndices())]
12+
MOI.Utilities.mock_optimize!(
13+
mock,
14+
MOI.get(highs, MOI.TerminationStatus()),
15+
MOI.get(highs, MOI.VariablePrimal(), x),
16+
)
17+
obj = MOI.get(highs, MOI.ObjectiveValue())
18+
MOI.set(mock, MOI.ObjectiveValue(), obj)
19+
return
20+
end
21+
22+
function mock_optimizer(fail_after::Int)
23+
return () -> begin
24+
model = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
25+
MOI.Utilities.set_mock_optimize!(
26+
model,
27+
ntuple(i -> _solve_mock, fail_after)...,
28+
mock -> MOI.Utilities.mock_optimize!(mock, MOI.NUMERICAL_ERROR),
29+
)
30+
return model
31+
end
32+
end

0 commit comments

Comments
 (0)