Skip to content

Commit

Permalink
Add support for VectorNonlinearFunction objectives (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Aug 16, 2023
1 parent 2d5d045 commit 1650ae1
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Combinatorics = "1"
HiGHS = "1"
Ipopt = "1"
MathOptInterface = "1.15"
MathOptInterface = "1.19"
julia = "1.6"

[extras]
Expand Down
12 changes: 11 additions & 1 deletion src/MultiObjectiveAlgorithms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ function _scalarise(f::MOI.VectorQuadraticFunction, w::Vector{Float64})
return MOI.ScalarQuadraticFunction(quad_terms, affine_terms, constant)
end

function _scalarise(f::MOI.VectorNonlinearFunction, w::Vector{Float64})
scalars = map(zip(w, f.rows)) do (wi, fi)
return MOI.ScalarNonlinearFunction(:*, Any[wi, fi])
end
return MOI.ScalarNonlinearFunction(:+, scalars)
end

abstract type AbstractAlgorithm end

MOI.Utilities.map_indices(::Function, x::AbstractAlgorithm) = x
Expand Down Expand Up @@ -493,6 +500,9 @@ function MOI.get(model::Optimizer, attr::MOI.ListOfModelAttributesSet)
end

function MOI.delete(model::Optimizer, x::MOI.VariableIndex)
if model.f isa MOI.VectorNonlinearFunction
throw(MOI.DeleteNotAllowed(x))
end
MOI.delete(model.inner, x)
if model.f !== nothing
model.f = MOI.Utilities.remove_variable(model.f, x)
Expand Down Expand Up @@ -582,7 +592,7 @@ function _compute_point(
X = Dict{MOI.VariableIndex,Float64}(
x => MOI.get(model.inner, MOI.VariablePrimal(), x) for x in variables
)
Y = MOI.Utilities.eval_variables(x -> X[x], f)
Y = MOI.Utilities.eval_variables(Base.Fix1(getindex, X), model, f)
return X, Y
end

Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/EpsilonConstraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function optimize_multiobjective!(
end
ci = MOI.add_constraint(model, f1, SetType(bound))
status = MOI.OPTIMAL
while true
for _ in 1:n_points
if _time_limit_exceeded(model, start_time)
status = MOI.TIME_LIMIT
break
Expand Down
32 changes: 32 additions & 0 deletions test/algorithms/EpsilonConstraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,38 @@ function test_poor_numerics()
return
end

function test_vectornonlinearfunction()
μ = [0.006898463772627643, -0.02972609131603086]
Q = [0.030446 0.00393731; 0.00393731 0.00713285]
N = 2
model = MOA.Optimizer(Ipopt.Optimizer)
MOI.set(model, MOA.Algorithm(), MOA.EpsilonConstraint())
MOI.set(model, MOA.SolutionLimit(), 10)
MOI.set(model, MOI.Silent(), true)
w = MOI.add_variables(model, N)
MOI.add_constraint.(model, w, MOI.GreaterThan(0.0))
MOI.add_constraint.(model, w, MOI.LessThan(1.0))
MOI.add_constraint(model, sum(1.0 * w[i] for i in 1:N), MOI.EqualTo(1.0))
f = MOI.VectorNonlinearFunction([
μ' * w,
MOI.ScalarNonlinearFunction(
:/,
Any[μ'*w, MOI.ScalarNonlinearFunction(:sqrt, Any[w'*Q*w])],
),
])
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
MOI.optimize!(model)
@test MOI.get(model, MOI.ResultCount()) >= 1
for i in 1:MOI.get(model, MOI.ResultCount())
w_sol = MOI.get(model, MOI.VariablePrimal(i), w)
y = MOI.get(model, MOI.ObjectiveValue(i))
@test y ' * w_sol, (μ' * w_sol) / sqrt(w_sol' * Q * w_sol)]
end
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL
return
end

function test_time_limit()
p1 = [77, 94, 71, 63, 96, 82, 85, 75, 72, 91, 99, 63, 84, 87, 79, 94, 90]
p2 = [65, 90, 90, 77, 95, 84, 70, 94, 66, 92, 74, 97, 60, 60, 65, 97, 93]
Expand Down

0 comments on commit 1650ae1

Please sign in to comment.