Skip to content

Commit 6a66108

Browse files
authored
Sort based on optimization sense (#152)
1 parent 16542fb commit 6a66108

File tree

9 files changed

+32
-11
lines changed

9 files changed

+32
-11
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ Query the number of scalar subproblems that were solved using
8989

9090
* `MOA.SubproblemCount()`
9191

92+
## Solution ordering
93+
94+
Results are lexicograhically ordered by their objective vectors. The order
95+
depends on the objective sense. The first result is best.
96+
9297
## Ideal point
9398

9499
By default, MOA will compute the ideal point, which can be queried using the

src/MultiObjectiveAlgorithms.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ function dominates(
4242
end
4343
end
4444

45-
_sort!(solutions::Vector{SolutionPoint}) = sort!(solutions; by = x -> x.y)
45+
function _sort!(solutions::Vector{SolutionPoint}, sense::MOI.OptimizationSense)
46+
return sort!(solutions; by = x -> x.y, rev = sense == MOI.MAX_SENSE)
47+
end
4648

4749
function filter_nondominated(
4850
sense,
4951
solutions::Vector{SolutionPoint};
5052
atol::Float64 = 1e-6,
5153
)
52-
_sort!(solutions)
5354
nondominated_solutions = SolutionPoint[]
5455
for candidate in solutions
5556
if any(test -> dominates(sense, test, candidate; atol), solutions)
@@ -60,6 +61,7 @@ function filter_nondominated(
6061
push!(nondominated_solutions, candidate)
6162
end
6263
end
64+
_sort!(nondominated_solutions, sense)
6365
return nondominated_solutions
6466
end
6567

@@ -681,7 +683,7 @@ function _optimize!(model::Optimizer)
681683
model.termination_status = status
682684
if solutions !== nothing
683685
model.solutions = solutions
684-
_sort!(model.solutions)
686+
_sort!(model.solutions, MOI.get(model, MOI.ObjectiveSense()))
685687
end
686688
if MOI.get(model, ComputeIdealPoint())
687689
_compute_ideal_point(model, start_time)

test/algorithms/Chalmet.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ function test_knapsack_max()
105105
[0, 1, 1, 1, 1, 0, 1, 0, 1, 1] => [3043, 4627],
106106
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1] => [3395, 3817],
107107
]
108+
reverse!(results)
108109
@test MOI.get(model, MOI.ResultCount()) == length(results)
109110
for (i, (x_sol, y_sol)) in enumerate(results)
110111
@test (x_sol, MOI.get(model, MOI.VariablePrimal(i), x); atol = 1e-6)

test/algorithms/Dichotomy.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ function test_moi_bolp_1_maximize()
9898
@test MOI.get(model, MOI.ResultCount()) == 3
9999
X = [[1.0, 0.25], [0.5, 0.5], [0.0, 1.0]]
100100
Y = [[-2.25, -1.25], [-1.5, -1.5], [-1.0, -2.5]]
101+
reverse!(X)
102+
reverse!(Y)
101103
for i in 1:3
102104
@test MOI.get(model, MOI.PrimalStatus(i)) == MOI.FEASIBLE_POINT
103105
@test MOI.get(model, MOI.DualStatus(i)) == MOI.NO_SOLUTION
@@ -227,6 +229,7 @@ function test_biobjective_knapsack()
227229
[948.0, 939.0] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17],
228230
[955.0, 906.0] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
229231
]
232+
reverse!(results)
230233
for i in 1:MOI.get(model, MOI.ResultCount())
231234
x_sol = MOI.get(model, MOI.VariablePrimal(i), x)
232235
@test results[i][2] == findall(elt -> elt > 0.9, x_sol)

