From 89f2efe63a30471aefea51f868386979058d8625 Mon Sep 17 00:00:00 2001 From: araujoms Date: Sun, 24 Aug 2025 00:01:43 +0200 Subject: [PATCH 1/8] add MOI interface for complex PSD cone --- Project.toml | 2 + src/MOI_wrapper/MOI_wrapper.jl | 8 +- .../hermitian_complex_psd_cone_bridge.jl | 170 ++++++++++++++++++ .../scaled_complex_psd_cone_bridge.jl | 121 +++++++++++++ 4 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl create mode 100644 src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl diff --git a/Project.toml b/Project.toml index dcf2bea..6a023ad 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "2.1.0" [deps] MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" SCS_jll = "f4f2fc5b-1d94-523c-97ea-2ab488bedf4b" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" @@ -19,6 +20,7 @@ SCSSCS_MKL_jllExt = ["SCS_MKL_jll"] [compat] MathOptInterface = "1.20" +MutableArithmetics = "1" Pkg = "<0.0.1, ^1.6" PrecompileTools = "1" SCS_GPU_jll = "=3.2.8" diff --git a/src/MOI_wrapper/MOI_wrapper.jl b/src/MOI_wrapper/MOI_wrapper.jl index 18e651c..7f68120 100644 --- a/src/MOI_wrapper/MOI_wrapper.jl +++ b/src/MOI_wrapper/MOI_wrapper.jl @@ -4,6 +4,8 @@ # in the LICENSE.md file or at https://opensource.org/licenses/MIT. include("scaled_psd_cone_bridge.jl") +include("hermitian_complex_psd_cone_bridge.jl") +include("scaled_complex_psd_cone_bridge.jl") MOI.Utilities.@product_of_sets( _Cones, @@ -11,6 +13,7 @@ MOI.Utilities.@product_of_sets( MOI.Nonnegatives, MOI.SecondOrderCone, ScaledPSDCone, + ScaledComplexPSDCone, MOI.ExponentialCone, MOI.DualExponentialCone, MOI.PowerCone{T}, @@ -132,7 +135,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer end function MOI.get(::Optimizer, ::MOI.Bridges.ListOfNonstandardBridges) - return Type[ScaledPSDConeBridge{Cdouble}] + return Type[ScaledPSDConeBridge{Cdouble}, ScaledComplexPSDConeBridge{Cdouble}, HermitianComplexPSDConeBridge{Cdouble}] end MOI.get(::Optimizer, ::MOI.SolverName) = "SCS" @@ -239,6 +242,7 @@ function MOI.supports_constraint( MOI.Nonnegatives, MOI.SecondOrderCone, ScaledPSDCone, + ScaledComplexPSDCone, MOI.ExponentialCone, MOI.DualExponentialCone, MOI.PowerCone{Cdouble}, @@ -390,7 +394,7 @@ function MOI.optimize!( Float64[], # # placeholder: bl _map_sets(MOI.dimension, T, Ab, MOI.SecondOrderCone), _map_sets(MOI.side_dimension, T, Ab, ScaledPSDCone), - Int[], # placeholder complex PSD + _map_sets(MOI.side_dimension, T, Ab, ScaledComplexPSDCone), div(Ab.sets.num_rows[5] - Ab.sets.num_rows[4], 3), div(Ab.sets.num_rows[6] - Ab.sets.num_rows[5], 3), vcat( diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl new file mode 100644 index 0000000..53da18c --- /dev/null +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -0,0 +1,170 @@ +# Copyright (c) 2014: SCS.jl contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +""" + struct ComplexPositiveSemidefiniteConeTriangle <: MOI.AbstractVectorSet + side_dimension::Int + end + +Similar to `HermitianPositiveSemidefiniteConeTriangle` but its +vectorization interleaves real and imaginary parts of the off-diagonal. +""" +struct ComplexPositiveSemidefiniteConeTriangle <: MOI.AbstractVectorSet + side_dimension::Int +end + +function MOI.Utilities.set_with_dimension(::Type{ComplexPositiveSemidefiniteConeTriangle}, dim) + return ComplexPositiveSemidefiniteConeTriangle(isqrt(dim)) +end + +Base.copy(x::ComplexPositiveSemidefiniteConeTriangle) = ComplexPositiveSemidefiniteConeTriangle(x.side_dimension) + +MOI.side_dimension(x::ComplexPositiveSemidefiniteConeTriangle) = x.side_dimension + +function MOI.dimension(x::ComplexPositiveSemidefiniteConeTriangle) + return x.side_dimension ^ 2 +end + +import MutableArithmetics as MA + +function MOI.Utilities.set_dot( + x::AbstractVector{S}, + y::AbstractVector{T}, + set::ComplexPositiveSemidefiniteConeTriangle, +) where {S,T} + U = MA.promote_operation(MA.add_mul, S, T) + result = zero(U) + d = set.side_dimension + k = 0 + for j in 1:d + for i in 1:j-1 + k += 1 + result = MA.add_mul!!(result, 2, x[k], y[k]) + k += 1 + result = MA.add_mul!!(result, 2, x[k], y[k]) + end + k += 1 + result = MA.add_mul!!(result, x[k], y[k]) + end + return result +end + +function MOI.Utilities.dot_coefficients( + a::AbstractVector, + set::ComplexPositiveSemidefiniteConeTriangle, +) + d = set.side_dimension + b = copy(a) + k = 0 + for j in 1:d + for i in 1:j-1 + k += 1 + b[k] /= 2 + k += 1 + b[k] /= 2 + end + k += 1 + end + return b +end + +struct HermitianComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ + T, + ComplexPositiveSemidefiniteConeTriangle, + MOI.HermitianPositiveSemidefiniteConeTriangle, + F, + F, +} + constraint::MOI.ConstraintIndex{F,ComplexPositiveSemidefiniteConeTriangle} +end + +function MOI.Bridges.Constraint.concrete_bridge_type( + ::Type{HermitianComplexPSDConeBridge{T}}, + ::Type{F}, + ::Type{MOI.HermitianPositiveSemidefiniteConeTriangle}, +) where {T,F<:MOI.AbstractVectorFunction} + return HermitianComplexPSDConeBridge{T,F} +end + +function MOI.Bridges.map_set( + ::Type{<:HermitianComplexPSDConeBridge}, + set::MOI.HermitianPositiveSemidefiniteConeTriangle, +) + return ComplexPositiveSemidefiniteConeTriangle(MOI.side_dimension(set)) +end + +function MOI.Bridges.inverse_map_set( + ::Type{<:HermitianComplexPSDConeBridge}, + set::ComplexPositiveSemidefiniteConeTriangle, +) + return MOI.HermtianPositiveSemidefiniteConeTriangle(set.side_dimension) +end + +function _hermitian_to_complex(vals) + dim = length(vals) + side = isqrt(dim) + k_re = 1 + k_im = div(side * (side + 1), 2) + 1 + l = 1 + newvals = zero(vals) + for i in 1:side + for j in 1:(i - 1) + newvals[l] = vals[k_re] + newvals[l + 1] = vals[k_im] + k_re += 1 + k_im += 1 + l += 2 + end + newvals[l] = vals[k_re] + k_re += 1 + l += 1 + end + return newvals +end + +function _complex_to_hermitian(vals) + dim = length(vals) + side = isqrt(dim) + k_re = 1 + k_im = div(side * (side + 1), 2) + 1 + l = 1 + newvals = zero(vals) + for i in 1:side + for j in 1:(i - 1) + newvals[k_re] = vals[l] + newvals[k_im] = vals[l + 1] + k_re += 1 + k_im += 1 + l += 2 + end + newvals[k_re] = vals[l] + k_re += 1 + l += 1 + end + return newvals +end + +# Map ConstraintFunction from Hermitian -> Complex +function MOI.Bridges.map_function(::Type{<:HermitianComplexPSDConeBridge}, f) + return _hermitian_to_complex(f) +end + +# Used to map the ConstraintPrimal from Complex -> Hermitian +function MOI.Bridges.inverse_map_function(::Type{<:HermitianComplexPSDConeBridge}, f) + return _complex_to_hermitian(f) +end + +# Used to map the ConstraintDual from Complex -> Hermitian +function MOI.Bridges.adjoint_map_function(::Type{<:HermitianComplexPSDConeBridge}, f) + return _complex_to_hermitian(f) +end + +# Used to set ConstraintDualStart +function MOI.Bridges.inverse_adjoint_map_function( + ::Type{<:HermitianComplexPSDConeBridge}, + f, +) + return _hermitian_to_complex(f) +end diff --git a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl new file mode 100644 index 0000000..aeb29b9 --- /dev/null +++ b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl @@ -0,0 +1,121 @@ +# Copyright (c) 2014: SCS.jl contributors +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +""" + struct ScaledComplexPSDCone <: MOI.AbstractVectorSet + side_dimension::Int + end + +Similar to `MOI.Scaled{ComplexPositiveSemidefiniteConeTriangle}` but its +vectorization is the lower triangular part column-wise. +""" +struct ScaledComplexPSDCone <: MOI.AbstractVectorSet + side_dimension::Int +end + +function MOI.Utilities.set_with_dimension(::Type{ScaledComplexPSDCone}, dim) + return ScaledComplexPSDCone(isqrt(dim)) +end + +Base.copy(x::ScaledComplexPSDCone) = ScaledComplexPSDCone(x.side_dimension) + +MOI.side_dimension(x::ScaledComplexPSDCone) = x.side_dimension + +function MOI.dimension(x::ScaledComplexPSDCone) + return x.side_dimension ^ 2 +end + +struct ScaledComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ + T, + ScaledComplexPSDCone, + MOI.Scaled{ComplexPositiveSemidefiniteConeTriangle}, + F, + F, +} + constraint::MOI.ConstraintIndex{F,ScaledComplexPSDCone} +end + +function MOI.Bridges.Constraint.concrete_bridge_type( + ::Type{ScaledComplexPSDConeBridge{T}}, + ::Type{F}, + ::Type{MOI.Scaled{ComplexPositiveSemidefiniteConeTriangle}}, +) where {T,F<:MOI.AbstractVectorFunction} + return ScaledComplexPSDConeBridge{T,F} +end + +function MOI.Bridges.map_set( + ::Type{<:ScaledComplexPSDConeBridge}, + set::MOI.Scaled{ComplexPositiveSemidefiniteConeTriangle}, +) + return ScaledPSDCone(MOI.side_dimension(set)) +end + +function MOI.Bridges.inverse_map_set( + ::Type{<:ScaledComplexPSDConeBridge}, + set::ScaledComplexPSDCone, +) + return MOI.Scaled(ComplexPositiveSemidefiniteConeTriangle(set.side_dimension)) +end + +function _transform_function(func) + vals = MOI.Utilities.eachscalar(func) + d = isqrt(length(vals)) + c = 0 + newvals = zero(vals) + for i in 1:d + c += 1 + newvals[c] = vals[i^2] + for j in i+1:d + triidx = 2i - 1 + (j - 1) ^ 2 + c += 1 + newvals[c] = vals[triidx] + c += 1 + newvals[c] = -vals[triidx + 1] + end + end + return newvals +end + +function _untransform_function(func) + vals = MOI.Utilities.eachscalar(func) + d = isqrt(length(vals)) + c = 0 + newvals = zero(vals) + for i in 1:d + c += 1 + newvals[i^2] = vals[c] + for j in i+1:d + triidx = 2i - 1 + (j - 1) ^ 2 + c += 1 + newvals[triidx] = vals[c] + c += 1 + newvals[triidx + 1] = -vals[c] + end + end + return newvals +end + +# Map ConstraintFunction from MOI -> SCS +function MOI.Bridges.map_function(::Type{<:ScaledComplexPSDConeBridge}, f) + return _transform_function(f) +end + +# Used to map the ConstraintPrimal from SCS -> MOI +function MOI.Bridges.inverse_map_function(::Type{<:ScaledComplexPSDConeBridge}, f) + return _untransform_function(f) +end + +# Used to map the ConstraintDual from SCS -> MOI +function MOI.Bridges.adjoint_map_function(::Type{<:ScaledComplexPSDConeBridge}, f) + return _untransform_function(f) +end + +# Used to set ConstraintDualStart +function MOI.Bridges.inverse_adjoint_map_function( + ::Type{<:ScaledComplexPSDConeBridge}, + f, +) + return _transform_function(f) +end From b03e061a747345a6b4daba38c29b181f8bf4425e Mon Sep 17 00:00:00 2001 From: araujoms Date: Sun, 24 Aug 2025 00:04:16 +0200 Subject: [PATCH 2/8] formatting --- src/MOI_wrapper/MOI_wrapper.jl | 6 +++- .../hermitian_complex_psd_cone_bridge.jl | 36 +++++++++++++------ .../scaled_complex_psd_cone_bridge.jl | 24 ++++++++----- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/MOI_wrapper/MOI_wrapper.jl b/src/MOI_wrapper/MOI_wrapper.jl index 7f68120..150426b 100644 --- a/src/MOI_wrapper/MOI_wrapper.jl +++ b/src/MOI_wrapper/MOI_wrapper.jl @@ -135,7 +135,11 @@ mutable struct Optimizer <: MOI.AbstractOptimizer end function MOI.get(::Optimizer, ::MOI.Bridges.ListOfNonstandardBridges) - return Type[ScaledPSDConeBridge{Cdouble}, ScaledComplexPSDConeBridge{Cdouble}, HermitianComplexPSDConeBridge{Cdouble}] + return Type[ + ScaledPSDConeBridge{Cdouble}, + ScaledComplexPSDConeBridge{Cdouble}, + HermitianComplexPSDConeBridge{Cdouble}, + ] end MOI.get(::Optimizer, ::MOI.SolverName) = "SCS" diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl index 53da18c..9b45c17 100644 --- a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -15,16 +15,23 @@ struct ComplexPositiveSemidefiniteConeTriangle <: MOI.AbstractVectorSet side_dimension::Int end -function MOI.Utilities.set_with_dimension(::Type{ComplexPositiveSemidefiniteConeTriangle}, dim) +function MOI.Utilities.set_with_dimension( + ::Type{ComplexPositiveSemidefiniteConeTriangle}, + dim, +) return ComplexPositiveSemidefiniteConeTriangle(isqrt(dim)) end -Base.copy(x::ComplexPositiveSemidefiniteConeTriangle) = ComplexPositiveSemidefiniteConeTriangle(x.side_dimension) +function Base.copy(x::ComplexPositiveSemidefiniteConeTriangle) + return ComplexPositiveSemidefiniteConeTriangle(x.side_dimension) +end -MOI.side_dimension(x::ComplexPositiveSemidefiniteConeTriangle) = x.side_dimension +function MOI.side_dimension(x::ComplexPositiveSemidefiniteConeTriangle) + return x.side_dimension +end function MOI.dimension(x::ComplexPositiveSemidefiniteConeTriangle) - return x.side_dimension ^ 2 + return x.side_dimension^2 end import MutableArithmetics as MA @@ -70,7 +77,8 @@ function MOI.Utilities.dot_coefficients( return b end -struct HermitianComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ +struct HermitianComplexPSDConeBridge{T,F} <: + MOI.Bridges.Constraint.SetMapBridge{ T, ComplexPositiveSemidefiniteConeTriangle, MOI.HermitianPositiveSemidefiniteConeTriangle, @@ -110,9 +118,9 @@ function _hermitian_to_complex(vals) l = 1 newvals = zero(vals) for i in 1:side - for j in 1:(i - 1) + for j in 1:(i-1) newvals[l] = vals[k_re] - newvals[l + 1] = vals[k_im] + newvals[l+1] = vals[k_im] k_re += 1 k_im += 1 l += 2 @@ -132,9 +140,9 @@ function _complex_to_hermitian(vals) l = 1 newvals = zero(vals) for i in 1:side - for j in 1:(i - 1) + for j in 1:(i-1) newvals[k_re] = vals[l] - newvals[k_im] = vals[l + 1] + newvals[k_im] = vals[l+1] k_re += 1 k_im += 1 l += 2 @@ -152,12 +160,18 @@ function MOI.Bridges.map_function(::Type{<:HermitianComplexPSDConeBridge}, f) end # Used to map the ConstraintPrimal from Complex -> Hermitian -function MOI.Bridges.inverse_map_function(::Type{<:HermitianComplexPSDConeBridge}, f) +function MOI.Bridges.inverse_map_function( + ::Type{<:HermitianComplexPSDConeBridge}, + f, +) return _complex_to_hermitian(f) end # Used to map the ConstraintDual from Complex -> Hermitian -function MOI.Bridges.adjoint_map_function(::Type{<:HermitianComplexPSDConeBridge}, f) +function MOI.Bridges.adjoint_map_function( + ::Type{<:HermitianComplexPSDConeBridge}, + f, +) return _complex_to_hermitian(f) end diff --git a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl index aeb29b9..bcf309e 100644 --- a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl @@ -24,7 +24,7 @@ Base.copy(x::ScaledComplexPSDCone) = ScaledComplexPSDCone(x.side_dimension) MOI.side_dimension(x::ScaledComplexPSDCone) = x.side_dimension function MOI.dimension(x::ScaledComplexPSDCone) - return x.side_dimension ^ 2 + return x.side_dimension^2 end struct ScaledComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ @@ -56,7 +56,9 @@ function MOI.Bridges.inverse_map_set( ::Type{<:ScaledComplexPSDConeBridge}, set::ScaledComplexPSDCone, ) - return MOI.Scaled(ComplexPositiveSemidefiniteConeTriangle(set.side_dimension)) + return MOI.Scaled( + ComplexPositiveSemidefiniteConeTriangle(set.side_dimension), + ) end function _transform_function(func) @@ -68,11 +70,11 @@ function _transform_function(func) c += 1 newvals[c] = vals[i^2] for j in i+1:d - triidx = 2i - 1 + (j - 1) ^ 2 + triidx = 2i - 1 + (j - 1)^2 c += 1 newvals[c] = vals[triidx] c += 1 - newvals[c] = -vals[triidx + 1] + newvals[c] = -vals[triidx+1] end end return newvals @@ -87,11 +89,11 @@ function _untransform_function(func) c += 1 newvals[i^2] = vals[c] for j in i+1:d - triidx = 2i - 1 + (j - 1) ^ 2 + triidx = 2i - 1 + (j - 1)^2 c += 1 newvals[triidx] = vals[c] c += 1 - newvals[triidx + 1] = -vals[c] + newvals[triidx+1] = -vals[c] end end return newvals @@ -103,12 +105,18 @@ function MOI.Bridges.map_function(::Type{<:ScaledComplexPSDConeBridge}, f) end # Used to map the ConstraintPrimal from SCS -> MOI -function MOI.Bridges.inverse_map_function(::Type{<:ScaledComplexPSDConeBridge}, f) +function MOI.Bridges.inverse_map_function( + ::Type{<:ScaledComplexPSDConeBridge}, + f, +) return _untransform_function(f) end # Used to map the ConstraintDual from SCS -> MOI -function MOI.Bridges.adjoint_map_function(::Type{<:ScaledComplexPSDConeBridge}, f) +function MOI.Bridges.adjoint_map_function( + ::Type{<:ScaledComplexPSDConeBridge}, + f, +) return _untransform_function(f) end From 662402d15e87a970bbda6a3ccf904b1313886451 Mon Sep 17 00:00:00 2001 From: araujoms Date: Sun, 24 Aug 2025 11:23:33 +0200 Subject: [PATCH 3/8] fix indexing --- src/MOI_wrapper/MOI_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper/MOI_wrapper.jl b/src/MOI_wrapper/MOI_wrapper.jl index 150426b..a1e7671 100644 --- a/src/MOI_wrapper/MOI_wrapper.jl +++ b/src/MOI_wrapper/MOI_wrapper.jl @@ -399,8 +399,8 @@ function MOI.optimize!( _map_sets(MOI.dimension, T, Ab, MOI.SecondOrderCone), _map_sets(MOI.side_dimension, T, Ab, ScaledPSDCone), _map_sets(MOI.side_dimension, T, Ab, ScaledComplexPSDCone), - div(Ab.sets.num_rows[5] - Ab.sets.num_rows[4], 3), div(Ab.sets.num_rows[6] - Ab.sets.num_rows[5], 3), + div(Ab.sets.num_rows[7] - Ab.sets.num_rows[6], 3), vcat( _map_sets(set -> set.exponent, Float64, Ab, MOI.PowerCone{Cdouble}), _map_sets( From e4598cea259e486786087a200ab7cc4bc4999fe8 Mon Sep 17 00:00:00 2001 From: araujoms Date: Sun, 24 Aug 2025 22:16:10 +0200 Subject: [PATCH 4/8] working interface --- .../hermitian_complex_psd_cone_bridge.jl | 33 +++++++++++------- .../scaled_complex_psd_cone_bridge.jl | 34 +++++++++---------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl index 9b45c17..b48e0dd 100644 --- a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -77,6 +77,11 @@ function MOI.Utilities.dot_coefficients( return b end +function MOI.is_set_dot_scaled( + ::Type{ComplexPositiveSemidefiniteConeTriangle}) + return true +end + struct HermitianComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ T, @@ -107,51 +112,53 @@ function MOI.Bridges.inverse_map_set( ::Type{<:HermitianComplexPSDConeBridge}, set::ComplexPositiveSemidefiniteConeTriangle, ) - return MOI.HermtianPositiveSemidefiniteConeTriangle(set.side_dimension) + return MOI.HermitianPositiveSemidefiniteConeTriangle(set.side_dimension) end -function _hermitian_to_complex(vals) +function _hermitian_to_complex(func) + vals = MOI.Utilities.eachscalar(func) dim = length(vals) side = isqrt(dim) k_re = 1 k_im = div(side * (side + 1), 2) + 1 l = 1 - newvals = zero(vals) + perm = zeros(Int, dim) for i in 1:side for j in 1:(i-1) - newvals[l] = vals[k_re] - newvals[l+1] = vals[k_im] + perm[l] = k_re + perm[l+1] = k_im k_re += 1 k_im += 1 l += 2 end - newvals[l] = vals[k_re] + perm[l] = k_re k_re += 1 l += 1 end - return newvals + return vals[perm] end -function _complex_to_hermitian(vals) +function _complex_to_hermitian(func) + vals = MOI.Utilities.eachscalar(func) dim = length(vals) side = isqrt(dim) k_re = 1 k_im = div(side * (side + 1), 2) + 1 l = 1 - newvals = zero(vals) + perm = zeros(Int, dim) for i in 1:side for j in 1:(i-1) - newvals[k_re] = vals[l] - newvals[k_im] = vals[l+1] + perm[k_re] = l + perm[k_im] = l+1 k_re += 1 k_im += 1 l += 2 end - newvals[k_re] = vals[l] + perm[k_re] = l k_re += 1 l += 1 end - return newvals + return vals[perm] end # Map ConstraintFunction from Hermitian -> Complex diff --git a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl index bcf309e..68462bc 100644 --- a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl @@ -49,7 +49,7 @@ function MOI.Bridges.map_set( ::Type{<:ScaledComplexPSDConeBridge}, set::MOI.Scaled{ComplexPositiveSemidefiniteConeTriangle}, ) - return ScaledPSDCone(MOI.side_dimension(set)) + return ScaledComplexPSDCone(MOI.side_dimension(set)) end function MOI.Bridges.inverse_map_set( @@ -61,47 +61,47 @@ function MOI.Bridges.inverse_map_set( ) end -function _transform_function(func) +function _complex_to_scs(func) vals = MOI.Utilities.eachscalar(func) d = isqrt(length(vals)) c = 0 - newvals = zero(vals) + perm = zeros(Int, length(vals)) for i in 1:d c += 1 - newvals[c] = vals[i^2] + perm[c] = i^2 for j in i+1:d triidx = 2i - 1 + (j - 1)^2 c += 1 - newvals[c] = vals[triidx] + perm[c] = triidx c += 1 - newvals[c] = -vals[triidx+1] + perm[c] = triidx+1 end end - return newvals + return vals[perm] end -function _untransform_function(func) +function _scs_to_complex(func) vals = MOI.Utilities.eachscalar(func) d = isqrt(length(vals)) c = 0 - newvals = zero(vals) + perm = zeros(Int, length(vals)) for i in 1:d c += 1 - newvals[i^2] = vals[c] + perm[i^2] = c for j in i+1:d triidx = 2i - 1 + (j - 1)^2 c += 1 - newvals[triidx] = vals[c] + perm[triidx] = c c += 1 - newvals[triidx+1] = -vals[c] + perm[triidx+1] = c end end - return newvals + return vals[perm] end # Map ConstraintFunction from MOI -> SCS function MOI.Bridges.map_function(::Type{<:ScaledComplexPSDConeBridge}, f) - return _transform_function(f) + return _complex_to_scs(f) end # Used to map the ConstraintPrimal from SCS -> MOI @@ -109,7 +109,7 @@ function MOI.Bridges.inverse_map_function( ::Type{<:ScaledComplexPSDConeBridge}, f, ) - return _untransform_function(f) + return _scs_to_complex(f) end # Used to map the ConstraintDual from SCS -> MOI @@ -117,7 +117,7 @@ function MOI.Bridges.adjoint_map_function( ::Type{<:ScaledComplexPSDConeBridge}, f, ) - return _untransform_function(f) + return _scs_to_complex(f) end # Used to set ConstraintDualStart @@ -125,5 +125,5 @@ function MOI.Bridges.inverse_adjoint_map_function( ::Type{<:ScaledComplexPSDConeBridge}, f, ) - return _transform_function(f) + return _complex_to_scs(f) end From 0cf6a5a40597dae3ccbdb15f32ebfabbd606994f Mon Sep 17 00:00:00 2001 From: araujoms Date: Sun, 24 Aug 2025 22:19:46 +0200 Subject: [PATCH 5/8] formatting --- src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl | 5 ++--- src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl index b48e0dd..207d479 100644 --- a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -77,8 +77,7 @@ function MOI.Utilities.dot_coefficients( return b end -function MOI.is_set_dot_scaled( - ::Type{ComplexPositiveSemidefiniteConeTriangle}) +function MOI.is_set_dot_scaled(::Type{ComplexPositiveSemidefiniteConeTriangle}) return true end @@ -149,7 +148,7 @@ function _complex_to_hermitian(func) for i in 1:side for j in 1:(i-1) perm[k_re] = l - perm[k_im] = l+1 + perm[k_im] = l + 1 k_re += 1 k_im += 1 l += 2 diff --git a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl index 68462bc..79165e4 100644 --- a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl @@ -74,7 +74,7 @@ function _complex_to_scs(func) c += 1 perm[c] = triidx c += 1 - perm[c] = triidx+1 + perm[c] = triidx + 1 end end return vals[perm] From 42d8da71b092a27252cd18402e2562bbaf00a2d1 Mon Sep 17 00:00:00 2001 From: araujoms Date: Mon, 25 Aug 2025 21:25:09 +0200 Subject: [PATCH 6/8] lower bridge cost --- src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl | 2 ++ src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl index 207d479..0036ac9 100644 --- a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -92,6 +92,8 @@ struct HermitianComplexPSDConeBridge{T,F} <: constraint::MOI.ConstraintIndex{F,ComplexPositiveSemidefiniteConeTriangle} end +MOI.Bridges.bridging_cost(::Type{<:ComplexPositiveSemidefiniteConeTriangle}) = 0.1 + function MOI.Bridges.Constraint.concrete_bridge_type( ::Type{HermitianComplexPSDConeBridge{T}}, ::Type{F}, diff --git a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl index 79165e4..8e60ddd 100644 --- a/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/scaled_complex_psd_cone_bridge.jl @@ -37,6 +37,8 @@ struct ScaledComplexPSDConeBridge{T,F} <: MOI.Bridges.Constraint.SetMapBridge{ constraint::MOI.ConstraintIndex{F,ScaledComplexPSDCone} end +MOI.Bridges.bridging_cost(::Type{<:ScaledComplexPSDConeBridge}) = 0.1 + function MOI.Bridges.Constraint.concrete_bridge_type( ::Type{ScaledComplexPSDConeBridge{T}}, ::Type{F}, From ef6a3f773df0e571b4972f9611f0ffae0a04885b Mon Sep 17 00:00:00 2001 From: araujoms Date: Mon, 25 Aug 2025 21:31:08 +0200 Subject: [PATCH 7/8] typo --- src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl index 0036ac9..7aa207b 100644 --- a/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl +++ b/src/MOI_wrapper/hermitian_complex_psd_cone_bridge.jl @@ -92,7 +92,7 @@ struct HermitianComplexPSDConeBridge{T,F} <: constraint::MOI.ConstraintIndex{F,ComplexPositiveSemidefiniteConeTriangle} end -MOI.Bridges.bridging_cost(::Type{<:ComplexPositiveSemidefiniteConeTriangle}) = 0.1 +MOI.Bridges.bridging_cost(::Type{<:HermitianComplexPSDConeBridge}) = 0.1 function MOI.Bridges.Constraint.concrete_bridge_type( ::Type{HermitianComplexPSDConeBridge{T}}, From 84d5670ad31905b62c9a1eef53ce75337d764db0 Mon Sep 17 00:00:00 2001 From: araujoms Date: Mon, 25 Aug 2025 21:55:27 +0200 Subject: [PATCH 8/8] test no longer fails --- test/MOI_wrapper.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index bbbc765..eec18fc 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -61,7 +61,6 @@ function _test_runtests(linear_solver) # Unexpected failures: # TODO(odow): looks like a tolerance issue? "test_linear_add_constraints", - "test_conic_HermitianPositiveSemidefiniteConeTriangle_2", # Expected test failures: # TODO(odow): get not supported for primal/dual starts "test_model_ModelFilter_AbstractConstraintAttribute",