Skip to content

Commit

Permalink
Merge pull request #1456 from qiboteam/negativity
Browse files Browse the repository at this point in the history
Add `negativity` to `quantum_info.entanglement`
  • Loading branch information
renatomello authored Oct 8, 2024
2 parents 2144add + 01a37bd commit b53ce52
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
6 changes: 6 additions & 0 deletions doc/source/api-reference/qibo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1704,6 +1704,12 @@ Entanglement of formation
.. autofunction:: qibo.quantum_info.entanglement_of_formation


Negativity
""""""""""

.. autofunction:: qibo.quantum_info.negativity


Entanglement fidelity
"""""""""""""""""""""

Expand Down
39 changes: 38 additions & 1 deletion src/qibo/quantum_info/entanglement.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

from qibo.backends import _check_backend
from qibo.config import PRECISION_TOL, raise_error
from qibo.quantum_info.linalg_operations import partial_trace
from qibo.quantum_info.linalg_operations import (
matrix_power,
partial_trace,
partial_transpose,
)
from qibo.quantum_info.metrics import fidelity, purity


Expand Down Expand Up @@ -116,6 +120,39 @@ def entanglement_of_formation(
return ent_of_form


def negativity(state, bipartition, backend=None):
"""Calculates the negativity of a bipartite quantum state.
Given a bipartite state :math:`\\rho \\in \\mathcal{H}_{A} \\otimes \\mathcal{H}_{B}`,
the negativity :math:`\\operatorname{Neg}(\\rho)` is given by
.. math::
\\operatorname{Neg}(\\rho) = \\frac{1}{2} \\,
\\left( \\norm{\\rho_{B}}_{1} - 1 \\right) \\, ,
where :math:`\\rho_{B}` is the reduced density matrix after tracing out qubits in
partition :math:`A`, and :math:`\\norm{\\cdot}_{1}` is the Schatten :math:`1`-norm
(also known as nuclear norm or trace norm).
Args:
state (ndarray): statevector or density matrix.
bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out.
backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used
in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`.
Defaults to ``None``.
Returns:
float: Negativity :math:`\\operatorname{Neg}(\\rho)` of state :math:`\\rho`.
"""
backend = _check_backend(backend)

reduced = partial_transpose(state, bipartition, backend)
reduced = backend.np.conj(reduced.T) @ reduced
norm = backend.np.trace(matrix_power(reduced, 1 / 2, backend))

return float(backend.np.real((norm - 1) / 2))


def entanglement_fidelity(
channel, nqubits: int, state=None, check_hermitian: bool = False, backend=None
):
Expand Down
22 changes: 22 additions & 0 deletions tests/test_quantum_info_entanglement.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
entanglement_of_formation,
entangling_capability,
meyer_wallach_entanglement,
negativity,
)
from qibo.quantum_info.random_ensembles import random_density_matrix, random_statevector

Expand Down Expand Up @@ -66,6 +67,27 @@ def test_concurrence_and_formation(backend, bipartition, base, check_purity):
backend.assert_allclose(ent_form, 0.0, atol=PRECISION_TOL)


@pytest.mark.parametrize("p", [1 / 5, 1 / 3 + 0.01, 1.0])
def test_negativity(backend, p):
# werner state
zero, one = np.array([1, 0]), np.array([0, 1])
psi = (np.kron(zero, one) - np.kron(one, zero)) / np.sqrt(2)
psi = np.outer(psi, psi.T)
psi = backend.cast(psi)
state = p * psi + (1 - p) * backend.identity_density_matrix(2, normalize=True)

neg = negativity(state, [0], backend=backend)

if p == 1 / 5:
target = 0.0
elif p == 1.0:
target = 1 / 2
else:
target = 3 / 400

backend.assert_allclose(neg, target, atol=1e-10)


@pytest.mark.parametrize("check_hermitian", [False, True])
@pytest.mark.parametrize("nqubits", [4, 6])
@pytest.mark.parametrize("channel", [gates.DepolarizingChannel])
Expand Down

0 comments on commit b53ce52

Please sign in to comment.