Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ using JuMP
import HiGHS
import MultiObjectiveAlgorithms as MOA
model = JuMP.Model(() -> MOA.Optimizer(HiGHS.Optimizer))
set_optimizer_attribute(model, MOA.Algorithm(), MOA.NISE())
set_optimizer_attribute(model, MOA.Algorithm(), MOA.Dichotomy())
set_optimizer_attribute(model, MOA.SolutionLimit(), 4)
```

Expand All @@ -44,11 +44,11 @@ Set the algorithm using the `MOA.Algorithm()` attribute.
The value must be one of the algorithms supported by MOA:

* `MOA.EpsilonConstraint()`
* `MOA.Dichotomy()`
* `MOA.DominguezRios()`
* `MOA.Hierarchical()`
* `MOA.KirlikSayin()`
* `MOA.Lexicographic()` [default]
* `MOA.NISE()`

Consult their docstrings for details.

Expand Down
44 changes: 33 additions & 11 deletions src/algorithms/NISE.jl → src/algorithms/Dichotomy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
# v.2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at http://mozilla.org/MPL/2.0/.

"""
Dichotomy()

A solver that implements the algorithm of:

Y. P. Aneja, K. P. K. Nair, (1979) Bicriteria Transportation Problem. Management
Science 25(1), 73-78.

## Supported optimizer attributes

* `MOA.SolutionLimit()`
"""
mutable struct Dichotomy <: AbstractAlgorithm
solution_limit::Union{Nothing,Int}

Dichotomy() = new(nothing)
end

"""
NISE()

Expand All @@ -12,32 +30,36 @@ Cohon, J. L., Church, R. L., & Sheer, D. P. (1979). Generating multiobjective
trade‐offs: An algorithm for bicriterion problems. Water Resources Research,
15(5), 1001-1010.

!!! note
This algorithm is identical to `Dichotomy()`, and it may be removed in a
future release.

## Supported optimizer attributes

* `MOA.SolutionLimit()`
"""
mutable struct NISE <: AbstractAlgorithm
solution_limit::Union{Nothing,Int}

NISE() = new(nothing)
end
NISE() = Dichotomy()

MOI.supports(::NISE, ::SolutionLimit) = true
MOI.supports(::Dichotomy, ::SolutionLimit) = true

function MOI.set(alg::NISE, ::SolutionLimit, value)
function MOI.set(alg::Dichotomy, ::SolutionLimit, value)
alg.solution_limit = value
return
end

function MOI.get(alg::NISE, attr::SolutionLimit)
function MOI.get(alg::Dichotomy, attr::SolutionLimit)
return something(alg.solution_limit, default(alg, attr))
end

function _solve_weighted_sum(model::Optimizer, alg::NISE, weight::Float64)
function _solve_weighted_sum(model::Optimizer, alg::Dichotomy, weight::Float64)
return _solve_weighted_sum(model, alg, [weight, 1 - weight])
end

function _solve_weighted_sum(model::Optimizer, ::NISE, weights::Vector{Float64})
function _solve_weighted_sum(
model::Optimizer,
::Dichotomy,
weights::Vector{Float64},
)
f = _scalarise(model.f, weights)
MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f)}(), f)
MOI.optimize!(model.inner)
Expand All @@ -51,7 +73,7 @@ function _solve_weighted_sum(model::Optimizer, ::NISE, weights::Vector{Float64})
return status, SolutionPoint(X, Y)
end

function optimize_multiobjective!(algorithm::NISE, model::Optimizer)
function optimize_multiobjective!(algorithm::Dichotomy, model::Optimizer)
if MOI.output_dimension(model.f) > 2
error("Only scalar or bi-objective problems supported.")
end
Expand Down
91 changes: 80 additions & 11 deletions test/algorithms/NISE.jl → test/algorithms/Dichotomy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# v.2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at http://mozilla.org/MPL/2.0/.

module TestNISE
module TestDichotomy

using Test

Expand All @@ -23,9 +23,11 @@ function run_tests()
return
end

function test_NISE_SolutionLimit()
function test_Dichotomy_SolutionLimit()
model = MOA.Optimizer(HiGHS.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.NISE())
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
@test MOI.supports(MOA.Dichotomy(), MOA.SolutionLimit())
@test MOI.supports(model, MOA.SolutionLimit())
@test MOI.get(model, MOA.SolutionLimit()) ==
MOA.default(MOA.SolutionLimit())
MOI.set(model, MOA.SolutionLimit(), 1)
Expand All @@ -36,7 +38,7 @@ end
function test_moi_bolp_1()
f = MOI.OptimizerWithAttributes(
() -> MOA.Optimizer(HiGHS.Optimizer),
MOA.Algorithm() => MOA.NISE(),
MOA.Algorithm() => MOA.Dichotomy(),
)
model = MOI.instantiate(f)
MOI.set(model, MOI.Silent(), true)
Expand Down Expand Up @@ -72,7 +74,7 @@ end
function test_moi_bolp_1_maximize()
f = MOI.OptimizerWithAttributes(
() -> MOA.Optimizer(HiGHS.Optimizer),
MOA.Algorithm() => MOA.NISE(),
MOA.Algorithm() => MOA.Dichotomy(),
)
model = MOI.instantiate(f)
MOI.set(model, MOI.Silent(), true)
Expand Down Expand Up @@ -108,7 +110,7 @@ end
function test_moi_bolp_1_reversed()
f = MOI.OptimizerWithAttributes(
() -> MOA.Optimizer(HiGHS.Optimizer),
MOA.Algorithm() => MOA.NISE(),
MOA.Algorithm() => MOA.Dichotomy(),
)
model = MOI.instantiate(f)
MOI.set(model, MOI.Silent(), true)
Expand Down Expand Up @@ -144,7 +146,7 @@ end
function test_moi_bolp_1_scalar()
f = MOI.OptimizerWithAttributes(
() -> MOA.Optimizer(HiGHS.Optimizer),
MOA.Algorithm() => MOA.NISE(),
MOA.Algorithm() => MOA.Dichotomy(),
)
model = MOI.instantiate(f)
MOI.set(model, MOI.Silent(), true)
Expand Down Expand Up @@ -198,7 +200,7 @@ function test_biobjective_knapsack()
w = [80, 87, 68, 72, 66, 77, 99, 85, 70, 93, 98, 72, 100, 89, 67, 86, 91]
f = MOI.OptimizerWithAttributes(
() -> MOA.Optimizer(HiGHS.Optimizer),
MOA.Algorithm() => MOA.NISE(),
MOA.Algorithm() => MOA.Dichotomy(),
)
model = MOI.instantiate(f)
MOI.set(model, MOI.Silent(), true)
Expand Down Expand Up @@ -234,7 +236,7 @@ end

function test_infeasible()
model = MOA.Optimizer(HiGHS.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.NISE())
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variables(model, 2)
MOI.add_constraint.(model, x, MOI.GreaterThan(0.0))
Expand All @@ -250,7 +252,7 @@ end

function test_unbounded()
model = MOA.Optimizer(HiGHS.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.NISE())
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variables(model, 2)
MOI.add_constraint.(model, x, MOI.GreaterThan(0.0))
Expand All @@ -264,6 +266,73 @@ function test_unbounded()
return
end

function test_bicriteria_transportation_nise()
m, n = 3, 4
c = Float64[1 2 7 7; 1 9 3 4; 8 9 4 6]
d = Float64[4 4 3 4; 5 8 9 10; 6 2 5 1]
a = Float64[11, 3, 14, 16]
b = Float64[8, 19, 17]
model = MOA.Optimizer(HiGHS.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
MOI.set(model, MOI.Silent(), true)
x = [MOI.add_variable(model) for i in 1:m, j in 1:n]
MOI.add_constraint.(model, x, MOI.GreaterThan(0.0))
for j in 1:n
terms = [MOI.ScalarAffineTerm(1.0, x[i, j]) for i in 1:m]
MOI.add_constraint(
model,
MOI.ScalarAffineFunction(terms, 0.0),
MOI.EqualTo(a[j]),
)
end
for i in 1:m
terms = [MOI.ScalarAffineTerm(1.0, x[i, j]) for j in 1:n]
MOI.add_constraint(
model,
MOI.ScalarAffineFunction(terms, 0.0),
MOI.EqualTo(b[i]),
)
end
f = MOI.Utilities.vectorize([
sum(c[i, j] * x[i, j] for i in 1:m, j in 1:n),
sum(d[i, j] * x[i, j] for i in 1:m, j in 1:n),
])
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
MOI.optimize!(model)
N = MOI.get(model, MOI.ResultCount())
y_sol = hcat(MOI.get.(model, MOI.ObjectiveValue.(1:N))...)
Y_N = Float64[143 156 176 186 208; 265 200 175 171 167]
@test isapprox(y_sol, Y_N; atol = 1e-6)
return
end

function test_deprecated()
nise = MOA.NISE()
dichotomy = MOA.Dichotomy()
@test nise isa typeof(dichotomy)
@test nise.solution_limit === dichotomy.solution_limit
return
end

function test_three_objective()
model = MOA.Optimizer(HiGHS.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
MOI.set(model, MOI.Silent(), true)
MOI.Utilities.loadfromstring!(
model,
"""
variables: x
maxobjective: [1.0 * x, -1.0 * x, 2.0 * x + 2.0]
""",
)
@test_throws(
ErrorException("Only scalar or bi-objective problems supported."),
MOI.optimize!(model),
)
return
end

end

TestNISE.run_tests()
TestDichotomy.run_tests()