Skip to content

Commit 5cf770f

Browse files
authored
Add support for TimeLimitSec to Lexicographic (#70)
1 parent 948ca31 commit 5cf770f

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

src/MultiObjectiveAlgorithms.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,10 @@ function _compute_point(
596596
return X, Y
597597
end
598598

599+
function _is_scalar_status_feasible_point(status::MOI.ResultStatusCode)
600+
return status == MOI.FEASIBLE_POINT
601+
end
602+
599603
function _is_scalar_status_optimal(status::MOI.TerminationStatusCode)
600604
return status == MOI.OPTIMAL || status == MOI.LOCALLY_SOLVED
601605
end

src/algorithms/Lexicographic.jl

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ point on the frontier, corresponding to solving each objective in order.
1111
1212
## Supported optimizer attributes
1313
14+
* `MOI.TimeLimitSec()`: terminate if the time limit is exceeded and return the
15+
current best solutions.
16+
1417
* `MOA.LexicographicAllPermutations()`: Controls whether to return the
1518
lexicographic solution for all permutations of the scalar objectives (when
1619
`true`), or only the solution corresponding to the lexicographic solution of
@@ -62,37 +65,54 @@ function MOI.set(alg::Lexicographic, ::LexicographicAllPermutations, val::Bool)
6265
end
6366

6467
function optimize_multiobjective!(algorithm::Lexicographic, model::Optimizer)
68+
start_time = time()
6569
sequence = 1:MOI.output_dimension(model.f)
6670
if !MOI.get(algorithm, LexicographicAllPermutations())
67-
return _solve_in_sequence(algorithm, model, sequence)
71+
return _solve_in_sequence(algorithm, model, sequence, start_time)
6872
end
6973
solutions = SolutionPoint[]
74+
status = MOI.OPTIMAL
7075
for sequence in Combinatorics.permutations(sequence)
71-
status, solution = _solve_in_sequence(algorithm, model, sequence)
76+
status, solution =
77+
_solve_in_sequence(algorithm, model, sequence, start_time)
78+
if !isempty(solution)
79+
push!(solutions, solution[1])
80+
end
7281
if !_is_scalar_status_optimal(status)
73-
return status, nothing
82+
break
7483
end
75-
push!(solutions, solution[1])
7684
end
7785
sense = MOI.get(model.inner, MOI.ObjectiveSense())
78-
return MOI.OPTIMAL, filter_nondominated(sense, solutions)
86+
return status, filter_nondominated(sense, solutions)
7987
end
8088

8189
function _solve_in_sequence(
8290
algorithm::Lexicographic,
8391
model::Optimizer,
8492
sequence::AbstractVector{Int},
93+
start_time::Float64,
8594
)
8695
variables = MOI.get(model.inner, MOI.ListOfVariableIndices())
8796
constraints = Any[]
8897
scalars = MOI.Utilities.eachscalar(model.f)
98+
solution = SolutionPoint[]
99+
status = MOI.OPTIMAL
89100
for i in sequence
101+
if _time_limit_exceeded(model, start_time)
102+
status = MOI.TIME_LIMIT
103+
break
104+
end
90105
f = scalars[i]
91106
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f)}(), f)
92107
MOI.optimize!(model.inner)
93108
status = MOI.get(model.inner, MOI.TerminationStatus())
109+
primal_status = MOI.get(model.inner, MOI.PrimalStatus())
110+
if _is_scalar_status_feasible_point(primal_status)
111+
X, Y = _compute_point(model, variables, model.f)
112+
solution = [SolutionPoint(X, Y)]
113+
end
94114
if !_is_scalar_status_optimal(status)
95-
return status, nothing
115+
break
96116
end
97117
X, Y = _compute_point(model, variables, f)
98118
rtol = MOI.get(algorithm, ObjectiveRelativeTolerance(i))
@@ -103,9 +123,8 @@ function _solve_in_sequence(
103123
end
104124
push!(constraints, MOI.add_constraint(model, f, set))
105125
end
106-
X, Y = _compute_point(model, variables, model.f)
107126
for c in constraints
108127
MOI.delete(model, c)
109128
end
110-
return MOI.OPTIMAL, [SolutionPoint(X, Y)]
129+
return status, solution
111130
end

0 commit comments

Comments
 (0)