Skip to content

Commit 7cc03e0

Browse files
authored
Support VectorQuadraticFunction objectives (#45)
1 parent b798d58 commit 7cc03e0

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
1010
[compat]
1111
Combinatorics = "1"
1212
HiGHS = "1"
13+
Ipopt = "1"
1314
MathOptInterface = "1.12"
1415
julia = "1.6"
1516

1617
[extras]
1718
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
19+
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
1820
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1921

2022
[targets]
21-
test = ["HiGHS", "Test"]
23+
test = ["HiGHS", "Ipopt", "Test"]

src/MultiObjectiveAlgorithms.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ function _scalarise(f::MOI.VectorAffineFunction, w::Vector{Float64})
7171
return MOI.ScalarAffineFunction(terms, constant)
7272
end
7373

74+
function _scalarise(f::MOI.VectorQuadraticFunction, w::Vector{Float64})
75+
@assert MOI.output_dimension(f) == length(w)
76+
quad_terms = MOI.ScalarQuadraticTerm{Float64}[
77+
MOI.ScalarQuadraticTerm(
78+
w[term.output_index] * term.scalar_term.coefficient,
79+
term.scalar_term.variable_1,
80+
term.scalar_term.variable_2,
81+
) for term in f.quadratic_terms
82+
]
83+
affine_terms = MOI.ScalarAffineTerm{Float64}[
84+
MOI.ScalarAffineTerm(
85+
w[term.output_index] * term.scalar_term.coefficient,
86+
term.scalar_term.variable,
87+
) for term in f.affine_terms
88+
]
89+
constant = sum(w[i] * f.constants[i] for i in 1:length(w))
90+
return MOI.ScalarQuadraticFunction(quad_terms, affine_terms, constant)
91+
end
92+
7493
abstract type AbstractAlgorithm end
7594

7695
MOI.Utilities.map_indices(::Function, x::AbstractAlgorithm) = x

test/algorithms/Dichotomy.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module TestDichotomy
88
using Test
99

1010
import HiGHS
11+
import Ipopt
1112
import MultiObjectiveAlgorithms as MOA
1213

1314
const MOI = MOA.MOI
@@ -333,6 +334,33 @@ maxobjective: [1.0 * x, -1.0 * x, 2.0 * x + 2.0]
333334
return
334335
end
335336

337+
function test_quadratic()
338+
μ = [0.05470748600000001, 0.18257110599999998]
339+
Q = [0.00076204 0.00051972; 0.00051972 0.00546173]
340+
N = 2
341+
model = MOA.Optimizer(Ipopt.Optimizer)
342+
MOI.set(model, MOA.Algorithm(), MOA.Dichotomy())
343+
MOI.set(model, MOA.SolutionLimit(), 10)
344+
MOI.set(model, MOI.Silent(), true)
345+
w = MOI.add_variables(model, N)
346+
MOI.add_constraint.(model, w, MOI.GreaterThan(0.0))
347+
MOI.add_constraint.(model, w, MOI.LessThan(1.0))
348+
MOI.add_constraint(model, sum(1.0 * w[i] for i in 1:N), MOI.EqualTo(1.0))
349+
var = sum(Q[i, j] * w[i] * w[j] for i in 1:N, j in 1:N)
350+
mean = sum(-μ[i] * w[i] for i in 1:N)
351+
f = MOI.Utilities.operate(vcat, Float64, var, mean)
352+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
353+
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
354+
MOI.optimize!(model)
355+
@test MOI.get(model, MOI.ResultCount()) == 10
356+
for i in 1:MOI.get(model, MOI.ResultCount())
357+
w_sol = MOI.get(model, MOI.VariablePrimal(i), w)
358+
y = MOI.get(model, MOI.ObjectiveValue(i))
359+
@test y [w_sol' * Q * w_sol, -μ' * w_sol]
360+
end
361+
return
362+
end
363+
336364
end
337365

338366
TestDichotomy.run_tests()

0 commit comments

Comments
 (0)