Skip to content

Commit 39f9696

Browse files
committed
WIP: have customized logging for each algorithm
1 parent b443161 commit 39f9696

File tree

11 files changed

+76
-3
lines changed

11 files changed

+76
-3
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
name = "MultiObjectiveAlgorithms"
22
uuid = "0327d340-17cd-11ea-3e99-2fd5d98cecda"
3-
authors = ["Oscar Dowson <[email protected]>"]
43
version = "1.7.0"
4+
authors = ["Oscar Dowson <[email protected]>"]
55

66
[deps]
77
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
88
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
9+
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
910

1011
[weakdeps]
1112
Polyhedra = "67491407-f73d-577b-9b50-8179a7c68029"
@@ -20,15 +21,16 @@ Ipopt = "1"
2021
JSON = "1"
2122
MathOptInterface = "1.19"
2223
Polyhedra = "0.8"
24+
Printf = "1.11.0"
2325
Test = "1"
2426
julia = "1.10"
2527

2628
[extras]
2729
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
2830
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
2931
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
30-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3132
Polyhedra = "67491407-f73d-577b-9b50-8179a7c68029"
33+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3234

3335
[targets]
3436
test = ["HiGHS", "Ipopt", "JSON", "Test", "Polyhedra"]

src/MultiObjectiveAlgorithms.jl

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
170170
f::Union{Nothing,MOI.AbstractVectorFunction}
171171
solutions::Vector{SolutionPoint}
172172
termination_status::MOI.TerminationStatusCode
173+
silent::Bool
173174
time_limit_sec::Union{Nothing,Float64}
174175
solve_time::Float64
175176
ideal_point::Vector{Float64}
@@ -178,12 +179,17 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
178179
optimizer_factory::Any
179180

