Skip to content

Commit 78bbdda

Browse files
committed
Update
1 parent 7aea42f commit 78bbdda

File tree

5 files changed

+46
-88
lines changed

5 files changed

+46
-88
lines changed

src/MultiObjectiveAlgorithms.jl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
120120
solutions::Vector{SolutionPoint}
121121
termination_status::MOI.TerminationStatusCode
122122
time_limit_sec::Union{Nothing,Float64}
123+
solution_limit::Union{Nothing,Int}
123124
solve_time::Float64
124125
ideal_point::Vector{Float64}
125126
compute_ideal_point::Bool
@@ -134,6 +135,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
134135
SolutionPoint[],
135136
MOI.OPTIMIZE_NOT_CALLED,
136137
nothing,
138+
nothing,
137139
NaN,
138140
Float64[],
139141
default(ComputeIdealPoint()),
@@ -187,6 +189,24 @@ function MOI.set(model::Optimizer, ::MOI.TimeLimitSec, ::Nothing)
187189
return
188190
end
189191

192+
### SolutionLimit
193+
194+
const SolutionLimit = MOI.SolutionLimit
195+
196+
MOI.supports(::Optimizer, ::MOI.SolutionLimit) = true
197+
198+
MOI.get(model::Optimizer, ::MOI.SolutionLimit) = model.solution_limit
199+
200+
function MOI.set(model::Optimizer, ::MOI.SolutionLimit, value::Integer)
201+
model.solution_limit = Int(value)
202+
return
203+
end
204+
205+
function MOI.set(model::Optimizer, ::MOI.SolutionLimit, ::Nothing)
206+
model.solution_limit = nothing
207+
return
208+
end
209+
190210
### SolveTimeSec
191211

192212
function MOI.get(model::Optimizer, ::MOI.SolveTimeSec)
@@ -263,11 +283,6 @@ function MOI.get(model::Optimizer, attr::AbstractAlgorithmAttribute)
263283
return MOI.get(model.algorithm, attr)
264284
end
265285

266-
const SolutionLimit = MOI.SolutionLimit
267-
268-
default(::MOI.SolutionLimit) = typemax(Int)
269-
default(::AbstractAlgorithm, attr::MOI.SolutionLimit) = default(attr)
270-
271286
"""
272287
ObjectivePriority(index::Int) <: AbstractAlgorithmAttribute -> Int
273288

src/algorithms/Dichotomy.jl

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ Science 25(1), 73-78.
1818
1919
* `MOI.SolutionLimit()`: terminate once this many solutions have been found.
2020
"""
21-
mutable struct Dichotomy <: AbstractAlgorithm
22-
solution_limit::Union{Nothing,Int}
23-
24-
Dichotomy() = new(nothing)
25-
end
21+
mutable struct Dichotomy <: AbstractAlgorithm end
2622

2723
"""
2824
NISE()
@@ -43,17 +39,6 @@ trade‐offs: An algorithm for bicriterion problems. Water Resources Research,
4339
"""
4440
NISE() = Dichotomy()
4541