test/algorithms/EpsilonConstraint.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function test_biobjective_knapsack()
6969
[950, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17],
7070
[956, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
7171
]
72+
reverse!(results)
7273
@test MOI.get(model, MOI.ResultCount()) == 9
7374
for i in 1:MOI.get(model, MOI.ResultCount())
7475
x_sol = MOI.get(model, MOI.VariablePrimal(i), x)
@@ -113,6 +114,7 @@ function test_biobjective_knapsack_atol()
113114
[949, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17],
114115
[955, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
115116
]
117+
reverse!(results)
116118
@test MOI.get(model, MOI.ResultCount()) == 9
117119
for i in 1:MOI.get(model, MOI.ResultCount())
118120
x_sol = MOI.get(model, MOI.VariablePrimal(i), x)
@@ -154,6 +156,7 @@ function test_biobjective_knapsack_atol_large()
154156
[948, 939] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17],
155157
[955, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
156158
]
159+
reverse!(results)
157160
@test MOI.get(model, MOI.ResultCount()) == 4
158161
for i in 1:MOI.get(model, MOI.ResultCount())
159162
x_sol = MOI.get(model, MOI.VariablePrimal(i), x)
@@ -238,6 +241,7 @@ function test_biobjective_knapsack_min_solution_limit()
238241
[943, 940] => [2, 3, 5, 6, 8, 9, 10, 11, 15, 16, 17],
239242
[955, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
240243
]
244+
reverse!(results)
241245
@test MOI.get(model, MOI.ResultCount()) == 3
242246
for i in 1:MOI.get(model, MOI.ResultCount())
243247
x_sol = MOI.get(model, MOI.VariablePrimal(i), x)

test/algorithms/Lexicographic.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ function test_knapsack_default()
9494
[1, 0, 1] => [1, 0, 0, 1],
9595
[1, 1, 0] => [1, 1, 0, 0],
9696
]
97+
reverse!(results)
9798
@test MOI.get(model, MOI.ResultCount()) == 3
9899
for i in 1:MOI.get(model, MOI.ResultCount())
99100
X = round.(Int, MOI.get(model, MOI.VariablePrimal(i), x))
@@ -247,6 +248,7 @@ function test_knapsack_5_objectives()
247248
[1, 0, 1, 0, 2] => [1, 0, 1, 0],
248249
[1, 1, 0, 0, 2] => [1, 1, 0, 0],
249250
]
251+
reverse!(results)
250252
for i in 1:MOI.get(model, MOI.ResultCount())
251253
X = round.(Int, MOI.get(model, MOI.VariablePrimal(i), x))
252254
Y = round.(Int, MOI.get(model, MOI.ObjectiveValue(i)))

test/algorithms/RandomWeighting.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ function test_knapsack_max()
124124
[0, 1, 1, 1, 1, 0, 1, 0, 1, 1] => [3043, 4627],
125125
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1] => [3395, 3817],
126126
]
127+
reverse!(results)
127128
@test MOI.get(model, MOI.ResultCount()) == length(results)
128129
for (i, (x_sol, y_sol)) in enumerate(results)
129130
@test (x_sol, MOI.get(model, MOI.VariablePrimal(i), x); atol = 1e-6)

test/problems.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ function test_problem_knapsack_max_p3(model)
113113
[0, 1, 1, 1, 1, 0, 1, 0, 1, 1] => [3042, 4627, 3189],
114114
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1] => [3394, 3817, 3408],
115115
]
116+
reverse!(results)
116117
N = MOI.get(model, MOI.ResultCount())
117118
@assert N == length(results)
118119
for i in 1:length(results)
@@ -223,6 +224,7 @@ function test_problem_knapsack_max_p4(model)
223224
[0, 1, 1, 0, 1, 1, 1, 1, 1, 0] => [3152, 3232, 3596, 3382],
224225
[1, 1, 1, 0, 1, 1, 1, 0, 0, 0] => [3269, 2320, 3059, 2891],
225226
]
227+
reverse!(results)
226228
@test MOI.get(model, MOI.ResultCount()) == length(results)
227229
for (i, (x_sol, y_sol)) in enumerate(results)
228230
@test (x_sol, MOI.get(model, MOI.VariablePrimal(i), x); atol = 1e-6)
@@ -368,7 +370,7 @@ function test_problem_assignment_max_p3(model)
368370
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
369371
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
370372
MOI.optimize!(model)
371-
results = reverse([
373+
results = [
372374
[0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1] => [16, 61, 47],
373375
[0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1] => [17, 43, 71],
374376
[0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1] => [18, 47, 67],
@@ -390,7 +392,7 @@ function test_problem_assignment_max_p3(model)
390392
[0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0] => [43, 51, 31],
391393
[0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0] => [45, 33, 34],
392394
[0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0] => [50, 40, 32],
393-
])
395+
]
394396
@test MOI.get(model, MOI.ResultCount()) == length(results)
395397
@test MOI.get(model, MOA.SubproblemCount()) >= length(results)
396398
for (i, (x_sol, y_sol)) in enumerate(results)

