Skip to content

Commit 115778d

Browse files
committed
Add bridge from Hermitian PSD to complex function in Symmetric PSD
1 parent c611a46 commit 115778d

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
"""
8+
HermitianToComplexSymmetricBridge{T,F,G} <: Bridges.Constraint.AbstractBridge
9+
10+
`HermitianToSymmetricBridge` implements the following reformulation:
11+
12+
* Hermitian positive semidefinite `n x n` represented as a vector of real
13+
entries with real and imaginary parts on different entries to a vector
14+
of complex entries.
15+
16+
See also [`MOI.Bridges.Constraint.HermitianToSymmetricPSDBridge`](@ref).
17+
18+
## Source node
19+
20+
`HermitianToComplexSymmetricBridge` supports:
21+
22+
* `G` in [`MOI.HermitianPositiveSemidefiniteConeTriangle`](@ref)
23+
24+
## Target node
25+
26+
`HermitianToComplexSymmetricBridge` creates:
27+
28+
* `F` in [`MOI.PositiveSemidefiniteConeTriangle`](@ref)
29+
30+
## Reformulation
31+
32+
The reformulation is best described by example.
33+
34+
The Hermitian matrix:
35+
```math
36+
\\begin{bmatrix}
37+
x_{11} & x_{12} + y_{12}im & x_{13} + y_{13}im\\\\
38+
x_{12} - y_{12}im & x_{22} & x_{23} + y_{23}im\\\\
39+
x_{13} - y_{13}im & x_{23} - y_{23}im & x_{33}
40+
\\end{bmatrix}
41+
```
42+
is positive semidefinite if and only if the symmetric matrix:
43+
```math
44+
\\begin{bmatrix}
45+
x_{11} & x_{12} & x_{13} & 0 & y_{12} & y_{13} \\\\
46+
& x_{22} & x_{23} & -y_{12} & 0 & y_{23} \\\\
47+
& & x_{33} & -y_{13} & -y_{23} & 0 \\\\
48+
& & & x_{11} & x_{12} & x_{13} \\\\
49+
& & & & x_{22} & x_{23} \\\\
50+
& & & & & x_{33}
51+
\\end{bmatrix}
52+
```
53+
is positive semidefinite.
54+
55+
The bridge achieves this reformulation by constraining the above matrix to
56+
belong to the `MOI.PositiveSemidefiniteConeTriangle(6)`.
57+
"""
58+
struct HermitianToComplexSymmetricBridge{T,F,G} <: SetMapBridge{
59+
T,
60+
MOI.PositiveSemidefiniteConeTriangle,
61+
MOI.HermitianPositiveSemidefiniteConeTriangle,
62+
F,
63+
G,
64+
}
65+
constraint::MOI.ConstraintIndex{F,MOI.PositiveSemidefiniteConeTriangle}
66+
end
67+
68+
# Should be favored over `HermitianToSymmetricPSDBridge`
69+
MOI.Bridges.bridging_cost(::Type{<:SOCtoPSDBridge}) = 0.5
70+
71+
function _promote_complex_vcat(::Type{T}, ::Type{G}) where {T,G}
72+
S = MOI.Utilities.scalar_type(G)
73+
M = MOI.Utilities.promote_operation(*, Complex{T}, S)
74+
return MOI.Utilities.promote_operation(vcat, T, M)
75+
end
76+
77+
function concrete_bridge_type(
78+
::Type{<:HermitianToComplexSymmetricBridge{T}},
79+
G::Type{<:MOI.AbstractVectorFunction},
80+
::Type{MOI.HermitianPositiveSemidefiniteConeTriangle},
81+
) where {T}
82+
F = _promote_complex_vcat(T, G)
83+
return HermitianToComplexSymmetricBridge{T,F,G}
84+
end
85+
86+
function MOI.Bridges.map_set(
87+
::Type{<:HermitianToComplexSymmetricBridge},
88+
set::MOI.HermitianPositiveSemidefiniteConeTriangle,
89+
)
90+
return MOI.PositiveSemidefiniteConeTriangle(set.side_dimension)
91+
end
92+
93+
function MOI.Bridges.inverse_map_set(
94+
::Type{<:HermitianToComplexSymmetricBridge},
95+
set::MOI.PositiveSemidefiniteConeTriangle,
96+
)
97+
return MOI.HermitianPositiveSemidefiniteConeTriangle(set.side_dimension)
98+
end
99+
100+
function MOI.Bridges.map_function(
101+
::Type{<:HermitianToComplexSymmetricBridge{T}},
102+
func,
103+
) where {T}
104+
complex_scalars = MOI.Utilities.eachscalar(func)
105+
S = MOI.Utilities.scalar_type(_promote_complex_vcat(T, typeof(func)))
106+
complex_dim = length(complex_scalars)
107+
complex_set = MOI.Utilities.set_with_dimension(
108+
MOI.HermitianPositiveSemidefiniteConeTriangle,
109+
complex_dim,
110+
)
111+
n = complex_set.side_dimension
112+
real_set = MOI.PositiveSemidefiniteConeTriangle(n)
113+
real_dim = MOI.dimension(real_set)
114+
real_scalars = Vector{S}(undef, real_dim)
115+
real_index = 0
116+
imag_index = real_dim
117+
for j in 1:n
118+
for i in 1:j
119+
real_index += 1
120+
if i == j
121+
real_scalars[real_index] = complex_scalars[real_index]
122+
else
123+
imag_index += 1
124+
real_scalars[real_index] = complex_scalars[real_index] + (one(T) * im) * complex_scalars[imag_index]
125+
end
126+
end
127+
end
128+
@assert length(real_scalars) == real_index
129+
@assert length(complex_scalars) == imag_index
130+
return MOI.Utilities.vectorize(real_scalars)
131+
end
132+
133+
function MOI.Bridges.inverse_map_function(
134+
::Type{<:HermitianToComplexSymmetricBridge},
135+
func,
136+
)
137+
real_scalars = MOI.Utilities.eachscalar(func)
138+
real_set = MOI.Utilities.set_with_dimension(
139+
MOI.PositiveSemidefiniteConeTriangle,
140+
length(real_scalars),
141+
)
142+
n = real_set.side_dimension
143+
complex_set = MOI.HermitianPositiveSemidefiniteConeTriangle(n)
144+
complex_scalars =
145+
Vector{MA.promote_operation(real, MOI.Utilities.scalar_type(typeof(func)))}(undef, MOI.dimension(complex_set))
146+
real_index = 0
147+
imag_index = MOI.dimension(real_set)
148+
for j in 1:n
149+
for i in 1:j
150+
real_index += 1
151+
complex_scalars[real_index] = real(real_scalars[real_index])
152+
if i != j
153+
imag_index += 1
154+
complex_scalars[imag_index] = imag(real_scalars[real_index])
155+
end
156+
end
157+
end
158+
@assert length(real_scalars) == real_index
159+
@assert length(complex_scalars) == imag_index
160+
return MOI.Utilities.vectorize(complex_scalars)
161+
end

0 commit comments

Comments
 (0)