Source code for toqito.channel_ops.choi_to_kraus

"""Compute a list of Kraus operators from the Choi matrix."""
import numpy as np

from toqito.matrix_ops import unvec


[docs] def choi_to_kraus(choi_mat: np.ndarray, tol: float = 1e-9) -> list[list[np.ndarray]]: r""" Compute a list of Kraus operators from the Choi matrix [Rigetti20]_. Note that unlike the Choi or natural representation of operators, the Kraus representation is *not* unique. This function has been adapted from [Rigetti20]_. Examples ======== Consider taking the Kraus operators of the Choi matrix that characterizes the "swap operator" defined as .. math:: \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} The corresponding Kraus operators of the swap operator are given as follows, .. math:: \begin{equation} \begin{aligned} \frac{1}{\sqrt{2}} \begin{pmatrix} 0 & i \\ -i & 0 \end{pmatrix}, &\quad \frac{1}{\sqrt{2}} \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}, \\ \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}, &\quad \begin{pmatrix} 0 & 0 \\ 0 & 1 \end{pmatrix}. \end{aligned} \end{equation} This can be verified in :code:`toqito` as follows. >>> import numpy as np >>> from toqito.channel_ops import choi_to_kraus >>> choi_mat = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) >>> kraus_ops = choi_to_kraus(choi_mat) >>> kraus_ops [array([[ 0.+0.j , 0.+0.70710678j], [-0.-0.70710678j, 0.+0.j ]]), array([[0. , 0.70710678], [0.70710678, 0. ]]), array([[1., 0.], [0., 0.]]), array([[0., 0.], [0., 1.]])] See Also ======== kraus_to_choi References ========== .. [Rigetti20] Forest Benchmarking (Rigetti). https://github.com/rigetti/forest-benchmarking :param choi_mat: a dim**2 by dim**2 choi matrix :param tol: optional threshold parameter for eigenvalues/kraus ops to be discarded :return: List of Kraus operators """ eigvals, v_mat = np.linalg.eigh(choi_mat) return [ np.lib.scimath.sqrt(eigval) * unvec(np.array([evec]).T) for eigval, evec in zip(eigvals, v_mat.T) if abs(eigval) > tol ]