46-
MOI.supports(::Dichotomy, ::MOI.SolutionLimit) = true
47-
48-
function MOI.set(alg::Dichotomy, ::MOI.SolutionLimit, value)
49-
alg.solution_limit = value
50-
return
51-
end
52-
53-
function MOI.get(alg::Dichotomy, attr::MOI.SolutionLimit)
54-
return something(alg.solution_limit, default(alg, attr))
55-
end
56-
5742
function _solve_weighted_sum(
5843
model::Optimizer,
5944
::Dichotomy,
@@ -100,7 +85,7 @@ function optimize_multiobjective!(algorithm::Dichotomy, model::Optimizer)
10085
if !(solutions[0.0] solutions[1.0])
10186
push!(queue, (0.0, 1.0))
10287
end
103-
limit = MOI.get(algorithm, MOI.SolutionLimit())
88+
limit = something(MOI.get(model, MOI.SolutionLimit()), typemax(Int))
10489
status = MOI.OPTIMAL
10590
while length(queue) > 0 && length(solutions) < limit
10691
if (ret = _check_premature_termination(model, start_time)) !== nothing

src/algorithms/EpsilonConstraint.jl

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,9 @@ bi-objective programs.
2727
list of current solutions.
2828
"""
2929
mutable struct EpsilonConstraint <: AbstractAlgorithm
30-
solution_limit::Union{Nothing,Int}
3130
atol::Union{Nothing,Float64}
3231

33-
EpsilonConstraint() = new(nothing, nothing)
34-
end
35-
36-
MOI.supports(::EpsilonConstraint, ::MOI.SolutionLimit) = true
37-
38-
function MOI.set(alg::EpsilonConstraint, ::MOI.SolutionLimit, value)
39-
alg.solution_limit = value
40-
return
41-
end
42-
43-
function MOI.get(alg::EpsilonConstraint, attr::MOI.SolutionLimit)
44-
return something(alg.solution_limit, default(alg, attr))
32+
EpsilonConstraint() = new(nothing)
4533
end
4634

4735
MOI.supports(::EpsilonConstraint, ::EpsilonConstraintStep) = true
@@ -94,8 +82,9 @@ function minimize_multiobjective!(
9482
model.ideal_point .= min.(solution_1[1].y, solution_2[1].y)
9583
# Compute the epsilon that we will be incrementing by each iteration
9684
ε = MOI.get(algorithm, EpsilonConstraintStep())
97-
n_points = MOI.get(algorithm, MOI.SolutionLimit())
98-
if n_points != default(algorithm, MOI.SolutionLimit())
85+
n_points = MOI.get(model, MOI.SolutionLimit())
86+
if n_points === nothing
87+
n_points = typemax(Int)
9988
ε = abs(right - left) / (n_points - 1)
10089
end
10190
solutions = SolutionPoint[only(solution_1), only(solution_2)]

src/algorithms/RandomWeighting.jl

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,7 @@ random weights.
1818
1919
At least one of these two limits must be set.
2020
"""
21-
mutable struct RandomWeighting <: AbstractAlgorithm
22-
solution_limit::Union{Nothing,Int}
23-
RandomWeighting() = new(nothing)
24-
end
25-
26-
MOI.supports(::RandomWeighting, ::MOI.SolutionLimit) = true
27-
28-
function MOI.set(alg::RandomWeighting, ::MOI.SolutionLimit, value)
29-
alg.solution_limit = value
30-
return
31-
end
32-
33-
function MOI.get(alg::RandomWeighting, attr::MOI.SolutionLimit)
34-
return something(alg.solution_limit, default(alg, attr))
35-
end
21+
mutable struct RandomWeighting <: AbstractAlgorithm end
3622

3723
function optimize_multiobjective!(algorithm::RandomWeighting, model::Optimizer)
3824
if MOI.get(model, MOI.TimeLimitSec()) === nothing &&
@@ -42,39 +28,25 @@ function optimize_multiobjective!(algorithm::RandomWeighting, model::Optimizer)
4228
start_time = time()
4329
solutions = SolutionPoint[]
4430
sense = MOI.get(model, MOI.ObjectiveSense())
45-
P = MOI.output_dimension(model.f)
4631
variables = MOI.get(model.inner, MOI.ListOfVariableIndices())
47-
f = _scalarise(model.f, ones(P))
48-
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f)}(), f)
49-
optimize_inner!(model)
50-
status = MOI.get(model.inner, MOI.TerminationStatus())
51-
if _is_scalar_status_optimal(status)
52-
X, Y = _compute_point(model, variables, model.f)
53-
push!(solutions, SolutionPoint(X, Y))
54-
else
55-
return status, nothing
56-
end
57-
# This double loop is a bit weird:
58-
# * the inner loop fills up SolutionLimit number of solutions. Then we cut
59-
# it back to nondominated.
60-
# * then the outer loop goes again
61-
while length(solutions) < MOI.get(algorithm, SolutionLimit())
62-
while length(solutions) < MOI.get(algorithm, SolutionLimit())
63-
ret = _check_premature_termination(model, start_time)
64-
if ret !== nothing
65-
return ret, filter_nondominated(sense, solutions)
66-
end
67-
weights = rand(P)
68-
f = _scalarise(model.f, weights)
69-
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f)}(), f)
70-
optimize_inner!(model)
71-
status = MOI.get(model.inner, MOI.TerminationStatus())
72-
if _is_scalar_status_optimal(status)
73-
X, Y = _compute_point(model, variables, model.f)
74-
push!(solutions, SolutionPoint(X, Y))
75-
end
32+
limit = something(MOI.get(model, MOI.SolutionLimit()), typemax(Int))
33+
status = MOI.OPTIMAL
34+
while length(solutions) < limit
35+
if (ret = _check_premature_termination(model, start_time)) !== nothing
36+
status = ret
37+
break
38+
end
39+
weights = rand(MOI.output_dimension(model.f))
40+
f = _scalarise(model.f, weights)
41+
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f)}(), f)
42+
optimize_inner!(model)
43+
if _is_scalar_status_optimal(model)
44+
X, Y = _compute_point(model, variables, model.f)
45+
push!(solutions, SolutionPoint(X, Y))
46+
end
47+
if length(solutions) == limit
48+
solutions = filter_nondominated(sense, solutions)
7649
end
77-
solutions = filter_nondominated(sense, solutions)
7850
end
79-
return MOI.OPTIMAL, filter_nondominated(sense, solutions)
51+
return status, filter_nondominated(sense, solutions)
8052
end

test/algorithms/Dichotomy.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ end
2828
function test_Dichotomy_SolutionLimit()
2929
model = MOA.Optimizer(HiGHS.Optimizer)
3030
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
31-
@test MOI.supports(MOA.Dichotomy(), MOI.SolutionLimit())
3231
@test MOI.supports(model, MOI.SolutionLimit())
33-
@test MOI.get(model, MOI.SolutionLimit()) ==
34-
MOA.default(MOI.SolutionLimit())
32+
@test MOI.get(model, MOI.SolutionLimit()) == nothing
3533
MOI.set(model, MOI.SolutionLimit(), 1)
3634
@test MOI.get(model, MOI.SolutionLimit()) == 1
3735
return
@@ -343,7 +341,6 @@ function test_deprecated()
343341
nise = MOA.NISE()
344342
dichotomy = MOA.Dichotomy()
345343
@test nise isa typeof(dichotomy)
346-
@test nise.solution_limit === dichotomy.solution_limit
347344
return
348345
end
349346

0 commit comments

Comments
 (0)