Skip to content

Commit 2a3b520

Browse files
authored
Tidy SDP atoms from CVXQUAD (#608)
1 parent da1051a commit 2a3b520

File tree

5 files changed

+228
-182
lines changed

5 files changed

+228
-182
lines changed

src/atoms/QuantumEntropyAtom.jl

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,32 @@
55
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
66

77
"""
8-
quantum_entropy returns -LinearAlgebra.tr(X*log(X)) where X is a positive semidefinite.
8+
QuantumEntropyAtom(X::AbstractExpr, m::Integer, k::Integer)
9+
10+
quantum_entropy returns -LinearAlgebra.tr(X*log(X)) where X is a positive
11+
semidefinite.
12+
913
Note this function uses logarithm base e, not base 2, so return value is in
1014
units of nats, not bits.
1115
1216
Quantum entropy is concave. This function implements the semidefinite
1317
programming approximation given in the reference below. Parameters m and k
14-
control the accuracy of this approximation: m is the number of quadrature
15-
nodes to use and k the number of square-roots to take. See reference for
16-
more details.
18+
control the accuracy of this approximation: m is the number of quadrature nodes
19+
to use and k the number of square-roots to take. See reference for more details.
1720
1821
Implementation uses the expression
19-
H(X) = -trace( D_{op}(X||I) )
22+
23+
H(X) = -trace( D_{op}(X||I) )
24+
2025
where D_{op} is the operator relative entropy:
21-
D_{op}(X||Y) = X^{1/2}*logm(X^{1/2} Y^{-1} X^{1/2})*X^{1/2}
2226
23-
All expressions and atoms are subtypes of AbstractExpr.
24-
Please read expressions.jl first.
27+
D_{op}(X||Y) = X^{1/2}*logm(X^{1/2} Y^{-1} X^{1/2})*X^{1/2}
28+
29+
## Reference
2530
26-
REFERENCE
27-
Ported from CVXQUAD which is based on the paper: "Lieb's concavity
28-
theorem, matrix geometric means and semidefinite optimization" by Hamza
29-
Fawzi and James Saunderson (arXiv:1512.03401)
31+
Ported from CVXQUAD which is based on the paper: "Lieb's concavity theorem,
32+
matrix geometric means and semidefinite optimization" by Hamza Fawzi and James
33+
Saunderson (arXiv:1512.03401)
3034
"""
3135
mutable struct QuantumEntropyAtom <: AbstractExpr
3236
children::Tuple{AbstractExpr}
@@ -35,12 +39,11 @@ mutable struct QuantumEntropyAtom <: AbstractExpr
3539
k::Integer
3640

3741
function QuantumEntropyAtom(X::AbstractExpr, m::Integer, k::Integer)
38-
children = (X,)
39-
n = size(X)[1]
42+
n = size(X, 1)
4043
if size(X) != (n, n)
4144
throw(DimensionMismatch("X must be square"))
4245
end
43-
return new(children, (1, 1), m, k)
46+
return new((X,), (1, 1), m, k)
4447
end
4548
end
4649

@@ -52,9 +55,7 @@ monotonicity(::QuantumEntropyAtom) = (NoMonotonicity(),)
5255

5356
curvature(::QuantumEntropyAtom) = ConcaveVexity()
5457

55-
function evaluate(atom::QuantumEntropyAtom)
56-
return quantum_entropy(evaluate(atom.children[1]))
57-
end
58+
evaluate(atom::QuantumEntropyAtom) = quantum_entropy(evaluate(atom.children[1]))
5859

5960
function quantum_entropy(X::AbstractExpr, m::Integer = 3, k::Integer = 3)
6061
return QuantumEntropyAtom(X, m, k)
@@ -68,21 +69,19 @@ function quantum_entropy(
6869
return -quantum_relative_entropy(X, Matrix(1.0 * LinearAlgebra.I, size(X)))
6970
end
7071

71-
function new_conic_form!(context::Context, atom::QuantumEntropyAtom)
72-
X = atom.children[1]
73-
n = size(X, 1)
74-
eye = Matrix(1.0 * LinearAlgebra.I, n, n)
72+
function new_conic_form!(
73+
context::Context{T},
74+
atom::QuantumEntropyAtom,
75+
) where {T}
76+
X = only(atom.children)
7577
add_constraint!(context, X 0)
7678
τ = if sign(X) == ComplexSign()
77-
ComplexVariable(n, n)
79+
ComplexVariable(size(X))
7880
else
79-
Variable(n, n)
81+
Variable(size(X))
8082
end
81-
add_constraint!(
82-
context,
83-
τ in RelativeEntropyEpiCone(X, eye, atom.m, atom.k),
84-
)
83+
I = Matrix(one(T) * LinearAlgebra.I(size(X, 1)))
84+
add_constraint!(context, τ in RelativeEntropyEpiCone(X, I, atom.m, atom.k))
8585
# It's already a real mathematically, but need to make it a real type.
86-
τ = real(-LinearAlgebra.tr(τ))
87-
return conic_form!(context, minimize(τ))
86+
return conic_form!(context, real(-LinearAlgebra.tr(τ)))
8887
end

src/atoms/QuantumRelativeEntropyAtom.jl

Lines changed: 77 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,36 @@
55
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
66

77
"""
8-
quantum_relative_entropy returns LinearAlgebra.tr(A*(log(A)-log(B))) where A and B
9-
are positive semidefinite matrices. Note this function uses logarithm
10-
base e, not base 2, so return value is in units of nats, not bits.
8+
QuantumRelativeEntropy1Atom(
9+
A::AbstractExpr,
10+
B::AbstractExpr,
11+
m::Integer,
12+
k::Integer,
13+
)
1114
12-
Quantum relative entropy is convex (jointly) in (A,B). This function
13-
implements the semidefinite programming approximation given in the reference
14-
below. Parameters m and k control the accuracy of this approximation: m is
15-
the number of quadrature nodes to use and k the number of square-roots to
16-
take. See reference for more details.
15+
quantum_relative_entropy returns LinearAlgebra.tr(A*(log(A)-log(B))) where A and
16+
B are positive semidefinite matrices.
17+
18+
Note this function uses logarithm base e, not base 2, so return value is in
19+
units of nats, not bits.
20+
21+
Quantum relative entropy is convex (jointly) in (A, B). This function implements
22+
the semidefinite programming approximation given in the reference below.
23+
Parameters m and k control the accuracy of this approximation: m is the number
24+
of quadrature nodes to use and k the number of square-roots to take. See
25+
reference for more details.
1726
1827
Implementation uses the expression
19-
D(A||B) = e'*D_{op} (A \\otimes I || I \\otimes B) )*e
28+
29+
D(A||B) = e'*D_{op} (A \\otimes I || I \\otimes B) )*e
30+
2031
where D_{op} is the operator relative entropy and e = vec(Matrix(I, n, n)).
2132
22-
All expressions and atoms are subtypes of AbstractExpr.
23-
Please read expressions.jl first.
33+
## Reference
2434
25-
REFERENCE
26-
Ported from CVXQUAD which is based on the paper: "Lieb's concavity
27-
theorem, matrix geometric means and semidefinite optimization" by Hamza
28-
Fawzi and James Saunderson (arXiv:1512.03401)
35+
Ported from CVXQUAD which is based on the paper: "Lieb's concavity theorem,
36+
matrix geometric means and semidefinite optimization" by Hamza Fawzi and James
37+
Saunderson (arXiv:1512.03401)
2938
"""
3039
mutable struct QuantumRelativeEntropy1Atom <: AbstractExpr
3140
children::Tuple{AbstractExpr,AbstractExpr}
@@ -39,22 +48,60 @@ mutable struct QuantumRelativeEntropy1Atom <: AbstractExpr
3948
m::Integer,
4049
k::Integer,
4150
)
42-
children = (A, B)
51+
n = size(A, 1)
4352
if size(A) != size(B)
4453
throw(DimensionMismatch("A and B must be the same size"))
45-
end
46-
n = size(A)[1]
47-
if size(A) != (n, n)
54+
elseif size(A) != (n, n)
4855
throw(DimensionMismatch("A and B must be square"))
4956
end
50-
return new(children, (1, 1), m, k)
57+
return new((A, B), (1, 1), m, k)
5158
end
5259
end
5360

5461
function head(io::IO, ::QuantumRelativeEntropy1Atom)
5562
return print(io, "quantum_relative_entropy")
5663
end
5764

65+
Base.sign(::QuantumRelativeEntropy1Atom) = Positive()
66+
67+
function monotonicity(::QuantumRelativeEntropy1Atom)
68+
return (NoMonotonicity(), NoMonotonicity())
69+
end
70+
71+
curvature(::QuantumRelativeEntropy1Atom) = ConvexVexity()
72+
73+
function evaluate(atom::QuantumRelativeEntropy1Atom)
74+
A = evaluate(atom.children[1])
75+
B = evaluate(atom.children[2])
76+
return quantum_relative_entropy(A, B)
77+
end
78+
79+
function quantum_relative_entropy(
80+
A::AbstractExpr,
81+
B::AbstractExpr,
82+
m::Integer = 3,
83+
k::Integer = 3,
84+
)
85+
return QuantumRelativeEntropy1Atom(A, B, m, k)
86+
end
87+
88+
function new_conic_form!(
89+
context::Context{T},
90+
atom::QuantumRelativeEntropy1Atom,
91+
) where {T}
92+
A, B = atom.children[1], atom.children[2]
93+
add_constraint!(context, A 0)
94+
add_constraint!(context, B 0)
95+
I = Matrix(one(T) * LinearAlgebra.I(size(A, 1)))
96+
m, k, e = atom.m, atom.k, vec(I)
97+
τ = Variable()
98+
add_constraint!(
99+
context,
100+
τ in RelativeEntropyEpiCone(kron(A, I), kron(I, conj(B)), m, k, e),
101+
)
102+
return conic_form!(context, τ)
103+
end
104+
58105
mutable struct QuantumRelativeEntropy2Atom <: AbstractExpr
59106
children::Tuple{AbstractExpr}
60107
size::Tuple{Int,Int}
@@ -71,16 +118,12 @@ mutable struct QuantumRelativeEntropy2Atom <: AbstractExpr
71118
k::Integer,
72119
nullspace_tol::Real,
73120
)
74-
children = (A,)
75-
121+
n = size(A, 1)
76122
if size(A) != size(B)
77123
throw(DimensionMismatch("A and B must be the same size"))
78-
end
79-
n = size(A)[1]
80-
if size(A) != (n, n)
124+
elseif size(A) != (n, n)
81125
throw(DimensionMismatch("A and B must be square"))
82-
end
83-
if norm(B - B') > nullspace_tol
126+
elseif norm(B - B') > nullspace_tol
84127
throw(DomainError(B, "B must be Hermitian"))
85128
end
86129
# nullspace of A must contain nullspace of B
@@ -90,52 +133,25 @@ mutable struct QuantumRelativeEntropy2Atom <: AbstractExpr
90133
end
91134
J = U'[v.>nullspace_tol, :]
92135
K = U'[v.<nullspace_tol, :]
93-
return new(children, (1, 1), m, k, B, J, K)
136+
return new((A,), (1, 1), m, k, B, J, K)
94137
end
95138
end
96139

97140
function head(io::IO, ::QuantumRelativeEntropy2Atom)
98141
return print(io, "quantum_relative_entropy")
99142
end
100143

101-
function Base.sign(
102-
::Union{QuantumRelativeEntropy1Atom,QuantumRelativeEntropy2Atom},
103-
)
104-
return Positive()
105-
end
106-
107-
function monotonicity(::QuantumRelativeEntropy1Atom)
108-
return (NoMonotonicity(), NoMonotonicity())
109-
end
144+
Base.sign(::QuantumRelativeEntropy2Atom) = Positive()
110145

111146
monotonicity(::QuantumRelativeEntropy2Atom) = (NoMonotonicity(),)
112147

113-
function curvature(
114-
::Union{QuantumRelativeEntropy1Atom,QuantumRelativeEntropy2Atom},
115-
)
116-
return ConvexVexity()
117-
end
118-
119-
function evaluate(atom::QuantumRelativeEntropy1Atom)
120-
A = evaluate(atom.children[1])
121-
B = evaluate(atom.children[2])
122-
return quantum_relative_entropy(A, B)
123-
end
148+
curvature(::QuantumRelativeEntropy2Atom) = ConvexVexity()
124149

125150
function evaluate(atom::QuantumRelativeEntropy2Atom)
126151
A = evaluate(atom.children[1])
127152
return quantum_relative_entropy(A, atom.B)
128153
end
129154

130-
function quantum_relative_entropy(
131-
A::AbstractExpr,
132-
B::AbstractExpr,
133-
m::Integer = 3,
134-
k::Integer = 3,
135-
)
136-
return QuantumRelativeEntropy1Atom(A, B, m, k)
137-
end
138-
139155
function quantum_relative_entropy(
140156
A::AbstractExpr,
141157
B::Union{AbstractMatrix,Constant},
@@ -163,8 +179,7 @@ function quantum_relative_entropy(
163179
k::Integer = 0,
164180
nullspace_tol::Real = 1e-6,
165181
)
166-
A = evaluate(A)
167-
B = evaluate(B)
182+
A, B = evaluate(A), evaluate(B)
168183
if size(A) != size(B)
169184
throw(DimensionMismatch("A and B must be the same size"))
170185
elseif size(A) != (size(A)[1], size(A)[1])
@@ -190,31 +205,9 @@ function quantum_relative_entropy(
190205
return real(LinearAlgebra.tr(Ap * (log(Ap) - log(Bp))))
191206
end
192207

193-
function new_conic_form!(context::Context, atom::QuantumRelativeEntropy1Atom)
194-
A = atom.children[1]
195-
B = atom.children[2]
196-
m = atom.m
197-
k = atom.k
198-
n = size(A)[1]
199-
eye = Matrix(1.0 * LinearAlgebra.I, n, n)
200-
e = vec(eye)
201-
add_constraint!(context, A 0)
202-
add_constraint!(context, B 0)
203-
τ = Variable()
204-
add_constraint!(
205-
context,
206-
τ in RelativeEntropyEpiCone(kron(A, eye), kron(eye, conj(B)), m, k, e),
207-
)
208-
return conic_form!(context, minimize(τ))
209-
end
210-
211208
function new_conic_form!(context::Context, atom::QuantumRelativeEntropy2Atom)
212-
A = atom.children[1]
213-
B = atom.B
214-
J = atom.J
215-
K = atom.K
216-
m = atom.m
217-
k = atom.k
209+
A = only(atom.children)
210+
B, J, K, m, k = atom.B, atom.J, atom.K, atom.m, atom.k
218211
add_constraint!(context, A 0)
219212
τ = if length(K) > 0
220213
add_constraint!(context, K * A * K' == 0)
@@ -224,5 +217,5 @@ function new_conic_form!(context::Context, atom::QuantumRelativeEntropy2Atom)
224217
else
225218
-quantum_entropy(A, m, k) - real(LinearAlgebra.tr(A * log(B)))
226219
end
227-
return conic_form!(context, minimize(τ))
220+
return conic_form!(context, τ)
228221
end

0 commit comments

Comments
 (0)