Source code for toqito.state_opt.ppt_distinguishability

"""PPT distinguishability."""
import cvxpy
import numpy as np

from toqito.channels import partial_transpose
from .state_helper import __is_states_valid, __is_probs_valid


[docs] def ppt_distinguishability( states: list[np.ndarray], probs: list[float] = None, dist_method: str = "min-error", strategy: bool = False, ) -> float: r""" Compute probability of optimally distinguishing a state via PPT measurements [COS13]_. Implements the semidefinite program (SDP) whose optimal value is equal to the maximum probability of perfectly distinguishing orthogonal maximally entangled states using any PPT measurement; a measurement whose operators are positive under partial transpose. This SDP was explicitly provided in [COS13]_. One can specify the distinguishability method using the :code:`dist_method` argument. For :code:`dist_method = "min-error"`, this is the default method that yields the probability of distinguishing quantum states via PPT measurements that minimize the probability of error. For :code:`dist_method = "unambiguous"`, Alice and Bob never provide an incorrect answer, although it is possible that their answer is inconclusive. Examples ========== Consider the following Bell states: .. math:: \begin{equation} \begin{aligned} |\psi_0 \rangle = \frac{|00\rangle + |11\rangle}{\sqrt{2}}, &\quad |\psi_1 \rangle = \frac{|01\rangle + |10\rangle}{\sqrt{2}}, \\ |\psi_2 \rangle = \frac{|01\rangle - |10\rangle}{\sqrt{2}}, &\quad |\psi_3 \rangle = \frac{|00\rangle - |11\rangle}{\sqrt{2}}. \end{aligned} \end{equation} It was illustrated in [YDY12]_ that for the following set of states .. math:: \begin{equation} \begin{aligned} \rho_1^{(2)} &= |\psi_0 \rangle | \psi_0 \rangle \langle \psi_0 | \langle \psi_0 |, \\ \rho_2^{(2)} &= |\psi_1 \rangle | \psi_3 \rangle \langle \psi_1 | \langle \psi_3 |, \\ \rho_3^{(2)} &= |\psi_2 \rangle | \psi_3 \rangle \langle \psi_2 | \langle \psi_3 |, \\ \rho_4^{(2)} &= |\psi_3 \rangle | \psi_3 \rangle \langle \psi_3 | \langle \psi_3 |, \\ \end{aligned} \end{equation} that the optimal probability of distinguishing via a PPT measurement should yield :math:`7/8 \approx 0.875` as was proved in [YDY12]_. >>> from toqito.states import bell >>> from toqito.state_opt import ppt_distinguishability >>> # Bell vectors: >>> psi_0 = bell(0) >>> psi_1 = bell(2) >>> psi_2 = bell(3) >>> psi_3 = bell(1) >>> >>> # YDY vectors from [YDY12]_. >>> x_1 = np.kron(psi_0, psi_0) >>> x_2 = np.kron(psi_1, psi_3) >>> x_3 = np.kron(psi_2, psi_3) >>> x_4 = np.kron(psi_3, psi_3) >>> >>> # YDY density matrices. >>> rho_1 = x_1 * x_1.conj().T >>> rho_2 = x_2 * x_2.conj().T >>> rho_3 = x_3 * x_3.conj().T >>> rho_4 = x_4 * x_4.conj().T >>> >>> states = [rho_1, rho_2, rho_3, rho_4] >>> probs = [1 / 4, 1 / 4, 1 / 4, 1 / 4] >>> ppt_distinguishability(states, probs) 0.875 References ========== .. [COS13] Cosentino, Alessandro. "Positive-partial-transpose-indistinguishable states via semidefinite programming." Physical Review A 87.1 (2013): 012321. https://arxiv.org/abs/1205.1031 .. [YDY12] Yu, Nengkun, Runyao Duan, and Mingsheng Ying. "Four locally indistinguishable ququad-ququad orthogonal maximally entangled states." Physical review letters 109.2 (2012): 020506. https://arxiv.org/abs/1107.3224 :param states: A list of states provided as either matrices or vectors. :param dist_method: The method of distinguishing states. :param probs: Respective list of probabilities each state is selected. :param dist_method: Method of distinguishing to use. :param strategy: Returns strategy if :code:`True` and does not otherwise. :return: The optimal probability with which the states can be distinguished via PPT measurements. """ __is_states_valid(states) if probs is None: probs = [1 / len(states)] * len(states) __is_probs_valid(probs) _, dim_y = states[0].shape # The variable `states` is provided as a list of vectors. Transform them # into density matrices. if dim_y == 1: for i, state_ket in enumerate(states): states[i] = state_ket * state_ket.conj().T if strategy: return primal_problem(states, probs, dist_method) return dual_problem(states, probs, dist_method)
def primal_problem( states: list[np.ndarray], probs: list[float] = None, dist_method="min-error" ) -> float: r""" Calculate primal problem for PPT distinguishability. The minimum-error semidefinite program implemented is defined as: .. math:: \begin{equation} \begin{aligned} \text{maximize:} \quad & \sum_{j=1}^k \langle P_j, \rho_j \rangle \\ \text{subject to:} \quad & P_1 + \cdots + P_k = \mathbb{I}_{\mathcal{A}} \otimes \mathbb{I}_{\mathcal{B}}, \\ & P_1, \ldots, P_k \in \text{PPT}(\mathcal{A} : \mathcal{B}). \end{aligned} \end{equation} The unambiguous semidefinite program implemented is defined as: .. math:: \begin{equation} \begin{aligned} \text{maximize:} \quad & \sum_{j=1}^k \langle P_j, \rho_j \rangle \\ \text{subject to:} \quad & P_1 + \cdots + P_k = \mathbb{I}_{\mathcal{A}} \otimes \mathbb{I}_{\mathcal{B}}, \\ & P_1, \ldots, P_k \in \text{PPT}(\mathcal{A} : \mathcal{B}), \\ & \langle P_i, \rho_j \rangle = 0, \quad 1 \leq i, j \leq k, \quad i \not= j. \end{aligned} \end{equation} :param states: A list of states provided as either matrices or vectors. :param probs: Respective list of probabilities each state is selected. :param dist_method: Method of distinguishing to use. :return: The optimal value of the PPT primal problem SDP. """ dim_x, _ = states[0].shape obj_func = [] meas = [] constraints = [] dim = int(np.log2(dim_x)) dim_list = [2] * int(np.log2(dim_x)) sys_list = list(range(1, dim, 2)) # Unambiguous consists of k + 1 operators, where the outcome of the k+1^st corresponds to the # inconclusive answer. if dist_method == "unambiguous": for i in range(len(states) + 1): meas.append(cvxpy.Variable((dim_x, dim_x), PSD=True)) constraints.append(partial_transpose(meas[i], sys_list, dim_list) >> 0) for i, _ in enumerate(states): for j, _ in enumerate(states): if i != j: constraints.append(probs[j] * cvxpy.trace(states[j].conj().T @ meas[i]) == 0) # Minimize error of distinguishing via PPT measurements. elif dist_method == "min-error": for i, _ in enumerate(states): meas.append(cvxpy.Variable((dim_x, dim_x), PSD=True)) constraints.append(partial_transpose(meas[i], sys_list, dim_list) >> 0) for i, _ in enumerate(states): obj_func.append(probs[i] * cvxpy.trace(states[i].conj().T @ meas[i])) constraints.append(sum(meas) == np.identity(dim_x)) objective = cvxpy.Maximize(sum(obj_func)) problem = cvxpy.Problem(objective, constraints) sol_default = problem.solve() return sol_default def dual_problem( states: list[np.ndarray], probs: list[float] = None, dist_method="min-error" ) -> float: r""" Calculate dual problem for PPT distinguishability. The minimum-error semidefinite program implemented is defined as: .. math:: \begin{equation} \begin{aligned} \text{minimize:} \quad & \frac{1}{k} \text{Tr}(Y) \\ \text{subject to:} \quad & Y - \rho_j \geq \text{T}_{\mathcal{A}} (Q_j), \quad j = 1, \ldots, k, \\ & Y \in \text{Herm}(\mathcal{A} \otimes \mathcal{B}), \\ & Q_1, \ldots, Q_k \in \text{Pos}(\mathcal{A} \otimes \mathcal{B}). \end{aligned} \end{equation} The unambiguous semidefinite program implemented is defined as: .. math:: \begin{equation} \begin{aligned} \text{minimize:} \quad & \frac{1}{k} \text{Tr}(Y) \\ \text{subject to:} \quad & Y - \rho_j + \sum_{\substack{i \leq i \leq k \\ i \not= j}} y_{i,j} \rho_i \geq T_{\mathcal{A}}(Q_j), \quad j = 1, \ldots, k, \\ & Y \geq T_{\mathcal{A}}(Q_{k+1}), \\ & Y \in \text{Herm}(\mathcal{A} \otimes \mathcal{B}), \\ & Q_1, \ldots, Q_k \in \text{Pos}(\mathcal{A} \otimes \mathcal{B}), \\ & y_{i,j} \in \mathcal{R}. \quad 1 \leq i, j \leq k, \quad i \not= j. \end{aligned} \end{equation} :param states: A list of states provided as either matrices or vectors. :param probs: Respective list of probabilities each state is selected. :param dist_method: Method of distinguishing to use. :return: The optimal value of the PPT dual problem SDP. """ constraints = [] meas = [] dim_x, _ = states[0].shape y_var = cvxpy.Variable((dim_x, dim_x), hermitian=True) objective = cvxpy.Minimize(cvxpy.trace(cvxpy.real(y_var))) dim = int(np.log2(dim_x)) dim_list = [2] * int(np.log2(dim_x)) sys_list = list(range(1, dim, 2)) # dim_list = [3, 3] if dist_method == "min-error": for i, _ in enumerate(states): meas.append(cvxpy.Variable((dim_x, dim_x), PSD=True)) constraints.append( cvxpy.real(y_var - probs[i] * states[i]) >> partial_transpose(meas[i], sys=sys_list, dim=dim_list) ) if dist_method == "unambiguous": for j, _ in enumerate(states): sum_val = 0 for i, _ in enumerate(states): if i != j: sum_val += cvxpy.real(cvxpy.Variable()) * probs[i] * states[i] meas.append(cvxpy.Variable((dim_x, dim_x), PSD=True)) constraints.append( cvxpy.real(y_var - probs[j] * states[j] + sum_val) >> partial_transpose(meas[j], sys=sys_list, dim=dim_list) ) meas.append(cvxpy.Variable((dim_x, dim_x), PSD=True)) constraints.append( cvxpy.real(y_var) >> partial_transpose(meas[-1], sys=sys_list, dim=dim_list) ) problem = cvxpy.Problem(objective, constraints) sol_default = problem.solve() # print(np.around(y_var.value, decimals=3)) return sol_default