Skip to content

Commit d922b3f

Browse files
committed
Fix sorting non-dominated solutions to use a tolerance
1 parent 2f32152 commit d922b3f

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

src/MultiObjectiveAlgorithms.jl

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,26 @@ function _dominates(
5151
end
5252
end
5353

54-
function _sort!(solutions::Vector{SolutionPoint}, sense::MOI.OptimizationSense)
55-
return sort!(solutions; by = x -> x.y, rev = sense == MOI.MAX_SENSE)
54+
# The use of `atol` when sorting is to work-around a tolerance issue that caused
55+
# a test failure in #181 that wasn't reproducible on macOS. It happened on linux
56+
# because of a minor version change in HiGHS.
57+
#
58+
# Consider two Y vectors `y1 = [22, 37, 63]` and `y2 = [22, 54, 47]`. We clearly
59+
# want to return them in the order `y1`, `y2`, but if `y1[1] = 22+eps` then
60+
# we'll get these "round the wrong way" from the user's perspective, even though
61+
# it would be numerically correct.
62+
#
63+
# My solution is just to round these to the nearest `atol`. The main situation
64+
# that this would be confusing is when the objective is integer and we sort
65+
# wrongly because of 0.9999999 and 1.00000001 etc.
66+
function _sort!(
67+
solutions::Vector{SolutionPoint},
68+
sense::MOI.OptimizationSense;
69+
atol::Float64,
70+
)
71+
digits = round(Int, log10(atol))
72+
rev = sense == MOI.MAX_SENSE
73+
return sort!(solutions; by = p -> round.(p.y; digits), rev)
5674
end
5775

5876
"""
@@ -83,7 +101,7 @@ function filter_nondominated(
83101
push!(nondominated_solutions, candidate)
84102
end
85103
end
86-
_sort!(nondominated_solutions, sense)
104+
_sort!(nondominated_solutions, sense; atol)
87105
return nondominated_solutions
88106
end
89107

0 commit comments

Comments
 (0)