Skip to content

Commit cab13bf

Browse files
authored
Fix and add tests for constant offset in objective function (#76)
1 parent bc0239d commit cab13bf

14 files changed

+77
-40
lines changed

src/algorithms/Chalmet.jl

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@ function _solve_constrained_model(
2727
f = MOI.Utilities.scalarize(model.f)
2828
g = sum(1.0 * fi for fi in f)
2929
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(g)}(), g)
30-
constraints = [
31-
MOI.add_constraint(model.inner, f[1], MOI.LessThan(rhs[1] - 1))
32-
MOI.add_constraint(model.inner, f[2], MOI.LessThan(rhs[2] - 1))
33-
]
30+
sets = MOI.LessThan.(rhs .- 1)
31+
c = MOI.Utilities.normalize_and_add_constraint.(model.inner, f, sets)
3432
MOI.optimize!(model.inner)
35-
MOI.delete.(model, constraints)
33+
MOI.delete.(model, c)
3634
status = MOI.get(model.inner, MOI.TerminationStatus())
3735
if !_is_scalar_status_optimal(status)
3836
return status, nothing
@@ -74,7 +72,11 @@ function optimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
7472
end
7573
_, y1[2] = _compute_point(model, variables, f2)
7674
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f1)}(), f1)
77-
y1_constraint = MOI.add_constraint(model.inner, f2, MOI.LessThan(y1[2]))
75+
y1_constraint = MOI.Utilities.normalize_and_add_constraint(
76+
model.inner,
77+
f2,
78+
MOI.LessThan(y1[2]),
79+
)
7880
MOI.optimize!(model.inner)
7981
x1, y1[1] = _compute_point(model, variables, f1)
8082
MOI.delete(model.inner, y1_constraint)
@@ -90,7 +92,11 @@ function optimize_multiobjective!(algorithm::Chalmet, model::Optimizer)
9092
return MOI.OPTIMAL, [solutions]
9193
end
9294
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f2)}(), f2)
93-
y2_constraint = MOI.add_constraint(model.inner, f1, MOI.LessThan(y2[1]))
95+
y2_constraint = MOI.Utilities.normalize_and_add_constraint(
96+
model.inner,
97+
f1,
98+
MOI.LessThan(y2[1]),
99+
)
94100
MOI.optimize!(model.inner)
95101
x2, y2[2] = _compute_point(model, variables, f2)
96102
MOI.delete(model.inner, y2_constraint)

src/algorithms/EpsilonConstraint.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ function optimize_multiobjective!(
104104
else
105105
MOI.GreaterThan{Float64}, left
106106
end
107-
ci = MOI.add_constraint(model, f1, SetType(bound))
107+
constant = MOI.constant(f1, Float64)
108+
ci = MOI.Utilities.normalize_and_add_constraint(
109+
model,
110+
f1,
111+
SetType(bound);
112+
allow_modify_function = true,
113+
)
114+
bound -= constant
108115
status = MOI.OPTIMAL
109116
for _ in 1:n_points
110117
if _time_limit_exceeded(model, start_time)
@@ -121,9 +128,9 @@ function optimize_multiobjective!(
121128
push!(solutions, SolutionPoint(X, Y))
122129
end
123130
if sense == MOI.MIN_SENSE
124-
bound = min(Y[1] - ε, bound - ε)
131+
bound = min(Y[1] - constant - ε, bound - ε)
125132
else
126-
bound = max(Y[1] + ε, bound + ε)
133+
bound = max(Y[1] - constant + ε, bound + ε)
127134
end
128135
end
129136
MOI.delete(model, ci)

src/algorithms/Hierarchical.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ function optimize_multiobjective!(algorithm::Hierarchical, model::Optimizer)
117117
else
118118
MOI.GreaterThan(Y[i] - rtol * abs(Y[i]))
119119
end
120-
push!(constraints, MOI.add_constraint(model, fi, set))
120+
ci = MOI.Utilities.normalize_and_add_constraint(model, fi, set)
121+
push!(constraints, ci)
121122
end
122123
end
123124
X, Y = _compute_point(model, variables, model.f)

src/algorithms/KirlikSayin.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ function optimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
152152
)
153153
for (i, f_i) in enumerate(scalars)
154154
if i != k
155-
ci = MOI.add_constraint(model.inner, f_i, SetType(ε[i] + δ))
155+
ci = MOI.Utilities.normalize_and_add_constraint(
156+
model.inner,
157+
f_i,
158+
SetType(ε[i] + δ),
159+
)
156160
push!(ε_constraints, ci)
157161
end
158162
end
@@ -168,8 +172,11 @@ function optimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer)
168172
sum_f = sum(1.0 * s for s in scalars)
169173
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(sum_f)}(), sum_f)
170174
# Constraint to eliminate weak dominance
171-
zₖ_constraint =
172-
MOI.add_constraint(model.inner, scalars[k], MOI.EqualTo(zₖ))
175+
zₖ_constraint = MOI.Utilities.normalize_and_add_constraint(
176+
model.inner,
177+
scalars[k],
178+
MOI.EqualTo(zₖ),
179+
)
173180
MOI.optimize!(model.inner)
174181
MOI.delete.(model, ε_constraints)
175182
MOI.delete(model, zₖ_constraint)

src/algorithms/Lexicographic.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ function _solve_in_sequence(
121121
else
122122
MOI.GreaterThan(Y - rtol * abs(Y))
123123
end
124-
push!(constraints, MOI.add_constraint(model, f, set))
124+
ci = MOI.Utilities.normalize_and_add_constraint(model, f, set)
125+
push!(constraints, ci)
125126
end
126127
for c in constraints
127128
MOI.delete(model, c)

src/algorithms/TambyVanderpooten.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function optimize_multiobjective!(
143143
ε_constraints = Any[]
144144
for (i, f_i) in enumerate(scalars)
145145
if i != k
146-
ci = MOI.add_constraint(
146+
ci = MOI.Utilities.normalize_and_add_constraint(
147147
model.inner,
148148
f_i,
149149
MOI.LessThan{Float64}(u[i] - 1),
@@ -171,8 +171,11 @@ function optimize_multiobjective!(
171171
y_k = MOI.get(model.inner, MOI.ObjectiveValue())
172172
sum_f = sum(1.0 * s for s in scalars)
173173
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(sum_f)}(), sum_f)
174-
y_k_constraint =
175-
MOI.add_constraint(model.inner, scalars[k], MOI.EqualTo(y_k))
174+
y_k_constraint = MOI.Utilities.normalize_and_add_constraint(
175+
model.inner,
176+
scalars[k],
177+
MOI.EqualTo(y_k),
178+
)
176179
MOI.optimize!(model.inner)
177180
if !_is_scalar_status_optimal(model)
178181
return status, nothing

test/algorithms/Chalmet.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ function test_knapsack_max()
9898
MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(C[i, j], x[j])) for
9999
i in 1:2 for j in 1:n
100100
],
101-
[0.0, 0.0],
101+
[1.0, 0.0],
102102
)
103103
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
104104
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
@@ -109,9 +109,9 @@ function test_knapsack_max()
109109
0 1 1 1 1 0 1 0 1 1
110110
]
111111
Y_N = Float64[
112-
2854 4636
113-
3394 3817
114-
3042 4627
112+
2855 4636
113+
3395 3817
114+
3043 4627
115115
]
116116
N = MOI.get(model, MOI.ResultCount())
117117
x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...)

test/algorithms/Dichotomy.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function test_moi_bolp_1()
4747
model,
4848
"""
4949
variables: x, y
50-
minobjective: [2 * x + y, x + 3 * y]
50+
minobjective: [2 * x + y + 1, x + 3 * y]
5151
c1: x + y >= 1.0
5252
c2: 0.5 * x + y >= 0.75
5353
c3: x >= 0.0
@@ -60,15 +60,15 @@ c4: y >= 0.25
6060
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL
6161
@test MOI.get(model, MOI.ResultCount()) == 3
6262
X = [[0.0, 1.0], [0.5, 0.5], [1.0, 0.25]]
63-
Y = [[1.0, 3.0], [1.5, 2.0], [2.25, 1.75]]
63+
Y = [[2.0, 3.0], [2.5, 2.0], [3.25, 1.75]]
6464
for i in 1:3
6565
@test MOI.get(model, MOI.PrimalStatus(i)) == MOI.FEASIBLE_POINT
6666
@test MOI.get(model, MOI.DualStatus(i)) == MOI.NO_SOLUTION
6767
@test MOI.get(model, MOI.ObjectiveValue(i)) == Y[i]
6868
@test MOI.get(model, MOI.VariablePrimal(i), x) == X[i][1]
6969
@test MOI.get(model, MOI.VariablePrimal(i), y) == X[i][2]
7070
end
71-
@test MOI.get(model, MOI.ObjectiveBound()) == [1.0, 1.75]
71+
@test MOI.get(model, MOI.ObjectiveBound()) == [2.0, 1.75]
7272
return
7373
end
7474

@@ -83,7 +83,7 @@ function test_moi_bolp_1_maximize()
8383
model,
8484
"""
8585
variables: x, y
86-
maxobjective: [-2.0 * x + -1.0 * y, -1.0 * x + -3.0 * y]
86+
maxobjective: [-2.0 * x + -1.0 * y, -1.0 * x + -3.0 * y + 0.5]
8787
c1: x + y >= 1.0
8888
c2: 0.5 * x + y >= 0.75
8989
c3: x >= 0.0
@@ -96,15 +96,15 @@ c4: y >= 0.25
9696
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL
9797
@test MOI.get(model, MOI.ResultCount()) == 3
9898
X = [[0.0, 1.0], [0.5, 0.5], [1.0, 0.25]]
99-
Y = [-[1.0, 3.0], -[1.5, 2.0], -[2.25, 1.75]]
99+
Y = [-[1.0, 2.5], -[1.5, 1.5], -[2.25, 1.25]]
100100
for i in 1:3
101101
@test MOI.get(model, MOI.PrimalStatus(i)) == MOI.FEASIBLE_POINT
102102
@test MOI.get(model, MOI.DualStatus(i)) == MOI.NO_SOLUTION
103103
@test MOI.get(model, MOI.ObjectiveValue(i)) == Y[i]
104104
@test MOI.get(model, MOI.VariablePrimal(i), x) == X[i][1]
105105
@test MOI.get(model, MOI.VariablePrimal(i), y) == X[i][2]
106106
end
107-
@test MOI.get(model, MOI.ObjectiveBound()) == -[1.0, 1.75]
107+
@test MOI.get(model, MOI.ObjectiveBound()) == -[1.0, 1.25]
108108
return
109109
end
110110

test/algorithms/DominguezRios.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function test_knapsack_min_p3()
5454
MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j]))
5555
for i in 1:p for j in 1:n
5656
],
57-
fill(0.0, p),
57+
ones(p),
5858
)
5959
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
6060
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
@@ -77,6 +77,7 @@ function test_knapsack_min_p3()
7777
-2997 -3539 -3509
7878
-2518 -3866 -3191
7979
]
80+
Y_N .+= 1
8081
N = MOI.get(model, MOI.ResultCount())
8182
x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...)
8283
@test isapprox(sort(x_sol; dims = 1), sort(X_E'; dims = 1); atol = 1e-6)

test/algorithms/EpsilonConstraint.jl

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function test_biobjective_knapsack()
4040
Float64,
4141
[sum(1.0 * p[i] * x[i] for i in 1:length(w)) for p in [p1, p2]]...,
4242
)
43+
f.constants[1] = 1.0
4344
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
4445
MOI.add_constraint(
4546
model,
@@ -48,15 +49,15 @@ function test_biobjective_knapsack()
4849
)
4950
MOI.optimize!(model)
5051
results = Dict(
51-
[955, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
52-
[949, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17],
53-
[948, 939] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17],
54-
[943, 940] => [2, 3, 5, 6, 8, 9, 10, 11, 15, 16, 17],
55-
[936, 942] => [1, 2, 3, 5, 6, 10, 11, 12, 15, 16, 17],
56-
[935, 947] => [2, 5, 6, 8, 9, 10, 11, 12, 15, 16, 17],
57-
[934, 971] => [2, 3, 5, 6, 8, 10, 11, 12, 15, 16, 17],
58-
[927, 972] => [2, 3, 5, 6, 8, 9, 10, 11, 12, 16, 17],
59-
[918, 983] => [2, 3, 4, 5, 6, 8, 10, 11, 12, 16, 17],
52+
[956, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17],
53+
[950, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17],
54+
[949, 939] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17],
55+
[944, 940] => [2, 3, 5, 6, 8, 9, 10, 11, 15, 16, 17],
56+
[937, 942] => [1, 2, 3, 5, 6, 10, 11, 12, 15, 16, 17],
57+
[936, 947] => [2, 5, 6, 8, 9, 10, 11, 12, 15, 16, 17],
58+
[935, 971] => [2, 3, 5, 6, 8, 10, 11, 12, 15, 16, 17],
59+
[928, 972] => [2, 3, 5, 6, 8, 9, 10, 11, 12, 16, 17],
60+
[919, 983] => [2, 3, 4, 5, 6, 8, 10, 11, 12, 16, 17],
6061
)
6162
@test MOI.get(model, MOI.ResultCount()) == 9
6263
for i in 1:MOI.get(model, MOI.ResultCount())

