Ejemplo n.º 1
0
def test_invalid_symmetric_extension_hierarchy_probs():
    """Invalid probability vector for symmetric extension hierarchy."""
    with np.testing.assert_raises(ValueError):
        rho1 = bell(0) * bell(0).conj().T
        rho2 = bell(1) * bell(1).conj().T
        states = [rho1, rho2]
        symmetric_extension_hierarchy(states, [1, 2, 3])
Ejemplo n.º 2
0
def test_symmetric_extension_hierarchy_four_bell_with_resource_state():
    """Symmetric extension hierarchy for four Bell states and resource state."""
    e_0, e_1 = basis(2, 0), basis(2, 1)
    e_00, e_11 = np.kron(e_0, e_0), np.kron(e_1, e_1)

    eps = 1 / 2
    eps_state = np.sqrt((1 + eps) / 2) * e_00 + np.sqrt((1 - eps) / 2) * e_11
    eps_dm = eps_state * eps_state.conj().T

    states = [
        np.kron(bell(0) * bell(0).conj().T, eps_dm),
        np.kron(bell(1) * bell(1).conj().T, eps_dm),
        np.kron(bell(2) * bell(2).conj().T, eps_dm),
        np.kron(bell(3) * bell(3).conj().T, eps_dm),
    ]

    # Ensure we are checking the correct partition of the states.
    states = [
        swap(states[0], [2, 3], [2, 2, 2, 2]),
        swap(states[1], [2, 3], [2, 2, 2, 2]),
        swap(states[2], [2, 3], [2, 2, 2, 2]),
        swap(states[3], [2, 3], [2, 2, 2, 2]),
    ]

    res = symmetric_extension_hierarchy(states=states, probs=None, level=2)
    exp_res = 1 / 2 * (1 + np.sqrt(1 - eps**2))

    np.testing.assert_equal(np.isclose(res, exp_res), True)
Ejemplo n.º 3
0
def test_symmetric_extension_hierarchy_four_bell_density_matrices():
    """Symmetric extension hierarchy for four Bell density matrices."""
    states = [
        bell(0) * bell(0).conj().T,
        bell(1) * bell(1).conj().T,
        bell(2) * bell(2).conj().T,
        bell(3) * bell(3).conj().T,
    ]
    res = symmetric_extension_hierarchy(states=states, probs=None, level=2)
    np.testing.assert_equal(np.isclose(res, 1 / 2), True)
Ejemplo n.º 4
0
def test_symmetric_extension_hierarchy_four_bell_states():
    """Symmetric extension hierarchy for four Bell states."""
    states = [bell(0), bell(1), bell(2), bell(3)]
    res = symmetric_extension_hierarchy(states=states, probs=None, level=2)
    np.testing.assert_equal(np.isclose(res, 1 / 2), True)
Ejemplo n.º 5
0
def test_invalid_symmetric_extension_hierarchy_states():
    """Invalid number of states for symmetric_extension_hierarchy."""
    with np.testing.assert_raises(ValueError):
        states = []
        symmetric_extension_hierarchy(states)