test/test_utilities.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function test_filter_nondominated()
2525
x = Dict{MOI.VariableIndex,Float64}()
2626
solutions = [MOA.SolutionPoint(x, [0, 1]), MOA.SolutionPoint(x, [1, 0])]
2727
@test MOA.filter_nondominated(MOI.MIN_SENSE, solutions) == solutions
28-
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) == solutions
28+
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) ==
29+
reverse(solutions)
2930
return
3031
end
3132

@@ -34,7 +35,7 @@ function test_filter_nondominated_sort_in_order()
3435
solutions = [MOA.SolutionPoint(x, [0, 1]), MOA.SolutionPoint(x, [1, 0])]
3536
r_solutions = reverse(solutions)
3637
@test MOA.filter_nondominated(MOI.MIN_SENSE, r_solutions) == solutions
37-
@test MOA.filter_nondominated(MOI.MAX_SENSE, r_solutions) == solutions
38+
@test MOA.filter_nondominated(MOI.MAX_SENSE, r_solutions) == r_solutions
3839
return
3940
end
4041

@@ -55,7 +56,7 @@ function test_filter_nondominated_weakly_dominated()
5556
MOA.SolutionPoint(x, [1, 0]),
5657
]
5758
@test MOA.filter_nondominated(MOI.MIN_SENSE, solutions) == solutions[[1, 3]]
58-
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) == solutions[[2, 3]]
59+
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) == solutions[[3, 2]]
5960
solutions = [
6061
MOA.SolutionPoint(x, [0, 1]),
6162
MOA.SolutionPoint(x, [0.5, 1]),
@@ -67,7 +68,7 @@ function test_filter_nondominated_weakly_dominated()
6768
@test MOA.filter_nondominated(MOI.MIN_SENSE, solutions) ==
6869
solutions[[1, 4, 6]]
6970
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) ==
70-
solutions[[3, 5, 6]]
71+
solutions[[6, 5, 3]]
7172
return
7273
end
7374

@@ -82,7 +83,7 @@ function test_filter_nondominated_knapsack()
8283
]
8384
result = solutions[[1, 3, 4]]
8485
@test MOA.filter_nondominated(MOI.MIN_SENSE, solutions) == result
85-
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) == result
86+
@test MOA.filter_nondominated(MOI.MAX_SENSE, solutions) == reverse(result)
8687
return
8788
end
8889

@@ -115,7 +116,7 @@ function test_filter_epsilon()
115116
solutions =
116117
[MOA.SolutionPoint(x, [1, 1 + 9e-5]), MOA.SolutionPoint(x, [2, 1])]
117118
new_solutions = MOA.filter_nondominated(MOI.MAX_SENSE, copy(solutions))
118-
@test new_solutions == solutions
119+
@test new_solutions == reverse(solutions)
119120
solutions =
120121
[MOA.SolutionPoint(x, [-1, -1 - 1e-6]), MOA.SolutionPoint(x, [-2, -1])]
121122
new_solutions = MOA.filter_nondominated(MOI.MIN_SENSE, copy(solutions))

0 commit comments

Comments
 (0)