180181
function Optimizer(optimizer_factory)
182+
inner = MOI.instantiate(optimizer_factory; with_cache_type = Float64)
183+
if MOI.supports(inner, MOI.Silent())
184+
MOI.set(inner, MOI.Silent(), true)
185+
end
181186
return new(
182-
MOI.instantiate(optimizer_factory; with_cache_type = Float64),
187+
inner,
183188
nothing,
184189
nothing,
185190
SolutionPoint[],
186191
MOI.OPTIMIZE_NOT_CALLED,
192+
false,
187193
nothing,
188194
NaN,
189195
Float64[],
@@ -220,6 +226,17 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
220226
return MOI.Utilities.default_copy_to(dest, src)
221227
end
222228

229+
### Silent
230+
231+
MOI.supports(::Optimizer, ::MOI.Silent) = true
232+
233+
MOI.get(model::Optimizer, ::MOI.Silent) = model.silent
234+
235+
function MOI.set(model::Optimizer, ::MOI.Silent, value::Bool)
236+
model.silent = value
237+
return
238+
end
239+
223240
### TimeLimitSec
224241

225242
function MOI.supports(model::Optimizer, attr::MOI.TimeLimitSec)
@@ -628,6 +645,8 @@ function MOI.delete(model::Optimizer, ci::MOI.ConstraintIndex)
628645
return
629646
end
630647

648+
import Printf
649+
631650
"""
632651
optimize_inner!(model::Optimizer)
633652
@@ -646,6 +665,21 @@ function optimize_inner!(model::Optimizer)
646665
return
647666
end
648667

668+
function _log_solution(model::Optimizer, Y)
669+
if model.silent
670+
return
671+
end
672+
print(_format(model.subproblem_count))
673+
for y in Y
674+
print(" ", _format(y))
675+
end
676+
println()
677+
return
678+
end
679+
_format(x::Int) = Printf.@sprintf("%5d", x)
680+
_format(x::Float64) = Printf.@sprintf("% .5e", x)
681+
_format(::Nothing) = " "
682+
649683
function _compute_ideal_point(model::Optimizer, start_time)
650684
for (i, f) in enumerate(MOI.Utilities.eachscalar(model.f))
651685
if _check_premature_termination(model, start_time) !== nothing
@@ -764,6 +798,13 @@ function _optimize!(model::Optimizer)
764798
empty!(model.ideal_point)
765799
return
766800
end
801+
if !model.silent
802+
print("Iter.")
803+
for i in 1:MOI.output_dimension(model.f)
804+
print(lpad("Obj. $i", 13))
805+
end
806+
println()
807+
end
767808
# We need to clear the ideal point prior to starting the solve. Algorithms
768809
# may update this during the solve, otherwise we will update it at the end.
769810
model.ideal_point = fill(NaN, MOI.output_dimension(model.f))
@@ -774,6 +815,9 @@ function _optimize!(model::Optimizer)
774815
model.solutions = solutions
775816
_sort!(model.solutions, MOI.get(model, MOI.ObjectiveSense()))
776817
end
818+
if !model.silent
819+
println("Found $(length(model.solutions)) solutions")
820+
end
777821
if MOI.get(model, ComputeIdealPoint())
778822
_compute_ideal_point(model, start_time)
779823
end

src/algorithms/Chalmet.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function _solve_constrained_model(
4343
end
4444
variables = MOI.get(model.inner, MOI.ListOfVariableIndices())
4545
X, Y = _compute_point(model, variables, model.f)
46+
_log_solution(model, Y)
4647
MOI.delete.(model, c)
4748
return status, SolutionPoint(X, Y)
4849
end
@@ -66,6 +67,7 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
6667
return status, solutions
6768
end
6869
_, y1[2] = _compute_point(model, variables, f2)
70+
_log_solution(model, y1[2])
6971
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f1)}(), f1)
7072
y1_constraint = MOI.Utilities.normalize_and_add_constraint(
7173
model.inner,
@@ -78,6 +80,7 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
7880
return status, solutions
7981
end
8082
x1, y1[1] = _compute_point(model, variables, f1)
83+
_log_solution(model, y1[1])
8184
MOI.delete(model.inner, y1_constraint)
8285
push!(solutions, SolutionPoint(x1, y1))
8386
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f1)}(), f1)
@@ -87,6 +90,7 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
8790
return status, solutions
8891
end
8992
_, y2[1] = _compute_point(model, variables, f1)
93+
_log_solution(model, y2[1])
9094
if y2[1] solutions[1].y[1]
9195
return MOI.OPTIMAL, solutions
9296
end
@@ -102,6 +106,7 @@ function minimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
102106
return status, solutions
103107
end
104108
x2, y2[2] = _compute_point(model, variables, f2)
109+
_log_solution(model, y2[2])
105110
MOI.delete(model.inner, y2_constraint)
106111
push!(solutions, SolutionPoint(x2, y2))
107112
push!(Q, (1, 2))

src/algorithms/Dichotomy.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function _solve_weighted_sum(
7474
end
7575
variables = MOI.get(model.inner, MOI.ListOfVariableIndices())
7676
X, Y = _compute_point(model, variables, model.f)
77+
_log_solution(model, Y)
7778
return status, SolutionPoint(X, Y)
7879
end
7980

src/algorithms/DominguezRios.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ function minimize_multiobjective!(algorithm::DominguezRios, model::Optimizer)
166166
return status, nothing
167167
end
168168
_, Y = _compute_point(model, variables, f_i)
169+
_log_solution(model, Y)
169170
yI[i] = Y
170171
model.ideal_point[i] = Y
171172
MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MAX_SENSE)
@@ -176,6 +177,7 @@ function minimize_multiobjective!(algorithm::DominguezRios, model::Optimizer)
176177
return status, nothing
177178
end
178179
_, Y = _compute_point(model, variables, f_i)
180+
_log_solution(model, Y)
179181
yN[i] = Y + 1
180182
end
181183
MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MIN_SENSE)
@@ -216,6 +218,7 @@ function minimize_multiobjective!(algorithm::DominguezRios, model::Optimizer)
216218
optimize_inner!(model)
217219
if _is_scalar_status_optimal(model)
218220
X, Y = _compute_point(model, variables, model.f)
221+
_log_solution(model, Y)
219222
obj = MOI.get(model.inner, MOI.ObjectiveValue())
220223
# We need to undo the scaling of the scalar objective. There's no
221224
# need to unscale `Y` because we have evaluated this explicitly from

src/algorithms/EpsilonConstraint.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ function minimize_multiobjective!(
127127
break
128128
end
129129
X, Y = _compute_point(model, variables, model.f)
130+
_log_solution(model, Y)
130131
if isempty(solutions) || !(Y solutions[end].y)
131132
push!(solutions, SolutionPoint(X, Y))
132133
end

src/algorithms/Hierarchical.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function minimize_multiobjective!(algorithm::Hierarchical, model::Optimizer)
114114
end
115115
# Add tolerance constraints
116116
X, Y = _compute_point(model, variables, new_vector_f)
117+
_log_solution(model, Y)
117118
for (i, fi) in enumerate(MOI.Utilities.eachscalar(new_vector_f))
118119
rtol = MOI.get(algorithm, ObjectiveRelativeTolerance(i))
119120
set = MOI.LessThan(Y[i] + rtol * abs(Y[i]))
@@ -122,6 +123,7 @@ function minimize_multiobjective!(algorithm::Hierarchical, model::Optimizer)
122123
end
123124
end
124125
X, Y = _compute_point(model, variables, model.f)
126+
_log_solution(model, Y)
125127
# Remove tolerance constraints
126128
for c in constraints
127129
MOI.delete(model, c)

src/algorithms/KirlikSayin.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ function minimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
9696
# This tolerance is really important!
9797
δ = 1.0
9898
scalars = MOI.Utilities.scalarize(model.f)
99+
printing = Vector{Union{Nothing,Float64}}(undef, n)
100+
fill!(printing, nothing)
99101
# Ideal and Nadir point estimation
100102
for (i, f_i) in enumerate(scalars)
101103
# Ideal point
@@ -106,6 +108,8 @@ function minimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
106108
return status, nothing
107109
end
108110
_, Y = _compute_point(model, variables, f_i)
111+
printing[i] = Y
112+
_log_solution(model, printing)
109113
model.ideal_point[i] = yI[i] = Y
110114
# Nadir point
111115
MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MAX_SENSE)
@@ -118,6 +122,9 @@ function minimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
118122
return status, nothing
119123
end
120124
_, Y = _compute_point(model, variables, f_i)
125+
printing[i] = Y
126+
_log_solution(model, printing)
127+
printing[i] = nothing
121128
yN[i] = Y + δ
122129
MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MIN_SENSE)
123130
end
@@ -180,6 +187,7 @@ function minimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
180187
continue
181188
end
182189
X, Y = _compute_point(model, variables, model.f)
190+
_log_solution(model, Y)
183191
Y_proj = _project(Y, k)
184192
if !(Y in YN)
185193
push!(solutions, SolutionPoint(X, Y))

src/algorithms/Lexicographic.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,14 @@ function _solve_in_sequence(
139139
primal_status = MOI.get(model.inner, MOI.PrimalStatus())
140140
if _is_scalar_status_feasible_point(primal_status)
141141
X, Y = _compute_point(model, variables, model.f)
142+
_log_solution(model, Y)
142143
solution = [SolutionPoint(X, Y)]
143144
end
144145
if !_is_scalar_status_optimal(status)
145146
break
146147
end
147148
X, Y = _compute_point(model, variables, f)
149+
_log_solution(model, Y)
148150
rtol = MOI.get(algorithm, ObjectiveRelativeTolerance(i))
149151
set = if MOI.get(model.inner, MOI.ObjectiveSense()) == MOI.MIN_SENSE
150152
MOI.LessThan(Y + rtol * abs(Y))

src/algorithms/RandomWeighting.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function optimize_multiobjective!(algorithm::RandomWeighting, model::Optimizer)
5454
status = MOI.get(model.inner, MOI.TerminationStatus())
5555
if _is_scalar_status_optimal(status)
5656
X, Y = _compute_point(model, variables, model.f)
57+
_log_solution(model, Y)
5758
push!(solutions, SolutionPoint(X, Y))
5859
else
5960
return status, nothing
@@ -75,6 +76,7 @@ function optimize_multiobjective!(algorithm::RandomWeighting, model::Optimizer)
7576
status = MOI.get(model.inner, MOI.TerminationStatus())
7677
if _is_scalar_status_optimal(status)
7778
X, Y = _compute_point(model, variables, model.f)
79+
_log_solution(model, Y)
7880
push!(solutions, SolutionPoint(X, Y))
7981
end
8082
end

0 commit comments

Comments
 (0)