test/algorithms/Hierarchical.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,15 @@ function test_knapsack()
4646
MOI.add_constraint.(model, x, MOI.LessThan(1.0))
4747
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
4848
f = MOI.Utilities.operate(vcat, Float64, P * x...)
49+
f.constants[4] = 1_000.0
4950
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
5051
MOI.add_constraint(model, sum(1.0 * x[i] for i in 1:4), MOI.LessThan(2.0))
5152
MOI.optimize!(model)
53+
@test MOI.get(model, MOI.ResultCount()) == 1
5254
x_sol = MOI.get(model, MOI.VariablePrimal(), x)
5355
@test (x_sol, [0.9, 0, 0.9, 0.2]; atol = 1e-3)
56+
y_sol = MOI.get(model, MOI.ObjectiveValue())
57+
@test (y_sol, P * x_sol .+ [0.0, 0.0, 0.0, 1_000.0]; atol = 1e-4)
5458
return
5559
end
5660

test/algorithms/KirlikSayin.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function test_knapsack_min_p3()
5151
MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j]))
5252
for i in 1:p for j in 1:n
5353
],
54-
fill(0.0, p),
54+
ones(p),
5555
)
5656
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
5757
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
@@ -74,6 +74,7 @@ function test_knapsack_min_p3()
7474
-2518 -3866 -3191
7575
-2854 -4636 -3076
7676
]
77+
Y_N .+= 1
7778
N = MOI.get(model, MOI.ResultCount())
7879
x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...)
7980
@test isapprox(sort(x_sol; dims = 1), sort(X_E'; dims = 1); atol = 1e-6)

test/algorithms/Lexicographic.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,15 @@ function test_knapsack()
3636
MOI.add_constraint.(model, x, MOI.LessThan(1.0))
3737
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
3838
f = MOI.Utilities.operate(vcat, Float64, P * x...)
39+
f.constants[4] = 1_000.0
3940
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
4041
MOI.add_constraint(model, sum(1.0 * x[i] for i in 1:4), MOI.LessThan(2.0))
4142
MOI.optimize!(model)
43+
@test MOI.get(model, MOI.ResultCount()) == 1
4244
x_sol = MOI.get(model, MOI.VariablePrimal(), x)
4345
@test (x_sol, [0.9, 1, 0, 0.1]; atol = 1e-3)
46+
y_sol = MOI.get(model, MOI.ObjectiveValue())
47+
@test (y_sol, P * x_sol .+ [0.0, 0.0, 0.0, 1_000.0]; atol = 1e-4)
4448
return
4549
end
4650

test/algorithms/TambyVanderpooten.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function test_knapsack_min_p3()
5151
MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j]))
5252
for i in 1:p for j in 1:n
5353
],
54-
fill(0.0, p),
54+
ones(p),
5555
)
5656
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
5757
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
@@ -74,6 +74,7 @@ function test_knapsack_min_p3()
7474
-2518 -3866 -3191
7575
-2854 -4636 -3076
7676
]
77+
Y_N .+= 1
7778
N = MOI.get(model, MOI.ResultCount())
7879
x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...)'
7980
y_sol = hcat([MOI.get(model, MOI.ObjectiveValue(i)) for i in 1:N]...)'

0 commit comments

Comments
 (0)