Loading picos/constraints/con_renyientr.py +127 −281 Original line number Diff line number Diff line Loading @@ -28,12 +28,9 @@ from .constraint import Constraint _API_START = api_start(globals()) # ------------------------------- class TrRenyiEntrEpiConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ class BaseRenyiEntrConstraint(Constraint): """Base class representing general Renyi entropy constraints.""" def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. Loading @@ -43,29 +40,36 @@ class TrRenyiEntrEpiConstraint(Constraint): :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, TrRenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, TrRenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert (-1 <= divergence.alpha and divergence.alpha <= 0) or \ ( 1 <= divergence.alpha and divergence.alpha <= 2) assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.upperBound = upperBound required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrRenyiEntrEpiConstraint, self).__init__(divergence._typeStr) super(BaseRenyiEntrConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" Loading @@ -89,7 +93,7 @@ class TrRenyiEntrEpiConstraint(Constraint): @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 return n * (n + 1) + 2 def _expression_names(self): yield "divergence" Loading @@ -100,104 +104,51 @@ class TrRenyiEntrEpiConstraint(Constraint): def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) return (2 * n * n + 1, 2) def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value class RenyiEntrConstraint(BaseRenyiEntrConstraint): """Upper bound of Renyi entropies. class ComplexTrRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression class TrRenyiEntrHypoConstraint(Constraint): """Lower bound of a concave trace function for Renyi entropies. This is the lower bound on the trace of a concave matrix geometric mean, represented by :class:`~picos.expressions.TrRenyiEntropy`. This is the upper bound on Renyi entropies, represented by :class:`~picos.expressions.RenyiEntropy`. """ def __init__(self, divergence, lowerBound): """Construct a :class:`RenyiEntrEpiConstraint`. def _required_divergence(self): from ..expressions import RenyiEntropy :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression lowerBound: Lower bound on the expression. """ from ..expressions import AffineExpression, TrRenyiEntropy assert isinstance(divergence, TrRenyiEntropy) assert isinstance(lowerBound, AffineExpression) assert len(lowerBound) == 1 assert 0 <= divergence.alpha and divergence.alpha <= 1 self.divergence = divergence self.lowerBound = lowerBound return RenyiEntropy required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) def _is_valid_alpha(self, alpha): return 0 <= alpha and alpha < 1 super(TrRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) class ComplexRenyiEntrConstraint(RenyiEntrConstraint): """Upper bound of complex Renyi entropies.""" def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha Subtype = namedtuple("Subtype", ("argdim",)) def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 from ..expressions import ComplexAffineExpression def _expression_names(self): yield "divergence" yield "lowerBound" return ComplexAffineExpression def _str(self): return glyphs.ge(self.divergence.string, self.lowerBound.string) class SandRenyiEntrConstraint(BaseRenyiEntrConstraint): """Upper bound of sandwiched Renyi entropies. def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) This is the upper bound on sandwiched Renyi entropies, represented by :class:`~picos.expressions.SandRenyiEntropy`. """ def _get_slack(self): return self.lowerBound.safe_value - self.divergence.safe_value def _required_divergence(self): from ..expressions import SandRenyiEntropy return SandRenyiEntropy class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): """Lower bound of a complex concave trace function for Renyi entropies.""" def _is_valid_alpha(self, alpha): return 0.5 <= alpha and alpha < 1 # TODO: Implement real conversion of matrix geometric mean cone class ComplexSandRenyiEntrConstraint(SandRenyiEntrConstraint): """Upper bound of complex sandwiched Renyi entropies.""" def _required_type(self): from ..expressions import ComplexAffineExpression Loading @@ -205,51 +156,43 @@ class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): return ComplexAffineExpression class RenyiEntrConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. # ---------------- This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. class BaseTrRenyiEntrEpiConstraint(Constraint): """Base class representing general upper bound on convex trace functions used to define Renyi entropies. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. """Construct a :class:`BaseTrRenyiEntrEpiConstraint`. :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, RenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, RenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert 0 <= divergence.alpha and divergence.alpha < 1 assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.upperBound = upperBound required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(RenyiEntrConstraint, self).__init__(divergence._typeStr) super(BaseRenyiEntrConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" Loading Loading @@ -290,115 +233,66 @@ class RenyiEntrConstraint(Constraint): return self.upperBound.safe_value - self.divergence.safe_value class ComplexRenyiEntrConstraint(RenyiEntrConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------------------------- class TrRenyiEntrEpiConstraint(BaseTrRenyiEntrEpiConstraint): """Upper bound of trace function used to define Renyi entropies. class TrSandRenyiEntrEpiConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. This is the upper bound on convex trace functions used to define Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. def _required_divergence(self): from ..expressions import TrRenyiEntropy :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, TrSandRenyiEntropy assert isinstance(divergence, TrSandRenyiEntropy) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert (-1 <= divergence.alpha and divergence.alpha <= 0) or \ ( 1 <= divergence.alpha and divergence.alpha <= 2) self.divergence = divergence self.upperBound = upperBound return TrRenyiEntropy required_type = self._required_type() def _is_valid_alpha(self, alpha): return (-1 <= alpha and alpha <= 0) or (1 <= alpha and alpha <= 2) assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrSandRenyiEntrEpiConstraint, self).__init__(divergence._typeStr) class ComplexTrRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of complex convex trace function used to define Renyi entropies. """ def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha from ..expressions import ComplexAffineExpression Subtype = namedtuple("Subtype", ("argdim",)) return ComplexAffineExpression def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 class TrSandRenyiEntrEpiConstraint(BaseTrRenyiEntrEpiConstraint): """Upper bound of trace function used to define sandwiched Renyi entropies. def _expression_names(self): yield "divergence" yield "upperBound" def _str(self): return glyphs.le(self.divergence.string, self.upperBound.string) This is the upper bound on convex trace functions used to define sandwiched Renyi entropies, represented by :class:`~picos.expressions.TrSandRenyiEntropy`. """ def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) def _required_divergence(self): from ..expressions import TrSandRenyiEntropy def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value return TrSandRenyiEntropy def _is_valid_alpha(self, alpha): return 1 <= alpha and alpha <= 2 class ComplexTrSandRenyiEntrEpiConstraint(TrSandRenyiEntrEpiConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone class ComplexTrSandRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of complex convex trace function used to define sandwiched Renyi entropies. """ def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------- class TrSandRenyiEntrHypoConstraint(Constraint): """Lower bound of a concave trace function for Renyi entropies. This is the lower bound on the trace of a concave matrix geometric mean, represented by :class:`~picos.expressions.TrRenyiEntropy`. class BaseTrRenyiEntrHypoConstraint(Constraint): """Base class representing general lower bound on concave trace functions used to define Renyi entropies. """ def __init__(self, divergence, lowerBound): Loading @@ -409,12 +303,14 @@ class TrSandRenyiEntrHypoConstraint(Constraint): :param ~picos.expressions.AffineExpression lowerBound: Lower bound on the expression. """ from ..expressions import AffineExpression, TrSandRenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, TrSandRenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(lowerBound, AffineExpression) assert len(lowerBound) == 1 assert 0 <= divergence.alpha and divergence.alpha <= 1 assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.lowerBound = lowerBound Loading @@ -424,7 +320,7 @@ class TrSandRenyiEntrHypoConstraint(Constraint): assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrSandRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) super(BaseTrRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression Loading Loading @@ -470,109 +366,59 @@ class TrSandRenyiEntrHypoConstraint(Constraint): def _get_slack(self): return self.lowerBound.safe_value - self.divergence.safe_value class TrRenyiEntrHypoConstraint(BaseTrRenyiEntrHypoConstraint): """Lower bound of trace function used to define Renyi entropies. class ComplexTrSandRenyiEntrHypoConstraint(TrSandRenyiEntrHypoConstraint): """Lower bound of a complex concave trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression class SandRenyiEntrConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. This is the lower bound on concave trace functions used to define Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ from ..expressions import AffineExpression, SandRenyiEntropy assert isinstance(divergence, SandRenyiEntropy) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert 0 <= divergence.alpha and divergence.alpha < 1 def _required_divergence(self): from ..expressions import TrRenyiEntropy self.divergence = divergence self.upperBound = upperBound return TrRenyiEntropy required_type = self._required_type() def _is_valid_alpha(self, alpha): return 0 <= alpha and alpha <= 1 assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(SandRenyiEntrConstraint, self).__init__(divergence._typeStr) class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): """Lower bound of complex concave trace function used to define Renyi entropies. """ def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha from ..expressions import ComplexAffineExpression Subtype = namedtuple("Subtype", ("argdim",)) return ComplexAffineExpression def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 2 class TrSandRenyiEntrHypoConstraint(BaseTrRenyiEntrHypoConstraint): """Lower bound of trace function used to define sandwiched Renyi entropies. def _expression_names(self): yield "divergence" yield "upperBound" This is the lower bound on concave trace functions used to define sandwiched Renyi entropies, represented by :class:`~picos.expressions.TrSandRenyiEntropy`. """ def _str(self): return glyphs.le(self.divergence.string, self.upperBound.string) def _required_divergence(self): from ..expressions import TrSandRenyiEntropy def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 2) return TrSandRenyiEntropy def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value def _is_valid_alpha(self, alpha): return 0.5 <= alpha and alpha <= 1 class ComplexSandRenyiEntrConstraint(SandRenyiEntrConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone class ComplexTrSandRenyiEntrHypoConstraint(TrSandRenyiEntrHypoConstraint): """Lower bound of complex concave trace function used to define sandwiched Renyi entropies. """ def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------------------------------- __all__ = api_end(_API_START, globals()) picos/expressions/exp_renyientr.py +24 −19 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ class RenyiEntropy(BaseRenyiEntropy): \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[0, 1)`. .. warning:: Loading Loading @@ -259,7 +259,8 @@ class RenyiEntropy(BaseRenyiEntropy): Dy, Uy = numpy.linalg.eigh(Y) Y_beta = Uy @ numpy.diag(numpy.power(Dy, 1 - self._alpha)) @ Uy.conj().T s = numpy.log(numpy.sum(X_alpha * Y_beta.conj()).real) / (self._alpha - 1) t = numpy.sum(X_alpha * Y_beta.conj()).real s = numpy.log(t) / (self._alpha - 1) return cvxopt.matrix(s) Loading @@ -286,9 +287,10 @@ class SandRenyiEntropy(BaseRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \frac{1}{\alpha-1}\log(\operatorname{Tr}[ (Y^{\frac{1-\alpha}{2\alpha} X Y^{\frac{1-\alpha}{2\alpha})^\alpha ]), for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[1/2, 1)`. .. warning:: Loading Loading @@ -324,7 +326,8 @@ class SandRenyiEntropy(BaseRenyiEntropy): Dyxy = numpy.linalg.eigvalsh(Y_beta @ X @ Y_beta) s = numpy.log(numpy.sum(numpy.power(Dyxy, self._alpha))) / (self._alpha - 1) t = numpy.sum(numpy.power(Dyxy, self._alpha)) s = numpy.log(t) / (self._alpha - 1) return cvxopt.matrix(s) Loading @@ -350,7 +353,7 @@ class BaseTrRenyiEntropy(Expression): @convert_and_refine_arguments("X", "Y") def __init__(self, X, Y, alpha): """Construct an :class:`MatrixGeometricMean`. """Construct an :class:`BaseTrRenyiEntropy`. :param X: The affine expression :math:`X`. :type X: ~picos.expressions.AffineExpression Loading Loading @@ -487,22 +490,23 @@ class BaseTrRenyiEntropy(Expression): isconvex = (-1 <= subtype.alpha and subtype.alpha <= 0) or \ ( 1 <= subtype.alpha and subtype.alpha <= 2) isconcave = 0 <= subtype.alpha and subtype.alpha <= 1 argdim = subtype.argdim if relation == operator.__le__ and isconvex: if subtype.iscomplex or not issubclass( other.clstype, AffineExpression ): return cls._ComplexEpiConstraint().make_type(argdim=subtype.argdim) return cls._ComplexEpiConstraint().make_type(argdim=argdim) else: return cls._RealEpiConstraint().make_type(argdim=subtype.argdim) return cls._RealEpiConstraint().make_type(argdim=argdim) if relation == operator.__ge__ and isconcave: if subtype.iscomplex or not issubclass( other.clstype, AffineExpression ): return cls._ComplexHypoConstraint().make_type(argdim=subtype.argdim) return cls._ComplexHypoConstraint().make_type(argdim=argdim) else: return cls._RealHypoConstraint().make_type(argdim=subtype.argdim) return cls._RealHypoConstraint().make_type(argdim=argdim) return NotImplemented Loading Loading @@ -531,7 +535,7 @@ class BaseTrRenyiEntropy(Expression): return NotImplemented class TrRenyiEntropy(BaseTrRenyiEntropy): r"""Renyi entropy of an affine expression. r"""Trace Renyi entropy of an affine expression. :Definition: Loading @@ -540,7 +544,7 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \operatorname{Tr}[ X^\alpha Y^{1-\alpha} ], for some :math:`\alpha\in[-1, 2]`. Loading @@ -561,8 +565,8 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): def _get_strings(self): typeStr = "Trace Renyi Entropy" xStr = glyphs.power(self._X.string, str(self._alpha)) yStr = glyphs.power(self._Y.string, str(1 - self._alpha)) xStr = glyphs.power(self._X.string, "a") yStr = glyphs.power(self._Y.string, "1-a") symbStr = glyphs.trace(glyphs.mul(xStr, yStr)) return typeStr, symbStr Loading Loading @@ -606,7 +610,7 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): class TrSandRenyiEntropy(BaseTrRenyiEntropy): r"""Renyi entropy of an affine expression. r"""Trace sandwiched Renyi entropy of an affine expression. :Definition: Loading @@ -615,9 +619,10 @@ class TrSandRenyiEntropy(BaseTrRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \operatorname{Tr}[ (Y^{\frac{1-\alpha}{2\alpha} X Y^{\frac{1-\alpha}{2\alpha})^\alpha ], for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[1/2, 2]`. .. warning:: Loading @@ -631,8 +636,8 @@ class TrSandRenyiEntropy(BaseTrRenyiEntropy): # -------------------------------------------------------------------------- def _is_valid_alpha(self, alpha): if not (numpy.isscalar(alpha) and 0 <= alpha and alpha <= 2): raise TypeError("The exponent alpha must be a scalar in [0, 2]") if not (numpy.isscalar(alpha) and 0.5 <= alpha and alpha <= 2): raise TypeError("The exponent alpha must be a scalar in [1/2, 2]") def _get_strings(self): typeStr = "Trace Sandwiched Renyi Entropy" Loading picos/solvers/solver_qics.py +5 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
picos/constraints/con_renyientr.py +127 −281 Original line number Diff line number Diff line Loading @@ -28,12 +28,9 @@ from .constraint import Constraint _API_START = api_start(globals()) # ------------------------------- class TrRenyiEntrEpiConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ class BaseRenyiEntrConstraint(Constraint): """Base class representing general Renyi entropy constraints.""" def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. Loading @@ -43,29 +40,36 @@ class TrRenyiEntrEpiConstraint(Constraint): :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, TrRenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, TrRenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert (-1 <= divergence.alpha and divergence.alpha <= 0) or \ ( 1 <= divergence.alpha and divergence.alpha <= 2) assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.upperBound = upperBound required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrRenyiEntrEpiConstraint, self).__init__(divergence._typeStr) super(BaseRenyiEntrConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" Loading @@ -89,7 +93,7 @@ class TrRenyiEntrEpiConstraint(Constraint): @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 return n * (n + 1) + 2 def _expression_names(self): yield "divergence" Loading @@ -100,104 +104,51 @@ class TrRenyiEntrEpiConstraint(Constraint): def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) return (2 * n * n + 1, 2) def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value class RenyiEntrConstraint(BaseRenyiEntrConstraint): """Upper bound of Renyi entropies. class ComplexTrRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression class TrRenyiEntrHypoConstraint(Constraint): """Lower bound of a concave trace function for Renyi entropies. This is the lower bound on the trace of a concave matrix geometric mean, represented by :class:`~picos.expressions.TrRenyiEntropy`. This is the upper bound on Renyi entropies, represented by :class:`~picos.expressions.RenyiEntropy`. """ def __init__(self, divergence, lowerBound): """Construct a :class:`RenyiEntrEpiConstraint`. def _required_divergence(self): from ..expressions import RenyiEntropy :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression lowerBound: Lower bound on the expression. """ from ..expressions import AffineExpression, TrRenyiEntropy assert isinstance(divergence, TrRenyiEntropy) assert isinstance(lowerBound, AffineExpression) assert len(lowerBound) == 1 assert 0 <= divergence.alpha and divergence.alpha <= 1 self.divergence = divergence self.lowerBound = lowerBound return RenyiEntropy required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) def _is_valid_alpha(self, alpha): return 0 <= alpha and alpha < 1 super(TrRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) class ComplexRenyiEntrConstraint(RenyiEntrConstraint): """Upper bound of complex Renyi entropies.""" def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha Subtype = namedtuple("Subtype", ("argdim",)) def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 from ..expressions import ComplexAffineExpression def _expression_names(self): yield "divergence" yield "lowerBound" return ComplexAffineExpression def _str(self): return glyphs.ge(self.divergence.string, self.lowerBound.string) class SandRenyiEntrConstraint(BaseRenyiEntrConstraint): """Upper bound of sandwiched Renyi entropies. def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) This is the upper bound on sandwiched Renyi entropies, represented by :class:`~picos.expressions.SandRenyiEntropy`. """ def _get_slack(self): return self.lowerBound.safe_value - self.divergence.safe_value def _required_divergence(self): from ..expressions import SandRenyiEntropy return SandRenyiEntropy class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): """Lower bound of a complex concave trace function for Renyi entropies.""" def _is_valid_alpha(self, alpha): return 0.5 <= alpha and alpha < 1 # TODO: Implement real conversion of matrix geometric mean cone class ComplexSandRenyiEntrConstraint(SandRenyiEntrConstraint): """Upper bound of complex sandwiched Renyi entropies.""" def _required_type(self): from ..expressions import ComplexAffineExpression Loading @@ -205,51 +156,43 @@ class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): return ComplexAffineExpression class RenyiEntrConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. # ---------------- This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. class BaseTrRenyiEntrEpiConstraint(Constraint): """Base class representing general upper bound on convex trace functions used to define Renyi entropies. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. """Construct a :class:`BaseTrRenyiEntrEpiConstraint`. :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, RenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, RenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert 0 <= divergence.alpha and divergence.alpha < 1 assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.upperBound = upperBound required_type = self._required_type() assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(RenyiEntrConstraint, self).__init__(divergence._typeStr) super(BaseRenyiEntrConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" Loading Loading @@ -290,115 +233,66 @@ class RenyiEntrConstraint(Constraint): return self.upperBound.safe_value - self.divergence.safe_value class ComplexRenyiEntrConstraint(RenyiEntrConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------------------------- class TrRenyiEntrEpiConstraint(BaseTrRenyiEntrEpiConstraint): """Upper bound of trace function used to define Renyi entropies. class TrSandRenyiEntrEpiConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. This is the upper bound on convex trace functions used to define Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. def _required_divergence(self): from ..expressions import TrRenyiEntropy :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. """ from ..expressions import AffineExpression, TrSandRenyiEntropy assert isinstance(divergence, TrSandRenyiEntropy) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert (-1 <= divergence.alpha and divergence.alpha <= 0) or \ ( 1 <= divergence.alpha and divergence.alpha <= 2) self.divergence = divergence self.upperBound = upperBound return TrRenyiEntropy required_type = self._required_type() def _is_valid_alpha(self, alpha): return (-1 <= alpha and alpha <= 0) or (1 <= alpha and alpha <= 2) assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrSandRenyiEntrEpiConstraint, self).__init__(divergence._typeStr) class ComplexTrRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of complex convex trace function used to define Renyi entropies. """ def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha from ..expressions import ComplexAffineExpression Subtype = namedtuple("Subtype", ("argdim",)) return ComplexAffineExpression def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 1 class TrSandRenyiEntrEpiConstraint(BaseTrRenyiEntrEpiConstraint): """Upper bound of trace function used to define sandwiched Renyi entropies. def _expression_names(self): yield "divergence" yield "upperBound" def _str(self): return glyphs.le(self.divergence.string, self.upperBound.string) This is the upper bound on convex trace functions used to define sandwiched Renyi entropies, represented by :class:`~picos.expressions.TrSandRenyiEntropy`. """ def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 1) def _required_divergence(self): from ..expressions import TrSandRenyiEntropy def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value return TrSandRenyiEntropy def _is_valid_alpha(self, alpha): return 1 <= alpha and alpha <= 2 class ComplexTrSandRenyiEntrEpiConstraint(TrSandRenyiEntrEpiConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone class ComplexTrSandRenyiEntrEpiConstraint(TrRenyiEntrEpiConstraint): """Upper bound of complex convex trace function used to define sandwiched Renyi entropies. """ def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------- class TrSandRenyiEntrHypoConstraint(Constraint): """Lower bound of a concave trace function for Renyi entropies. This is the lower bound on the trace of a concave matrix geometric mean, represented by :class:`~picos.expressions.TrRenyiEntropy`. class BaseTrRenyiEntrHypoConstraint(Constraint): """Base class representing general lower bound on concave trace functions used to define Renyi entropies. """ def __init__(self, divergence, lowerBound): Loading @@ -409,12 +303,14 @@ class TrSandRenyiEntrHypoConstraint(Constraint): :param ~picos.expressions.AffineExpression lowerBound: Lower bound on the expression. """ from ..expressions import AffineExpression, TrSandRenyiEntropy from ..expressions import AffineExpression required_divergence = self._required_divergence() required_type = self._required_type() assert isinstance(divergence, TrSandRenyiEntropy) assert isinstance(divergence, required_divergence) assert isinstance(lowerBound, AffineExpression) assert len(lowerBound) == 1 assert 0 <= divergence.alpha and divergence.alpha <= 1 assert self._is_valid_alpha(divergence.alpha) self.divergence = divergence self.lowerBound = lowerBound Loading @@ -424,7 +320,7 @@ class TrSandRenyiEntrHypoConstraint(Constraint): assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(TrSandRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) super(BaseTrRenyiEntrHypoConstraint, self).__init__(divergence._typeStr) def _required_type(self): from ..expressions import AffineExpression Loading Loading @@ -470,109 +366,59 @@ class TrSandRenyiEntrHypoConstraint(Constraint): def _get_slack(self): return self.lowerBound.safe_value - self.divergence.safe_value class TrRenyiEntrHypoConstraint(BaseTrRenyiEntrHypoConstraint): """Lower bound of trace function used to define Renyi entropies. class ComplexTrSandRenyiEntrHypoConstraint(TrSandRenyiEntrHypoConstraint): """Lower bound of a complex concave trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression class SandRenyiEntrConstraint(Constraint): """Upper bound of a convex trace function for Renyi entropies. This is the upper bound on a convex trace function for Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ def __init__(self, divergence, upperBound): """Construct a :class:`TrRenyiEntrEpiConstraint`. :param ~picos.expressions.TrRenyiEntropy divergence: Constrained expression. :param ~picos.expressions.AffineExpression upperBound: Upper bound on the expression. This is the lower bound on concave trace functions used to define Renyi entropies, represented by :class:`~picos.expressions.TrRenyiEntropy`. """ from ..expressions import AffineExpression, SandRenyiEntropy assert isinstance(divergence, SandRenyiEntropy) assert isinstance(upperBound, AffineExpression) assert len(upperBound) == 1 assert 0 <= divergence.alpha and divergence.alpha < 1 def _required_divergence(self): from ..expressions import TrRenyiEntropy self.divergence = divergence self.upperBound = upperBound return TrRenyiEntropy required_type = self._required_type() def _is_valid_alpha(self, alpha): return 0 <= alpha and alpha <= 1 assert isinstance(divergence.X, required_type) assert isinstance(divergence.Y, required_type) super(SandRenyiEntrConstraint, self).__init__(divergence._typeStr) class ComplexTrRenyiEntrHypoConstraint(TrRenyiEntrHypoConstraint): """Lower bound of complex concave trace function used to define Renyi entropies. """ def _required_type(self): from ..expressions import AffineExpression return AffineExpression @property def u(self): """The :math:`u` of the divergence.""" # TODO: Allow u to be an arbitrary affine expression from ..expressions import Constant return Constant(1.0) @property def X(self): """The :math:`X` of the divergence.""" return self.divergence.X @cached_property def Y(self): """The :math:`Y` of the divergence.""" return self.divergence.Y @cached_property def alpha(self): r"""The parameter :math:`\alpha`.""" return self.divergence.alpha from ..expressions import ComplexAffineExpression Subtype = namedtuple("Subtype", ("argdim",)) return ComplexAffineExpression def _subtype(self): return self.Subtype(self.X.shape[0] ** 2) @classmethod def _cost(cls, subtype): n = subtype.argdim return n * (n + 1) + 2 class TrSandRenyiEntrHypoConstraint(BaseTrRenyiEntrHypoConstraint): """Lower bound of trace function used to define sandwiched Renyi entropies. def _expression_names(self): yield "divergence" yield "upperBound" This is the lower bound on concave trace functions used to define sandwiched Renyi entropies, represented by :class:`~picos.expressions.TrSandRenyiEntropy`. """ def _str(self): return glyphs.le(self.divergence.string, self.upperBound.string) def _required_divergence(self): from ..expressions import TrSandRenyiEntropy def _get_size(self): n = self.X.shape[0] return (2 * n * n + 1, 2) return TrSandRenyiEntropy def _get_slack(self): return self.upperBound.safe_value - self.divergence.safe_value def _is_valid_alpha(self, alpha): return 0.5 <= alpha and alpha <= 1 class ComplexSandRenyiEntrConstraint(SandRenyiEntrConstraint): """Upper bound of trace of a complex convex trace function for Renyi entropies.""" # TODO: Implement real conversion of matrix geometric mean cone class ComplexTrSandRenyiEntrHypoConstraint(TrSandRenyiEntrHypoConstraint): """Lower bound of complex concave trace function used to define sandwiched Renyi entropies. """ def _required_type(self): from ..expressions import ComplexAffineExpression return ComplexAffineExpression # -------------------------------------- __all__ = api_end(_API_START, globals())
picos/expressions/exp_renyientr.py +24 −19 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ class RenyiEntropy(BaseRenyiEntropy): \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[0, 1)`. .. warning:: Loading Loading @@ -259,7 +259,8 @@ class RenyiEntropy(BaseRenyiEntropy): Dy, Uy = numpy.linalg.eigh(Y) Y_beta = Uy @ numpy.diag(numpy.power(Dy, 1 - self._alpha)) @ Uy.conj().T s = numpy.log(numpy.sum(X_alpha * Y_beta.conj()).real) / (self._alpha - 1) t = numpy.sum(X_alpha * Y_beta.conj()).real s = numpy.log(t) / (self._alpha - 1) return cvxopt.matrix(s) Loading @@ -286,9 +287,10 @@ class SandRenyiEntropy(BaseRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \frac{1}{\alpha-1}\log(\operatorname{Tr}[ (Y^{\frac{1-\alpha}{2\alpha} X Y^{\frac{1-\alpha}{2\alpha})^\alpha ]), for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[1/2, 1)`. .. warning:: Loading Loading @@ -324,7 +326,8 @@ class SandRenyiEntropy(BaseRenyiEntropy): Dyxy = numpy.linalg.eigvalsh(Y_beta @ X @ Y_beta) s = numpy.log(numpy.sum(numpy.power(Dyxy, self._alpha))) / (self._alpha - 1) t = numpy.sum(numpy.power(Dyxy, self._alpha)) s = numpy.log(t) / (self._alpha - 1) return cvxopt.matrix(s) Loading @@ -350,7 +353,7 @@ class BaseTrRenyiEntropy(Expression): @convert_and_refine_arguments("X", "Y") def __init__(self, X, Y, alpha): """Construct an :class:`MatrixGeometricMean`. """Construct an :class:`BaseTrRenyiEntropy`. :param X: The affine expression :math:`X`. :type X: ~picos.expressions.AffineExpression Loading Loading @@ -487,22 +490,23 @@ class BaseTrRenyiEntropy(Expression): isconvex = (-1 <= subtype.alpha and subtype.alpha <= 0) or \ ( 1 <= subtype.alpha and subtype.alpha <= 2) isconcave = 0 <= subtype.alpha and subtype.alpha <= 1 argdim = subtype.argdim if relation == operator.__le__ and isconvex: if subtype.iscomplex or not issubclass( other.clstype, AffineExpression ): return cls._ComplexEpiConstraint().make_type(argdim=subtype.argdim) return cls._ComplexEpiConstraint().make_type(argdim=argdim) else: return cls._RealEpiConstraint().make_type(argdim=subtype.argdim) return cls._RealEpiConstraint().make_type(argdim=argdim) if relation == operator.__ge__ and isconcave: if subtype.iscomplex or not issubclass( other.clstype, AffineExpression ): return cls._ComplexHypoConstraint().make_type(argdim=subtype.argdim) return cls._ComplexHypoConstraint().make_type(argdim=argdim) else: return cls._RealHypoConstraint().make_type(argdim=subtype.argdim) return cls._RealHypoConstraint().make_type(argdim=argdim) return NotImplemented Loading Loading @@ -531,7 +535,7 @@ class BaseTrRenyiEntropy(Expression): return NotImplemented class TrRenyiEntropy(BaseTrRenyiEntropy): r"""Renyi entropy of an affine expression. r"""Trace Renyi entropy of an affine expression. :Definition: Loading @@ -540,7 +544,7 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \operatorname{Tr}[ X^\alpha Y^{1-\alpha} ], for some :math:`\alpha\in[-1, 2]`. Loading @@ -561,8 +565,8 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): def _get_strings(self): typeStr = "Trace Renyi Entropy" xStr = glyphs.power(self._X.string, str(self._alpha)) yStr = glyphs.power(self._Y.string, str(1 - self._alpha)) xStr = glyphs.power(self._X.string, "a") yStr = glyphs.power(self._Y.string, "1-a") symbStr = glyphs.trace(glyphs.mul(xStr, yStr)) return typeStr, symbStr Loading Loading @@ -606,7 +610,7 @@ class TrRenyiEntropy(BaseTrRenyiEntropy): class TrSandRenyiEntropy(BaseTrRenyiEntropy): r"""Renyi entropy of an affine expression. r"""Trace sandwiched Renyi entropy of an affine expression. :Definition: Loading @@ -615,9 +619,10 @@ class TrSandRenyiEntropy(BaseTrRenyiEntropy): .. math:: \frac{1}{\alpha-1}\log(\operatorname{Tr}[ X^\alpha Y^{1-\alpha} ]), \operatorname{Tr}[ (Y^{\frac{1-\alpha}{2\alpha} X Y^{\frac{1-\alpha}{2\alpha})^\alpha ], for some :math:`\alpha\in[-1, 2]`. for some :math:`\alpha\in[1/2, 2]`. .. warning:: Loading @@ -631,8 +636,8 @@ class TrSandRenyiEntropy(BaseTrRenyiEntropy): # -------------------------------------------------------------------------- def _is_valid_alpha(self, alpha): if not (numpy.isscalar(alpha) and 0 <= alpha and alpha <= 2): raise TypeError("The exponent alpha must be a scalar in [0, 2]") if not (numpy.isscalar(alpha) and 0.5 <= alpha and alpha <= 2): raise TypeError("The exponent alpha must be a scalar in [1/2, 2]") def _get_strings(self): typeStr = "Trace Sandwiched Renyi Entropy" Loading
picos/solvers/solver_qics.py +5 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes