Coverage for picos/constraints/con_oprelentr.py: 92.31%
91 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-12 07:53 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-12 07:53 +0000
1# ------------------------------------------------------------------------------
2# Copyright (C) 2024 Kerry He
3#
4# This file is part of PICOS.
5#
6# PICOS is free software: you can redistribute it and/or modify it under the
7# terms of the GNU General Public License as published by the Free Software
8# Foundation, either version 3 of the License, or (at your option) any later
9# version.
10#
11# PICOS is distributed in the hope that it will be useful, but WITHOUT ANY
12# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program. If not, see <http://www.gnu.org/licenses/>.
17# ------------------------------------------------------------------------------
19"""Operator relative entropy constraints."""
21from collections import namedtuple
23from .. import glyphs
24from ..apidoc import api_end, api_start
25from ..caching import cached_property
26from .constraint import Constraint
28_API_START = api_start(globals())
29# -------------------------------
32class OpRelEntropyConstraint(Constraint):
33 """Epigraph of an operator relative entropy.
35 This is the upper bound, in the Loewner order, of an operator relative
36 entropy, represented by :class:`~picos.expressions.OperatorRelativeEntropy`.
37 """
39 def __init__(self, divergence, upperBound):
40 """Construct a :class:`OpRelEntropyConstraint`.
42 :param ~picos.expressions.OperatorRelativeEntropy divergence:
43 Constrained expression.
44 :param ~picos.expressions.AffineExpression upperBound:
45 Upper bound on the expression.
46 """
47 from ..expressions import OperatorRelativeEntropy
49 required_type = self._required_type()
51 assert isinstance(divergence, OperatorRelativeEntropy)
52 assert isinstance(upperBound, required_type)
53 assert divergence.shape == upperBound.shape
55 self.divergence = divergence
56 self.upperBound = upperBound
58 assert isinstance(divergence.X, required_type)
59 assert isinstance(divergence.Y, required_type)
61 super(OpRelEntropyConstraint, self).__init__(divergence._typeStr)
63 def _required_type(self):
64 from ..expressions import AffineExpression
66 return AffineExpression
68 @property
69 def X(self):
70 """The :math:`X` of the divergence."""
71 return self.divergence.X
73 @cached_property
74 def Y(self):
75 """The :math:`Y` of the divergence."""
76 return self.divergence.Y
78 Subtype = namedtuple("Subtype", ("argdim",))
80 def _subtype(self):
81 return self.Subtype(self.X.shape[0] ** 2)
83 @classmethod
84 def _cost(cls, subtype):
85 n = subtype.argdim
86 return n * (n + 1) // 2 * 3
88 def _expression_names(self):
89 yield "divergence"
90 yield "upperBound"
92 def _str(self):
93 return glyphs.psdle(self.divergence.string, self.upperBound.string)
95 def _get_size(self):
96 n = self.X.shape[0]
97 return (3 * n * n, 1)
99 def _get_slack(self):
100 return self.upperBound.safe_value - self.divergence.safe_value
103class ComplexOpRelEntropyConstraint(OpRelEntropyConstraint):
104 """Epigraph of a complex operator relative entropy."""
106 # TODO: Implement real conversion of operator relative entropy epigraph
108 def _required_type(self):
109 from ..expressions import ComplexAffineExpression
111 return ComplexAffineExpression
114class TrOpRelEntropyConstraint(Constraint):
115 """Upper bound of trace of operator relative entropy.
117 This is the upper bound on the trace of an operator relative entropy,
118 represented by :class:`~picos.expressions.TrOperatorRelativeEntropy`.
119 """
121 def __init__(self, divergence, upperBound):
122 """Construct a :class:`TrOpRelEntropyConstraint`.
124 :param ~picos.expressions.TrOperatorRelativeEntropy divergence:
125 Constrained expression.
126 :param ~picos.expressions.AffineExpression upperBound:
127 Upper bound on the expression.
128 """
129 from ..expressions import AffineExpression, TrOperatorRelativeEntropy
131 assert isinstance(divergence, TrOperatorRelativeEntropy)
132 assert isinstance(upperBound, AffineExpression)
133 assert len(upperBound) == 1
135 self.divergence = divergence
136 self.upperBound = upperBound
138 required_type = self._required_type()
140 assert isinstance(divergence.X, required_type)
141 assert isinstance(divergence.Y, required_type)
143 super(TrOpRelEntropyConstraint, self).__init__(divergence._typeStr)
145 def _required_type(self):
146 from ..expressions import AffineExpression
148 return AffineExpression
150 @property
151 def X(self):
152 """The :math:`X` of the divergence."""
153 return self.divergence.X
155 @cached_property
156 def Y(self):
157 """The :math:`Y` of the divergence."""
158 return self.divergence.Y
160 Subtype = namedtuple("Subtype", ("argdim",))
162 def _subtype(self):
163 return self.Subtype(self.X.shape[0] ** 2)
165 @classmethod
166 def _cost(cls, subtype):
167 n = subtype.argdim
168 return n * (n + 1) + 1
170 def _expression_names(self):
171 yield "divergence"
172 yield "upperBound"
174 def _str(self):
175 return glyphs.le(self.divergence.string, self.upperBound.string)
177 def _get_size(self):
178 n = self.X.shape[0]
179 return (2 * n * n + 1, 1)
181 def _get_slack(self):
182 return self.upperBound.safe_value - self.divergence.safe_value
185class ComplexTrOpRelEntropyConstraint(TrOpRelEntropyConstraint):
186 """Upper bound of trace of complex operator relative entropy."""
188 # TODO: Implement real conversion of operator relative entropy cone
190 def _required_type(self):
191 from ..expressions import ComplexAffineExpression
193 return ComplexAffineExpression
196# --------------------------------------
197__all__ = api_end(_API_START, globals())