Source code for toqito.state_props.entanglement_of_formation
"""Computes the entanglement of formation of a bipartite quantum state."""
import numpy as np
import scipy
from toqito.matrix_ops import partial_trace
from toqito.state_props import concurrence, von_neumann_entropy
[docs]
def entanglement_of_formation(rho: np.ndarray, dim: list[int] | int | None = None) -> float:
r"""Compute entanglement-of-formation of a bipartite quantum state [@Quantiki_EOF].
Entanglement-of-formation is the entropy of formation of the bipartite
quantum state `rho`. Note that this function currently only supports
`rho` being a pure state or a 2-qubit state: it is not known how to
compute the entanglement-of-formation of higher-dimensional mixed states.
This function was adapted from QETLAB.
Examples:
Compute the entanglement-of-formation of a Bell state.
Let \(u = \frac{1}{\sqrt{2}} \left(|00\rangle + |11\rangle \right)\)
and let
\[
\rho = uu^* = \frac{1}{2}\begin{pmatrix}
1 & 0 & 0 & 1 \\
0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 \\
1 & 0 & 0 & 1
\end{pmatrix}.
\]
The entanglement-of-formation of \(\rho\) is equal to 1.
```python exec="1" source="above"
import numpy as np
from toqito.state_props import entanglement_of_formation
from toqito.states import bell
u_vec = bell(0)
rho = u_vec @ u_vec.conj().T
print(entanglement_of_formation(rho))
```
Raises:
ValueError: If matrices have improper dimension.
Args:
rho: A matrix or vector.
dim: The default has both subsystems of equal dimension.
Returns:
A value between 0 and 1 that corresponds to the entanglement-of-formation of `rho`.
"""
dim_x, dim_y = rho.shape
round_dim = int(np.round(np.sqrt(max(dim_x, dim_y))))
if dim is None:
dim_int = round_dim
elif isinstance(dim, int):
dim_int = dim
else:
dim_int = None
# User can specify dimension as integer.
if dim_int is not None:
dim_arr = np.array([dim_int, max(dim_x, dim_y) / dim_int], dtype=int)
dim_arr[1] = np.round(dim_arr[1])
else:
dim_arr = np.array(dim)
if np.prod(dim_arr) != max(dim_x, dim_y):
raise ValueError("Invalid dimension: Please provide local dimensions that match the size of `rho`.")
# If `rho` is a rank-1 density matrix, turn it into a vector instead
# so we can compute the entanglement-of-formation easily.
tmp_rho = scipy.linalg.orth(rho)
if dim_x == dim_y and tmp_rho.shape[1] == 1:
rho = tmp_rho
dim_y = 1
# Start computing entanglement-of-formation.
if min(dim_x, dim_y) == 1:
rho = rho[:]
dim_list = [int(x) for x in dim_arr]
return von_neumann_entropy(partial_trace(rho @ rho.conj().T, [1], dim_list))
# Case: `rho` is a density matrix.
if dim_x == dim_y:
# In the two-qubit case, we know how to compute the
# entanglement-of-formation exactly.
if dim_x == 4:
rho_c = concurrence(rho)
rho_c1 = (1 + np.sqrt(1 - rho_c**2)) / 2
rho_c2 = (1 - np.sqrt(1 - rho_c**2)) / 2
rho_c1_log2 = 0 if rho_c1 == 0 else np.log2(rho_c1)
rho_c2_log2 = 0 if rho_c2 == 0 else np.log2(rho_c2)
return -rho_c1 * rho_c1_log2 - rho_c2 * rho_c2_log2
raise ValueError(
"Invalid input: It is presently only known how to compute "
"the entanglement-of-formation for two-qubit states and pure "
"states."
)
raise ValueError("Invalid dimension: `rho` must be either a vector or square matrix.")