From fe09980e21843d1f2ef21f8e44004af25155aaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 14 Mar 2021 19:26:02 +0100 Subject: [PATCH 1/2] add quadratic term --- src/conic_form.jl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/conic_form.jl b/src/conic_form.jl index b1ee86e..c689bd0 100644 --- a/src/conic_form.jl +++ b/src/conic_form.jl @@ -1,15 +1,15 @@ """ - GeometricConicForm{T, AT, VT, C} <: MOI.ModelLike + GeometricConicForm{T, AT, VB, VC, QT, C} <: MOI.ModelLike Represents an optimization model of the form: ``` -sense ⟨c, x⟩ + c0 +sense ⟨c, x⟩ + ⟨Qx, x⟩ + c0 s.t. b_i - A_i x ∈ C_i ∀ i ``` with each `C_i` a cone defined in MOI. """ -mutable struct GeometricConicForm{T, AT, VB, VC, C} <: MOI.ModelLike +mutable struct GeometricConicForm{T, AT, VB, VC, QT, C} <: MOI.ModelLike num_rows::Vector{Int} dimension::Dict{Int, Int} sense::MOI.OptimizationSense @@ -17,11 +17,12 @@ mutable struct GeometricConicForm{T, AT, VB, VC, C} <: MOI.ModelLike A::Union{Nothing, AT} # The constraints b::VB # `b - Ax in cones` c::VC # `sense c'x + objective_constant` + Q::Union{QT, Nothing} cone_types::C cone_types_dict::Dict{DataType, Int} - function GeometricConicForm{T, AT, VB, VC}(cone_types) where {T, AT, VB, VC} - model = new{T, AT, VB, VC, typeof(cone_types)}() + function GeometricConicForm{T, AT, VB, VC, QT}(cone_types) where {T, AT, VB, VC, QT} + model = new{T, AT, VB, VC, QT, typeof(cone_types)}() model.cone_types = cone_types model.cone_types_dict = Dict{DataType, Int}( s => i for (i, s) in enumerate(cone_types) @@ -29,10 +30,15 @@ mutable struct GeometricConicForm{T, AT, VB, VC, C} <: MOI.ModelLike model.num_rows = zeros(Int, length(cone_types)) model.dimension = Dict{Int, Int}() model.A = nothing + model.Q = nothing return model end end +function GeometricConicForm{T, AT, VB, VC}(cone_types) where {T, AT, VB, VC} + return GeometricConicForm{T, AT, VB, VC, SparseMatrixCSC{T,Int}}(cone_types) +end + function GeometricConicForm{T, AT, VT}(cone_types) where {T, AT, VT} return GeometricConicForm{T, AT, VT, VT}(cone_types) end From 56808b116cd2dcedb2aa00396f8f6feed18b1b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Sun, 14 Mar 2021 21:07:28 +0100 Subject: [PATCH 2/2] add test and set quadratic objective --- src/conic_form.jl | 16 +++++++++++++++- test/conic_form.jl | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/conic_form.jl b/src/conic_form.jl index c689bd0..99d7d6f 100644 --- a/src/conic_form.jl +++ b/src/conic_form.jl @@ -111,6 +111,20 @@ function MOI.set(model::GeometricConicForm{T}, ::MOI.ObjectiveFunction, return nothing end +function MOI.set(model::GeometricConicForm{T, AT, VB, VC, QT}, ::MOI.ObjectiveFunction, + f::MOI.ScalarQuadraticFunction{T}) where {T, AT, VB, VC, QT} + c = Vector(sparsevec(variable_index_value.(f.affine_terms), MOI.coefficient.(f.affine_terms), + model.A.n)) + model.objective_constant = f.constant + model.c = c + n = length(c) + Q = convert(QT, spzeros(T, n, n)) + for term in f.quadratic_terms + Q[term.variable_index_1.value, term.variable_index_2.value] = term.coefficient + end + return nothing +end + function _allocate_constraint(model::GeometricConicForm, src, indexmap, cone_id, ci) # TODO use `CanonicalConstraintFunction` func = MOI.get(src, MOI.ConstraintFunction(), ci) @@ -147,7 +161,7 @@ function _load_constraints(model::GeometricConicForm, src, indexmap, cone_offset end end -function MOI.copy_to(dest::GeometricConicForm{T}, src::MOI.ModelLike; copy_names::Bool=true) where T +function MOI.copy_to(dest::GeometricConicForm{T}, src::MOI.ModelLike; copy_names::Bool=true) where {T} MOI.empty!(dest) vis_src = MOI.get(src, MOI.ListOfVariableIndices()) diff --git a/test/conic_form.jl b/test/conic_form.jl index fb30054..642bfa7 100644 --- a/test/conic_form.jl +++ b/test/conic_form.jl @@ -85,6 +85,22 @@ function psd1(::Type{T}, ::Type{I}) where {T, I} T[-1, -1, -1, -1, -2, -1, -1, -1, -1, -2, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1], ) ) + @test conic_form.Q === nothing + + conic_form2 = MatOI.GeometricConicForm{T, MatOI.SparseMatrixCSRtoCSC{T, Int, I}, Vector{T}, Vector{T}, SparseMatrixCSC{T, Int}}([MOI.PositiveSemidefiniteConeTriangle, MOI.SecondOrderCone, MOI.Zeros]) + + MOI.set( + model, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}}(), + MOI.ScalarQuadraticFunction( + MOI.ScalarAffineTerm.([objXcoefs; one(T)], [X[objXidx]; x[1]]), + [MOI.ScalarQuadraticTerm(0.5, x[1], x[1])], + zero(T), + ) + ) + index_map = MOI.copy_to(conic_form2, model) + @test conic_form.Q !== nothing + @test sum(conic_form.Q) ≈ 0.5 end # Taken from `MOI.Test.psdt2test`. @@ -147,7 +163,7 @@ function psd2(::Type{T}, ::Type{I}, η::T = T(10), α::T = T(4)/T(5), δ::T = T( ) end -@testset "PSD $T, $I" for T in [Float64, BigFloat], I in [MatOI.ZeroBasedIndexing, MatOI.OneBasedIndexing] +@testset "PSD $T, $I" for T in (Float64, BigFloat), I in (MatOI.ZeroBasedIndexing, MatOI.OneBasedIndexing) psd1(T, I) psd2(T, I) end