diff --git a/src/algorithms/Chalmet.jl b/src/algorithms/Chalmet.jl index 145f322..0b3fd79 100644 --- a/src/algorithms/Chalmet.jl +++ b/src/algorithms/Chalmet.jl @@ -27,12 +27,10 @@ function _solve_constrained_model( f = MOI.Utilities.scalarize(model.f) g = sum(1.0 * fi for fi in f) MOI.set(model.inner, MOI.ObjectiveFunction{typeof(g)}(), g) - constraints = [ - MOI.add_constraint(model.inner, f[1], MOI.LessThan(rhs[1] - 1)) - MOI.add_constraint(model.inner, f[2], MOI.LessThan(rhs[2] - 1)) - ] + sets = MOI.LessThan.(rhs .- 1) + c = MOI.Utilities.normalize_and_add_constraint.(model.inner, f, sets) MOI.optimize!(model.inner) - MOI.delete.(model, constraints) + MOI.delete.(model, c) status = MOI.get(model.inner, MOI.TerminationStatus()) if !_is_scalar_status_optimal(status) return status, nothing @@ -74,7 +72,11 @@ function optimize_multiobjective!(algorithm::Chalmet, model::Optimizer) end _, y1[2] = _compute_point(model, variables, f2) MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f1)}(), f1) - y1_constraint = MOI.add_constraint(model.inner, f2, MOI.LessThan(y1[2])) + y1_constraint = MOI.Utilities.normalize_and_add_constraint( + model.inner, + f2, + MOI.LessThan(y1[2]), + ) MOI.optimize!(model.inner) x1, y1[1] = _compute_point(model, variables, f1) MOI.delete(model.inner, y1_constraint) @@ -90,7 +92,11 @@ function optimize_multiobjective!(algorithm::Chalmet, model::Optimizer) return MOI.OPTIMAL, [solutions] end MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f2)}(), f2) - y2_constraint = MOI.add_constraint(model.inner, f1, MOI.LessThan(y2[1])) + y2_constraint = MOI.Utilities.normalize_and_add_constraint( + model.inner, + f1, + MOI.LessThan(y2[1]), + ) MOI.optimize!(model.inner) x2, y2[2] = _compute_point(model, variables, f2) MOI.delete(model.inner, y2_constraint) diff --git a/src/algorithms/EpsilonConstraint.jl b/src/algorithms/EpsilonConstraint.jl index 6f219a6..5f8c1ac 100644 --- a/src/algorithms/EpsilonConstraint.jl +++ b/src/algorithms/EpsilonConstraint.jl @@ -104,7 +104,14 @@ function optimize_multiobjective!( else MOI.GreaterThan{Float64}, left end - ci = MOI.add_constraint(model, f1, SetType(bound)) + constant = MOI.constant(f1, Float64) + ci = MOI.Utilities.normalize_and_add_constraint( + model, + f1, + SetType(bound); + allow_modify_function = true, + ) + bound -= constant status = MOI.OPTIMAL for _ in 1:n_points if _time_limit_exceeded(model, start_time) @@ -121,9 +128,9 @@ function optimize_multiobjective!( push!(solutions, SolutionPoint(X, Y)) end if sense == MOI.MIN_SENSE - bound = min(Y[1] - ε, bound - ε) + bound = min(Y[1] - constant - ε, bound - ε) else - bound = max(Y[1] + ε, bound + ε) + bound = max(Y[1] - constant + ε, bound + ε) end end MOI.delete(model, ci) diff --git a/src/algorithms/Hierarchical.jl b/src/algorithms/Hierarchical.jl index c4ea5cb..cd0e882 100644 --- a/src/algorithms/Hierarchical.jl +++ b/src/algorithms/Hierarchical.jl @@ -117,7 +117,8 @@ function optimize_multiobjective!(algorithm::Hierarchical, model::Optimizer) else MOI.GreaterThan(Y[i] - rtol * abs(Y[i])) end - push!(constraints, MOI.add_constraint(model, fi, set)) + ci = MOI.Utilities.normalize_and_add_constraint(model, fi, set) + push!(constraints, ci) end end X, Y = _compute_point(model, variables, model.f) diff --git a/src/algorithms/KirlikSayin.jl b/src/algorithms/KirlikSayin.jl index 5ebd34b..eed6943 100644 --- a/src/algorithms/KirlikSayin.jl +++ b/src/algorithms/KirlikSayin.jl @@ -152,7 +152,11 @@ function optimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer) ) for (i, f_i) in enumerate(scalars) if i != k - ci = MOI.add_constraint(model.inner, f_i, SetType(ε[i] + δ)) + ci = MOI.Utilities.normalize_and_add_constraint( + model.inner, + f_i, + SetType(ε[i] + δ), + ) push!(ε_constraints, ci) end end @@ -168,8 +172,11 @@ function optimize_multiobjective!(algorithm::KirlikSayin, model::Optimizer) sum_f = sum(1.0 * s for s in scalars) MOI.set(model.inner, MOI.ObjectiveFunction{typeof(sum_f)}(), sum_f) # Constraint to eliminate weak dominance - zₖ_constraint = - MOI.add_constraint(model.inner, scalars[k], MOI.EqualTo(zₖ)) + zₖ_constraint = MOI.Utilities.normalize_and_add_constraint( + model.inner, + scalars[k], + MOI.EqualTo(zₖ), + ) MOI.optimize!(model.inner) MOI.delete.(model, ε_constraints) MOI.delete(model, zₖ_constraint) diff --git a/src/algorithms/Lexicographic.jl b/src/algorithms/Lexicographic.jl index 1d86ad3..aef20c8 100644 --- a/src/algorithms/Lexicographic.jl +++ b/src/algorithms/Lexicographic.jl @@ -121,7 +121,8 @@ function _solve_in_sequence( else MOI.GreaterThan(Y - rtol * abs(Y)) end - push!(constraints, MOI.add_constraint(model, f, set)) + ci = MOI.Utilities.normalize_and_add_constraint(model, f, set) + push!(constraints, ci) end for c in constraints MOI.delete(model, c) diff --git a/src/algorithms/TambyVanderpooten.jl b/src/algorithms/TambyVanderpooten.jl index 41f1f96..50af408 100644 --- a/src/algorithms/TambyVanderpooten.jl +++ b/src/algorithms/TambyVanderpooten.jl @@ -143,7 +143,7 @@ function optimize_multiobjective!( ε_constraints = Any[] for (i, f_i) in enumerate(scalars) if i != k - ci = MOI.add_constraint( + ci = MOI.Utilities.normalize_and_add_constraint( model.inner, f_i, MOI.LessThan{Float64}(u[i] - 1), @@ -171,8 +171,11 @@ function optimize_multiobjective!( y_k = MOI.get(model.inner, MOI.ObjectiveValue()) sum_f = sum(1.0 * s for s in scalars) MOI.set(model.inner, MOI.ObjectiveFunction{typeof(sum_f)}(), sum_f) - y_k_constraint = - MOI.add_constraint(model.inner, scalars[k], MOI.EqualTo(y_k)) + y_k_constraint = MOI.Utilities.normalize_and_add_constraint( + model.inner, + scalars[k], + MOI.EqualTo(y_k), + ) MOI.optimize!(model.inner) if !_is_scalar_status_optimal(model) return status, nothing diff --git a/test/algorithms/Chalmet.jl b/test/algorithms/Chalmet.jl index 79043ff..9adfde3 100644 --- a/test/algorithms/Chalmet.jl +++ b/test/algorithms/Chalmet.jl @@ -98,7 +98,7 @@ function test_knapsack_max() MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(C[i, j], x[j])) for i in 1:2 for j in 1:n ], - [0.0, 0.0], + [1.0, 0.0], ) MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) @@ -109,9 +109,9 @@ function test_knapsack_max() 0 1 1 1 1 0 1 0 1 1 ] Y_N = Float64[ - 2854 4636 - 3394 3817 - 3042 4627 + 2855 4636 + 3395 3817 + 3043 4627 ] N = MOI.get(model, MOI.ResultCount()) x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...) diff --git a/test/algorithms/Dichotomy.jl b/test/algorithms/Dichotomy.jl index d027365..3af9f0a 100644 --- a/test/algorithms/Dichotomy.jl +++ b/test/algorithms/Dichotomy.jl @@ -47,7 +47,7 @@ function test_moi_bolp_1() model, """ variables: x, y -minobjective: [2 * x + y, x + 3 * y] +minobjective: [2 * x + y + 1, x + 3 * y] c1: x + y >= 1.0 c2: 0.5 * x + y >= 0.75 c3: x >= 0.0 @@ -60,7 +60,7 @@ c4: y >= 0.25 @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL @test MOI.get(model, MOI.ResultCount()) == 3 X = [[0.0, 1.0], [0.5, 0.5], [1.0, 0.25]] - Y = [[1.0, 3.0], [1.5, 2.0], [2.25, 1.75]] + Y = [[2.0, 3.0], [2.5, 2.0], [3.25, 1.75]] for i in 1:3 @test MOI.get(model, MOI.PrimalStatus(i)) == MOI.FEASIBLE_POINT @test MOI.get(model, MOI.DualStatus(i)) == MOI.NO_SOLUTION @@ -68,7 +68,7 @@ c4: y >= 0.25 @test MOI.get(model, MOI.VariablePrimal(i), x) == X[i][1] @test MOI.get(model, MOI.VariablePrimal(i), y) == X[i][2] end - @test MOI.get(model, MOI.ObjectiveBound()) == [1.0, 1.75] + @test MOI.get(model, MOI.ObjectiveBound()) == [2.0, 1.75] return end @@ -83,7 +83,7 @@ function test_moi_bolp_1_maximize() model, """ variables: x, y -maxobjective: [-2.0 * x + -1.0 * y, -1.0 * x + -3.0 * y] +maxobjective: [-2.0 * x + -1.0 * y, -1.0 * x + -3.0 * y + 0.5] c1: x + y >= 1.0 c2: 0.5 * x + y >= 0.75 c3: x >= 0.0 @@ -96,7 +96,7 @@ c4: y >= 0.25 @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL @test MOI.get(model, MOI.ResultCount()) == 3 X = [[0.0, 1.0], [0.5, 0.5], [1.0, 0.25]] - Y = [-[1.0, 3.0], -[1.5, 2.0], -[2.25, 1.75]] + Y = [-[1.0, 2.5], -[1.5, 1.5], -[2.25, 1.25]] for i in 1:3 @test MOI.get(model, MOI.PrimalStatus(i)) == MOI.FEASIBLE_POINT @test MOI.get(model, MOI.DualStatus(i)) == MOI.NO_SOLUTION @@ -104,7 +104,7 @@ c4: y >= 0.25 @test MOI.get(model, MOI.VariablePrimal(i), x) == X[i][1] @test MOI.get(model, MOI.VariablePrimal(i), y) == X[i][2] end - @test MOI.get(model, MOI.ObjectiveBound()) == -[1.0, 1.75] + @test MOI.get(model, MOI.ObjectiveBound()) == -[1.0, 1.25] return end diff --git a/test/algorithms/DominguezRios.jl b/test/algorithms/DominguezRios.jl index b70e216..e8e550d 100644 --- a/test/algorithms/DominguezRios.jl +++ b/test/algorithms/DominguezRios.jl @@ -54,7 +54,7 @@ function test_knapsack_min_p3() MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j])) for i in 1:p for j in 1:n ], - fill(0.0, p), + ones(p), ) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) @@ -77,6 +77,7 @@ function test_knapsack_min_p3() -2997 -3539 -3509 -2518 -3866 -3191 ] + Y_N .+= 1 N = MOI.get(model, MOI.ResultCount()) x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...) @test isapprox(sort(x_sol; dims = 1), sort(X_E'; dims = 1); atol = 1e-6) diff --git a/test/algorithms/EpsilonConstraint.jl b/test/algorithms/EpsilonConstraint.jl index 088ee6e..783cfd6 100644 --- a/test/algorithms/EpsilonConstraint.jl +++ b/test/algorithms/EpsilonConstraint.jl @@ -40,6 +40,7 @@ function test_biobjective_knapsack() Float64, [sum(1.0 * p[i] * x[i] for i in 1:length(w)) for p in [p1, p2]]..., ) + f.constants[1] = 1.0 MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) MOI.add_constraint( model, @@ -48,15 +49,15 @@ function test_biobjective_knapsack() ) MOI.optimize!(model) results = Dict( - [955, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17], - [949, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17], - [948, 939] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17], - [943, 940] => [2, 3, 5, 6, 8, 9, 10, 11, 15, 16, 17], - [936, 942] => [1, 2, 3, 5, 6, 10, 11, 12, 15, 16, 17], - [935, 947] => [2, 5, 6, 8, 9, 10, 11, 12, 15, 16, 17], - [934, 971] => [2, 3, 5, 6, 8, 10, 11, 12, 15, 16, 17], - [927, 972] => [2, 3, 5, 6, 8, 9, 10, 11, 12, 16, 17], - [918, 983] => [2, 3, 4, 5, 6, 8, 10, 11, 12, 16, 17], + [956, 906] => [2, 3, 5, 6, 9, 10, 11, 14, 15, 16, 17], + [950, 915] => [1, 2, 5, 6, 8, 9, 10, 11, 15, 16, 17], + [949, 939] => [1, 2, 3, 5, 6, 8, 10, 11, 15, 16, 17], + [944, 940] => [2, 3, 5, 6, 8, 9, 10, 11, 15, 16, 17], + [937, 942] => [1, 2, 3, 5, 6, 10, 11, 12, 15, 16, 17], + [936, 947] => [2, 5, 6, 8, 9, 10, 11, 12, 15, 16, 17], + [935, 971] => [2, 3, 5, 6, 8, 10, 11, 12, 15, 16, 17], + [928, 972] => [2, 3, 5, 6, 8, 9, 10, 11, 12, 16, 17], + [919, 983] => [2, 3, 4, 5, 6, 8, 10, 11, 12, 16, 17], ) @test MOI.get(model, MOI.ResultCount()) == 9 for i in 1:MOI.get(model, MOI.ResultCount()) diff --git a/test/algorithms/Hierarchical.jl b/test/algorithms/Hierarchical.jl index bd5840d..0f2db86 100644 --- a/test/algorithms/Hierarchical.jl +++ b/test/algorithms/Hierarchical.jl @@ -46,11 +46,15 @@ function test_knapsack() MOI.add_constraint.(model, x, MOI.LessThan(1.0)) MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) f = MOI.Utilities.operate(vcat, Float64, P * x...) + f.constants[4] = 1_000.0 MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) MOI.add_constraint(model, sum(1.0 * x[i] for i in 1:4), MOI.LessThan(2.0)) MOI.optimize!(model) + @test MOI.get(model, MOI.ResultCount()) == 1 x_sol = MOI.get(model, MOI.VariablePrimal(), x) @test ≈(x_sol, [0.9, 0, 0.9, 0.2]; atol = 1e-3) + y_sol = MOI.get(model, MOI.ObjectiveValue()) + @test ≈(y_sol, P * x_sol .+ [0.0, 0.0, 0.0, 1_000.0]; atol = 1e-4) return end diff --git a/test/algorithms/KirlikSayin.jl b/test/algorithms/KirlikSayin.jl index 61f51ae..8a45fe0 100644 --- a/test/algorithms/KirlikSayin.jl +++ b/test/algorithms/KirlikSayin.jl @@ -51,7 +51,7 @@ function test_knapsack_min_p3() MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j])) for i in 1:p for j in 1:n ], - fill(0.0, p), + ones(p), ) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) @@ -74,6 +74,7 @@ function test_knapsack_min_p3() -2518 -3866 -3191 -2854 -4636 -3076 ] + Y_N .+= 1 N = MOI.get(model, MOI.ResultCount()) x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...) @test isapprox(sort(x_sol; dims = 1), sort(X_E'; dims = 1); atol = 1e-6) diff --git a/test/algorithms/Lexicographic.jl b/test/algorithms/Lexicographic.jl index c14b9ee..efa444a 100644 --- a/test/algorithms/Lexicographic.jl +++ b/test/algorithms/Lexicographic.jl @@ -36,11 +36,15 @@ function test_knapsack() MOI.add_constraint.(model, x, MOI.LessThan(1.0)) MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) f = MOI.Utilities.operate(vcat, Float64, P * x...) + f.constants[4] = 1_000.0 MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) MOI.add_constraint(model, sum(1.0 * x[i] for i in 1:4), MOI.LessThan(2.0)) MOI.optimize!(model) + @test MOI.get(model, MOI.ResultCount()) == 1 x_sol = MOI.get(model, MOI.VariablePrimal(), x) @test ≈(x_sol, [0.9, 1, 0, 0.1]; atol = 1e-3) + y_sol = MOI.get(model, MOI.ObjectiveValue()) + @test ≈(y_sol, P * x_sol .+ [0.0, 0.0, 0.0, 1_000.0]; atol = 1e-4) return end diff --git a/test/algorithms/TambyVanderpooten.jl b/test/algorithms/TambyVanderpooten.jl index e4b9fdf..6b3196b 100644 --- a/test/algorithms/TambyVanderpooten.jl +++ b/test/algorithms/TambyVanderpooten.jl @@ -51,7 +51,7 @@ function test_knapsack_min_p3() MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(-C[i, j], x[j])) for i in 1:p for j in 1:n ], - fill(0.0, p), + ones(p), ) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) @@ -74,6 +74,7 @@ function test_knapsack_min_p3() -2518 -3866 -3191 -2854 -4636 -3076 ] + Y_N .+= 1 N = MOI.get(model, MOI.ResultCount()) x_sol = hcat([MOI.get(model, MOI.VariablePrimal(i), x) for i in 1:N]...)' y_sol = hcat([MOI.get(model, MOI.ObjectiveValue(i)) for i in 1:N]...)'