Skip to content

Commit 96904be

Browse files
blegatodow
andauthored
Refactor GeomMeanEpiCone into GenericConstraint (#604)
* Refactor GeomMeanEpiCone into GenericConstraint * Fixes * Fix tests * Update * Update * eye -> I * Revert Tuple approach * Fix format * Update constant.jl * Update * Remove sdp_geom_mean_epicone_argcheck * Update test/test_constraints.jl Co-authored-by: Benoît Legat <[email protected]> * Update --------- Co-authored-by: odow <[email protected]> Co-authored-by: Oscar Dowson <[email protected]>
1 parent 5d5724d commit 96904be

File tree

9 files changed

+180
-249
lines changed

9 files changed

+180
-249
lines changed

docs/src/manual/operations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ solver (including SCS and Mosek).
117117
| `matrixfrac(x, P)` | $x^TP^{-1}x$ | convex | not monotonic | IC: P is positive semidefinite |
118118
| `sumlargesteigs(x, k)` | sum of top $k$ eigenvalues of $x$ | convex | not monotonic | IC: P symmetric |
119119
| `T in GeomMeanHypoCone(A, B, t)` | $T \preceq A \#_t B = A^{1/2} (A^{-1/2} B A^{-1/2})^t A^{1/2}$ | concave | increasing | IC: $A \succeq 0$, $B \succeq 0$, $t \in [0,1]$ |
120-
| `T in GeomMeanEpiCone(A, B, t)` | $T \succeq A \#_t B = A^{1/2} (A^{-1/2} B A^{-1/2})^t A^{1/2}$ | convex | not monotonic | IC: $A \succeq 0$, $B \succeq 0$, $t \in [-1, 0] \cup [1, 2]$ |
120+
| `Convex.GenericConstraint((T, A, B), GeometricMeanEpiConeSquare(t, size(T, 1)))` | $T \succeq A \#_t B = A^{1/2} (A^{-1/2} B A^{-1/2})^t A^{1/2}$ | convex | not monotonic | IC: $A \succeq 0$, $B \succeq 0$, $t \in [-1, 0] \cup [1, 2]$ |
121121
| `quantum_entropy(X)` | $-\textrm{Tr}(X \log X)$ | concave | not monotonic | IC: $X \succeq 0$; uses natural log |
122122
| `quantum_relative_entropy(A, B)` | $\textrm{Tr}(A \log A - A \log B)$ | convex | not monotonic | IC: $A \succeq 0$, $B \succeq 0$; uses natural log |
123123
| `trace_logm(X, C)` | $\textrm{Tr}(C \log X)$ | concave in X | not monotonic | IC: $X \succeq 0$, $C \succeq 0$, $C$ constant; uses natural log |

src/Convex.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export conv,
4545
sumsmallest,
4646
sumsquares,
4747
GeomMeanHypoCone,
48-
GeomMeanEpiCone,
48+
GeometricMeanEpiConeSquare,
4949
RelativeEntropyEpiCone,
5050
quantum_relative_entropy,
5151
quantum_entropy,

src/atoms/TraceMpowerAtom.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,13 @@ function new_conic_form!(context::Context{T}, atom::TraceMpowerAtom) where {T}
9595
if 0 <= atom.t <= 1
9696
add_constraint!(context, tmp in GeomMeanHypoCone(I, A, atom.t, false))
9797
else
98-
add_constraint!(context, tmp in GeomMeanEpiCone(I, A, atom.t, false))
98+
add_constraint!(
99+
context,
100+
Convex.GenericConstraint(
101+
(tmp, I, A),
102+
GeometricMeanEpiConeSquare(atom.t, size(A, 1)),
103+
),
104+
)
99105
end
100106
# It's already a real mathematically, but Convex doesn't know it
101107
return conic_form!(context, real(LinearAlgebra.tr(atom.C * tmp)))

src/constraints/GeomMeanEpiCone.jl

Lines changed: 0 additions & 166 deletions
This file was deleted.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Copyright (c) 2014: Madeleine Udell and contributors
2+
# Copyright (c) 2021: Hamza Fawzi
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+
GeometricMeanEpiConeSquare(t::Rational, side_dimension::Int)
9+
10+
The constraint `(T, A, B) in GeometricMeanEpiConeSquare(t, side_dimension)`
11+
constrains T to
12+
13+
A #_t B ⪯ T
14+
15+
where:
16+
17+
* A #_t B is the t-weighted geometric mean of A and B:
18+
A^{1/2} (A^{-1/2} B A^{-1/2})^t A^{1/2}
19+
* Parameter t must be in [-1, 0] or [1, 2].
20+
* Constraints A ⪰ 0, B ⪰ 0 are added.
21+
22+
## Reference
23+
24+
Ported from CVXQUAD which is based on the paper: "Lieb's concavity theorem,
25+
matrix geometric means and semidefinite optimization" by Hamza Fawzi and James
26+
Saunderson (arXiv:1512.03401)
27+
"""
28+
struct GeometricMeanEpiConeSquare <: MOI.AbstractVectorSet
29+
t::Rational
30+
side_dimension::Int
31+
32+
function GeometricMeanEpiConeSquare(t::Rational, side_dimension::Int)
33+
if !(-1 <= t <= 0 || 1 <= t <= 2)
34+
throw(DomainError(t, "t must be in the range [-1, 0] or [1, 2]"))
35+
end
36+
return new(t, side_dimension)
37+
end
38+
end
39+
40+
MOI.dimension(set::GeometricMeanEpiConeSquare) = 3 * set.side_dimension^2
41+
42+
function head(io::IO, ::GeometricMeanEpiConeSquare)
43+
return print(io, "GeometricMeanEpiConeSquare")
44+
end
45+
46+
function GenericConstraint(func::Tuple, set::GeometricMeanEpiConeSquare)
47+
for f in func
48+
n = LinearAlgebra.checksquare(f)
49+
if n != set.side_dimension
50+
throw(
51+
DimensionMismatch(
52+
"Matrix of side dimension `$n` does not match set of side dimension `$(set.side_dimension)`",
53+
),
54+
)
55+
end
56+
end
57+
return GenericConstraint(vcat(vec.(func)...), set)
58+
end
59+
60+
function _get_matrices(c::GenericConstraint{GeometricMeanEpiConeSquare})
61+
n = c.set.side_dimension
62+
d = n^2
63+
T = reshape(c.child[1:d], n, n)
64+
A = reshape(c.child[d.+(1:d)], n, n)
65+
B = reshape(c.child[2d.+(1:d)], n, n)
66+
return T, A, B
67+
end
68+
69+
# For t ∈ [-1, 0] ∪ [1, 2] the t-weighted matrix geometric mean is matrix convex
70+
# (arxiv:1512.03401).
71+
# So if A and B are convex sets, then T ⪰ A #_t B will be a convex set.
72+
function vexity(constraint::GenericConstraint{GeometricMeanEpiConeSquare})
73+
T, A, B = _get_matrices(constraint)
74+
if vexity(A) in (ConcaveVexity(), NotDcp()) ||
75+
vexity(B) in (ConcaveVexity(), NotDcp())
76+
return NotDcp()
77+
end
78+
return ConvexVexity() + -vexity(T)
79+
end
80+
81+
function _add_constraint!(
82+
context::Context,
83+
constraint::GenericConstraint{GeometricMeanEpiConeSquare},
84+
)
85+
T, A, B = _get_matrices(constraint)
86+
t = constraint.set.t
87+
Z = if sign(constraint.child) == ComplexSign()
88+
HermitianSemidefinite(size(A, 1))
89+
else
90+
Semidefinite(size(A, 1))
91+
end
92+
if t <= 0
93+
add_constraint!(context, [T A; A Z] 0)
94+
add_constraint!(context, Z in GeomMeanHypoCone(A, B, -t, false))
95+
else
96+
# range of t checked in GeometricMeanEpiConeSquare constructor.
97+
@assert t >= 1
98+
add_constraint!(context, [T B; B Z] 0)
99+
add_constraint!(context, Z in GeomMeanHypoCone(A, B, 2 - t, false))
100+
end
101+
return
102+
end

src/expressions.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ function vexity(x::AbstractExpr)
7575
return vex
7676
end
7777

78+
vexity(::Value) = ConstVexity()
79+
7880
evaluate(x) = output(x) # fallback
7981

8082
Base.size(x::AbstractExpr) = x.size

0 commit comments

Comments
 (0)