qml.math.choi_matrix

choi_matrix(Ks, check_Ks=False)[source]

Compute the Choi matrix \(\Lambda\) of a quantum channel \(\mathcal{E}\),

\[\Lambda = (\mathbb{1} \otimes \mathcal{E})(|\phi^+ \rangle \langle \phi^+|) = \frac{1}{2^n} \sum_{ij=0}^{2^n-1} |i \rangle \langle j| \otimes \mathcal{E}(|i \rangle \langle j|),\]

where \(|\phi^+ \rangle\) is the maximally entangled state \(|\phi^+\rangle = \frac{1}{\sqrt{2^n}} \sum_{i=0}^{2^n-1} |i\rangle \otimes |i\rangle\) between the qubit system the channel \(\mathcal{E}\) is acting on and additional “artificial” system of the same size.

We assume the channel \(\mathcal{E}(\rho) = \sum_\ell K_\ell^\dagger \rho K_\ell\) is provided in terms of its Kraus operators \(\{K_j\}\) (Ks) that are trace-preserving, hence \(\sum_j K_j^\dagger K_j = \mathbb{1}\).

Parameters:
  • Ks (TensorLike) – A list of Kraus operators with size (2**n, 2**n) that act on n wires.

  • check_Ks (bool) – Whether or not to check if the provided Kraus operators are trace-preserving, i.e. \(\sum_j K_j^\dagger K_j = \mathbb{1}\). Default is False.

Returns:

The Choi matrix \(\Lambda\) of size (2**(2n), 2**(2n))

Return type:

TensorLike

Examples

The simplest quantum channel is a single unitary gate. In that case, the Kraus operators reduce to the unitary gate itself.

>>> import pennylane as qml
>>> Ks = [qml.matrix(qml.CNOT((0, 1)))]
>>> Lambda = qml.math.choi_matrix(Ks)
>>> Lambda.shape
(16, 16)

The resulting Choi matrix is a density matrix, so its trace sums to 1. Because the channel is unitary, the resulting Choi state is pure, which can be seen from \(\text{tr}\left( \Lambda^2 \right) = 1\)

>>> np.trace(Lambda), np.trace(Lambda @ Lambda)
(np.float64(1.0), np.float64(1.0))

We can construct a non-unitary channel by taking different unitary operators and weighting them such that the trace is preserved (i.e., the squares of the coefficients sum to one).

>>> Ks = [np.sqrt(0.3) * qml.CNOT((0, 1)), np.sqrt(1-0.3) * qml.X(0)]
>>> Ks = [qml.matrix(op, wire_order=range(2)) for op in Ks]
>>> Lambda = qml.math.choi_matrix(Ks)

In this case, the resulting Choi matrix does not correspond to a pure state, as seen by \(\text{tr}\left( \Lambda^2 \right) < 1\).

>>> np.trace(Lambda), np.trace(Lambda @ Lambda)
(np.float64(1.0), np.float64(0.58))