@@ -117,6 +117,7 @@ function optimize_multiobjective!(
117117 end
118118 limit = MOI. get (algorithm, SolutionLimit ())
119119 status = MOI. OPTIMAL
120+ atol = 1e-6
120121 while length (queue) > 0 && length (solutions) < limit
121122 if (ret = _check_premature_termination (model)) != = nothing
122123 status = ret
@@ -125,15 +126,24 @@ function optimize_multiobjective!(
125126 (a, b) = popfirst! (queue)
126127 y_d = solutions[a]. y .- solutions[b]. y
127128 w = y_d[2 ] / (y_d[2 ] - y_d[1 ])
129+ if ! (a <= w <= b)
130+ # The weight is outside the domain. This can happen if the solver
131+ # finds a solution "outside" the domain by some small numerical
132+ # value, either because of constraint feasibility, or, more likely,
133+ # because of the MIP gap. See MultiObjectiveAlgorithms.jl#191.
134+ # We don't need to search this weight
135+ continue
136+ end
128137 status, solution =
129138 _solve_weighted_sum (algorithm, model, inner, f, [w, 1.0 - w])
130139 if ! _is_scalar_status_optimal (status)
131140 break # Exit the solve with some error.
132- elseif solution ≈ solutions[a] || solution ≈ solutions[b]
141+ end
142+ if ≈ (solution, solutions[a]; atol) || ≈ (solution, solutions[b]; atol)
133143 # We have found an existing solution. We're free to prune (a, b)
134144 # from the search space.
135145 else
136- # Solution is identical to a and b, so search the domain (a, w) and
146+ # Solution is different to a and b, so search the domain (a, w) and
137147 # (w, b), and add solution as a new Pareto-optimal solution!
138148 push! (queue, (a, w))
139149 push! (queue, (w, b))
0 commit comments