Coverage for picos/constraints/con_quantrelentr.py: 94.34%
53 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"""Implementation of :class:`QuantRelEntropyConstraint`."""
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 QuantRelEntropyConstraint(Constraint):
33 """Upper bound on a quantum relative entropy.
35 This is the upper bound on a negative or relative quantum entropy, both
36 represented by :class:`~picos.expressions.NegativeQuantumEntropy`.
37 """
39 def __init__(self, divergence, upperBound):
40 """Construct a :class:`QuantRelEntropyConstraint`.
42 :param ~picos.expressions.NegativeQuantumEntropy divergence:
43 Constrained expression.
44 :param ~picos.expressions.AffineExpression upperBound:
45 Upper bound on the expression.
46 """
47 from ..expressions import AffineExpression, NegativeQuantumEntropy
49 assert isinstance(divergence, NegativeQuantumEntropy)
50 assert isinstance(upperBound, AffineExpression)
51 assert len(upperBound) == 1
53 self.divergence = divergence
54 self.upperBound = upperBound
56 required_type = self._required_type()
58 assert isinstance(divergence.X, required_type)
59 assert isinstance(divergence.Y, required_type) or divergence.Y is None
61 super(QuantRelEntropyConstraint, 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 r"""The :math:`Y` of the divergence, or :math:`\mathbb{I}`."""
76 from ..expressions import AffineExpression
78 if self.divergence.Y is None:
79 import numpy
81 return AffineExpression.from_constant(
82 numpy.eye(self.divergence.X.shape[0])
83 )
84 else:
85 return self.divergence.Y
87 Subtype = namedtuple("Subtype", ("argdim",))
89 def _subtype(self):
90 return self.Subtype(self.X.shape[0] ** 2)
92 @classmethod
93 def _cost(cls, subtype):
94 n = subtype.argdim
95 return n * (n + 1) + 1
97 def _expression_names(self):
98 yield "divergence"
99 yield "upperBound"
101 def _str(self):
102 return glyphs.le(self.divergence.string, self.upperBound.string)
104 def _get_size(self):
105 n = self.X.shape[0]
106 return (2 * n * n + 1, 1)
108 def _get_slack(self):
109 return self.upperBound.safe_value - self.divergence.safe_value
112class ComplexQuantRelEntropyConstraint(QuantRelEntropyConstraint):
113 """Upper bound on a complex quantum relative entropy."""
115 # TODO: Implement real conversion of quantum key distribution cone
117 def _required_type(self):
118 from ..expressions import ComplexAffineExpression
120 return ComplexAffineExpression
123# --------------------------------------
124__all__ = api_end(_API_START, globals())