Source code for toqito.states.werner

"""Werner state."""
from __future__ import annotations

import itertools
import numpy as np

from toqito.perms import permutation_operator
from toqito.perms import swap_operator


[docs] def werner(dim: int, alpha: float | list[float]) -> np.ndarray: r""" Produce a Werner state [Wer89]_. A Werner state is a state of the following form .. math:: \begin{equation} \rho_{\alpha} = \frac{1}{d^2 - d\alpha} \left(\mathbb{I} \otimes \mathbb{I} - \alpha S \right) \in \mathbb{C}^d \otimes \mathbb{C}^d. \end{equation} Yields a Werner state with parameter :code:`alpha` acting on :code:`(dim * dim)`- dimensional space. More specifically, :math:`\rho` is the density operator defined by :math:`(\mathbb{I} - `alpha` S)` (normalized to have trace 1), where :math:`\mathbb{I}` is the density operator and :math:`S` is the operator that swaps two copies of :code:`dim`-dimensional space (see swap and swap_operator for example). If :code:`alpha` is a vector with :math:`p!-1` entries, for some integer :math:`p > 1`, then a multipartite Werner state is returned. This multipartite Werner state is the normalization of I - `alpha(1)*P(2)` - ... - `alpha(p!-1)*P(p!)`, where P(i) is the operator that permutes p subsystems according to the i-th permutation when they are written in lexicographical order (for example, the lexicographical ordering when p = 3 is: `[1, 2, 3], [1, 3, 2], [2, 1,3], [2, 3, 1], [3, 1, 2], [3, 2, 1],` so P(4) in this case equals permutation_operator(dim, [2, 3, 1]). Examples ========== Computing the qutrit Werner state with :math:`\alpha = 1/2` can be done in :code:`toqito` as >>> from toqito.states import werner >>> werner(3, 1 / 2) [[ 0.06666667, 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0.13333333, 0. , -0.06666667, 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0.13333333, 0. , 0. , 0. , -0.06666667, 0. , 0. ], [ 0. , -0.06666667, 0. , 0.13333333, 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0.06666667, 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0.13333333, 0. , -0.06666667, 0. ], [ 0. , 0. , -0.06666667, 0. , 0. , 0. , 0.13333333, 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , -0.06666667, 0. , 0.13333333, 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.06666667]] We may also compute multipartite Werner states in :code:`toqito` as well. >>> from toqito.states import werner >>> werner(2, [0.01, 0.02, 0.03, 0.04, 0.05]) [[ 0.12179487, 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0.12820513, 0. , 0. , -0.00641026, 0. , 0. , 0. ], [ 0. , 0. , 0.12179487, 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0.12820513, 0. , 0. , -0.00641026, 0. ], [ 0. , -0.00641026, 0. , 0. , 0.12820513, 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0.12179487, 0. , 0. ], [ 0. , 0. , 0. , -0.00641026, 0. , 0. , 0.12820513, 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.12179487]] References ========== .. [Wer89] R. F. Werner. Quantum states with Einstein-Podolsky-Rosen correlations admitting a hidden-variable model. Phys. Rev. A, 40(8):4277–4281. 1989 :raises ValueError: Alpha vector does not have the correct length. :param dim: The dimension of the Werner state. :param alpha: Parameter to specify Werner state. :return: A Werner state of dimension :code:`dim`. """ # The total number of permutation operators. if isinstance(alpha, float): n_fac = 2 else: n_fac = len(alpha) + 1 # Multipartite Werner state. if n_fac > 2: # Compute the number of parties from `len(alpha)`. n_var = n_fac # We won't actually go all the way to `n_fac`. for i in range(2, n_fac): n_var = n_var // i if n_var == i + 1: break if n_var < i: raise ValueError( "InvalidAlpha: The `alpha` vector must contain" " p!-1 entries for some integer p > 1." ) # Done error checking and computing the number of parties -- now # compute the Werner state. perms = list(itertools.permutations(np.arange(n_var))) sorted_perms = np.argsort(perms, axis=1) + 1 for i in range(2, n_fac): rho = np.identity(dim**n_var) - alpha[i - 1] * permutation_operator( dim, sorted_perms[i, :], False, True ) rho = rho / np.trace(rho) return rho # Bipartite Werner state. return (np.identity(dim**2) - alpha * swap_operator(dim, True)) / (dim * (dim - alpha))