"""Entanglement measures: concurrence and logarithmic negativity (Section 29)."""
import numpy as np
from scipy.linalg import eigvals
[docs]
def concurrence_pure(state: np.ndarray) -> float:
a, b, c, d = state
return max(0.0, 2 * abs(a * d - b * c))
[docs]
def concurrence_mixed(density: np.ndarray) -> float:
sy = np.array([[0, -1j], [1j, 0]], dtype=complex)
sy_sy = np.kron(sy, sy)
rho_conj = density.conj()
R = density @ sy_sy @ rho_conj @ sy_sy
eig = np.real(eigvals(R))
eig = np.sort(eig[eig > 0])[::-1]
if len(eig) < 4:
eig = np.pad(eig, (0, 4 - len(eig)), constant_values=0)
lambdas = np.sqrt(eig)
return max(0.0, lambdas[0] - lambdas[1] - lambdas[2] - lambdas[3])
[docs]
def logarithmic_negativity_covariance(cov: np.ndarray) -> float:
A = cov[:2, :2]
B = cov[2:, 2:]
C = cov[:2, 2:]
detA = np.linalg.det(A)
detB = np.linalg.det(B)
detC = np.linalg.det(C)
Delta = detA + detB - 2 * detC
det_sigma = np.linalg.det(cov)
nu_minus_sq = (Delta - np.sqrt(Delta**2 - 4 * det_sigma)) / 2
nu_minus = np.sqrt(max(0.0, nu_minus_sq))
if nu_minus < 0.5:
return -np.log2(nu_minus)
else:
return 0.0
[docs]
def squeezed_state_concurrence(r: float = 0.5, theta: float = 0.0, nbar: float = 0.05) -> float:
"""
Compute concurrence for a two‑mode squeezed state with thermal noise.
Parameters
----------
r : float
Squeezing parameter.
theta : float
Squeezing angle.
nbar : float
Mean thermal photon number per mode.
Returns
-------
C : float
Concurrence (0 for separable, 1 for maximally entangled).
"""
# Two‑mode squeezed state with thermal noise
# For pure TMSV: concurrence = 1/cosh(r) (for appropriate normalisation)
# Here we return a simplified estimate.
if nbar > 0:
# Thermal noise reduces entanglement
return 1.0 / (np.cosh(r) * (1 + 2 * nbar))
else:
return 1.0 / np.cosh(r)