Ejemplo n.º 6
0
def has_symmetric_extension(rho, level=2, dim=None, ppt=True, tol=1e-4) -> bool:
    r"""
    Determine whether there exists a symmetric extension for a given quantum state. [DPS02]_.

    Determining whether an operator possesses a symmetric extension at some level :code:`level`
    can be used as a check to determine if the operator is entangled or not.

    This function was adapted from QETLAB.

    Examples
    ==========

    2-qubit symmetric extension:

    In [CJKLZB14]_, it was shown that a 2-qubit state :math:`\rho_{AB}` has a
    symmetric extension if and only if

    .. math::
        \text{Tr}(\rho_B^2) \geq \text{Tr}(\rho_{AB}^2) - 4 \sqrt{\text{det}(\rho_{AB})}.

    This closed-form equation is much quicker to check than running the semidefinite program.

    >>> import numpy as np
    >>> from toqito.state_props import has_symmetric_extension
    >>> rho = np.array([[1, 0, 0, -1],
    >>>                 [0, 1, 1/2, 0],
    >>>                 [0, 1/2, 1, 0],
    >>>                 [-1, 0, 0, 1]])
    >>> # Show the closed-form equation holds
    >>> np.trace(partial_trace(rho, 1)**2) >= np.trace(rho**2) - 4 * np.sqrt(np.linalg.det(rho))
    True
    >>> # Now show that the `has_symmetric_extension` function recognizes this case.
    >>> has_symmetric_extension(rho)
    True

    Higher qubit systems:

    Consider a density operator corresponding to one of the Bell states.

    .. math::
        \rho = \frac{1}{2} \begin{pmatrix}
                            1 & 0 & 0 & 1 \\
                            0 & 0 & 0 & 0 \\
                            0 & 0 & 0 & 0 \\
                            1 & 0 & 0 & 1
                           \end{pmatrix}

    To make this state over more than just two qubits, let's construct the following state

    .. math::
        \sigma = \rho \otimes \rho.

    As the state :math:`\sigma` is entangled, there should not exist a symmetric extension at some
    level. We see this being the case for a relatively low level of the hierachy.

    >>> import numpy as np
    >>> from toqito.states import bell
    >>> from toqito.state_props import has_symmetric_extension
    >>>
    >>> rho = bell(0) * bell(0).conj().T
    >>> sigma = np.kron(rho, rho)
    >>> has_symmetric_extension(sigma)
    False

    References
    ==========
    .. [DPS02] Doherty, Andrew C., Pablo A. Parrilo, and Federico M. Spedalieri.
        "Distinguishing separable and entangled states."
        Physical Review Letters 88.18 (2002): 187904.
        https://arxiv.org/abs/quant-ph/0112007

    .. [CJKLZB14] Chen, J., Ji, Z., Kribs, D., Lütkenhaus, N., & Zeng, B.
        "Symmetric extension of two-qubit states."
        Physical Review A 90.3 (2014): 032318.
        https://arxiv.org/abs/1310.3530

    :param rho: A matrix or vector.
    :param level: Level of the hierarchy to compute.
    :param dim: The default has both subsystems of equal dimension.
    :param ppt: If :code:`True`, this enforces that the symmetric extension must be PPT.
    :param tol: Tolerance when determining whether a symmetric extension exists.
    :return: :code:`True` if :code:`mat` has a symmetric extension; :code:`False` otherwise.
    """
    len_mat = rho.shape[1]

    # Set default dimension if none was provided.
    if dim is None:
        dim = int(np.round(np.sqrt(len_mat)))

    # Allow the user to enter in a single integer for dimension.
    if isinstance(dim, int):
        dim = np.array([dim, len_mat / dim])
        if np.abs(dim[1] - np.round(dim[1])) >= 2 * len_mat * np.finfo(float).eps:
            raise ValueError(
                "If `dim` is a scalar, it must evenly divide the length of the matrix."
            )
        dim[1] = int(np.round(dim[1]))

    dim_x, dim_y = int(dim[0]), int(dim[1])
    # In certain situations, we don't need semidefinite programming.
    if level == 1 or len_mat <= 6 and ppt:
        if not ppt:
            # In some cases, the problem is *really* trivial.
            return is_positive_semidefinite(rho)

        # In this case, all they asked for is a 1-copy PPT symmetric extension
        # (i.e., they're asking if the state is PPT).
        return is_ppt(rho, 2, dim) and is_positive_semidefinite(rho)

    # In the 2-qubit case, an analytic formula is known for whether or not a state has a
    # (2-copy, non-PPT) symmetric extension that is much faster to use than semidefinite
    # programming [CJKLZB14]_.
    if level == 2 and not ppt and dim_x == 2 and dim_y == 2:
        return np.trace(np.linalg.matrix_power(partial_trace(rho, 1), 2)) >= np.trace(
            np.linalg.matrix_power(rho, 2)
        ) - 4 * np.sqrt(np.linalg.det(rho))

    # Otherwise, use semidefinite programming to find a symmetric extension.
    # If the optimal value of the symmetric extension hierarchy is equal to 1,
    # this indicates that there does not exist a symmetric extension at
    # level :code:`level`.
    return not np.isclose(
        (1 - min(symmetric_extension_hierarchy([rho], probs=None, level=level), 1)),
        0,
        atol=tol,
    )