Apply a quantum channel to an operator.
(Section: Representations and Characterizations of Channels of 1).
Specifically, an application of the channel is defined as
\[
\Phi(X) = \text{Tr}_{\mathcal{X}} \left(J(\Phi)
\left(\mathbb{I}_{\mathcal{Y}} \otimes X^{T}\right)\right),
\]
where
\[
J(\Phi): \text{T}(\mathcal{X}, \mathcal{Y}) \rightarrow
\text{L}(\mathcal{Y} \otimes \mathcal{X})
\]
is the Choi representation of \(\Phi\).
We assume the quantum channel given as phi_op is provided as either the Choi matrix
of the channel or a set of Kraus operators that define the quantum channel.
This function is adapted from the QETLAB package.
Examples:
The swap operator is the Choi matrix of the transpose map. The following is a (non-ideal,
but illustrative) way of computing the transpose of a matrix.
Consider the following matrix
\[
X = \begin{pmatrix}
1 & 4 & 7 \\
2 & 5 & 8 \\
3 & 6 & 9
\end{pmatrix}
\]
Applying the swap operator given as
\[
\Phi =
\begin{pmatrix}
1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\
0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1
\end{pmatrix}
\]
to the matrix \(X\), we have the resulting matrix of
\[
\Phi(X) = \begin{pmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9
\end{pmatrix}
\]
Using |toqito⟩, we can obtain the above matrices as follows.
from toqito.channel_ops import apply_channel
from toqito.perms import swap_operator
import numpy as np
test_input_mat = np.array([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
print(apply_channel(test_input_mat, swap_operator(3)))
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
Raises:
-
ValueError
–
If matrix is not Choi matrix.
Parameters:
-
mat
(ndarray)
–
-
phi_op
(ndarray | list[list[ndarray]])
–
A superoperator. phi_op should be provided either as a Choi matrix, or as a list of numpy arrays with
Returns:
-
ndarray
–
The result of applying the superoperator phi_op to the operator mat.
References
1 Watrous, John. The Theory of Quantum Information. (2018). doi:10.1017/9781316848142.
Source code in toqito/channel_ops/apply_channel.py
| def apply_channel(mat: np.ndarray, phi_op: np.ndarray | list[list[np.ndarray]]) -> np.ndarray:
r"""Apply a quantum channel to an operator.
(Section: Representations and Characterizations of Channels of [@Watrous_2018_TQI]).
Specifically, an application of the channel is defined as
\[
\Phi(X) = \text{Tr}_{\mathcal{X}} \left(J(\Phi)
\left(\mathbb{I}_{\mathcal{Y}} \otimes X^{T}\right)\right),
\]
where
\[
J(\Phi): \text{T}(\mathcal{X}, \mathcal{Y}) \rightarrow
\text{L}(\mathcal{Y} \otimes \mathcal{X})
\]
is the Choi representation of \(\Phi\).
We assume the quantum channel given as `phi_op` is provided as either the Choi matrix
of the channel or a set of Kraus operators that define the quantum channel.
This function is adapted from the QETLAB package.
Examples:
The swap operator is the Choi matrix of the transpose map. The following is a (non-ideal,
but illustrative) way of computing the transpose of a matrix.
Consider the following matrix
\[
X = \begin{pmatrix}
1 & 4 & 7 \\
2 & 5 & 8 \\
3 & 6 & 9
\end{pmatrix}
\]
Applying the swap operator given as
\[
\Phi =
\begin{pmatrix}
1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\
0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1
\end{pmatrix}
\]
to the matrix \(X\), we have the resulting matrix of
\[
\Phi(X) = \begin{pmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9
\end{pmatrix}
\]
Using `|toqito⟩`, we can obtain the above matrices as follows.
```python exec="1" source="above"
from toqito.channel_ops import apply_channel
from toqito.perms import swap_operator
import numpy as np
test_input_mat = np.array([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
print(apply_channel(test_input_mat, swap_operator(3)))
```
Raises:
ValueError: If matrix is not Choi matrix.
Args:
mat: A matrix.
phi_op: A superoperator. `phi_op` should be provided either as a Choi matrix, or as a list of numpy arrays with
either 1 or 2 columns whose entries are its Kraus operators.
Returns:
The result of applying the superoperator `phi_op` to the operator `mat`.
"""
# Both of the following methods of applying the superoperator are much faster than naively
# looping through the Kraus operators or constructing eigenvectors of a Choi matrix.
# The superoperator was given as a list of Kraus operators:
if isinstance(phi_op, list):
s_phi_op = [len(phi_op), len(phi_op[0])]
phi_0_list = []
phi_1_list = []
# Map is completely positive if input is given as:
# 1. [K1, K2, .. Kr]
# 2. [[K1], [K2], .. [Kr]]
# 3. [[K1, K2, .. Kr]] and r > 2
if isinstance(phi_op[0], np.ndarray):
phi_0_list = phi_op
elif s_phi_op[1] == 1 or (s_phi_op[0] == 1 and s_phi_op[1] > 2):
phi_0_list = list(itertools.chain(*phi_op))
else:
# Input is given as: [[A1, B1], [A2, B2], .. [Ar, Br]]
phi_0_list = [k_mat[0] for k_mat in phi_op]
phi_1_list = [k_mat[1].conj().T for k_mat in phi_op]
if not phi_1_list:
phi_1_list = [k_mat.conj().T for k_mat in phi_0_list]
k_1 = np.concatenate(phi_0_list, axis=1)
k_2 = np.concatenate(phi_1_list, axis=0)
a_mat = np.kron(np.identity(len(phi_0_list)), mat)
return k_1 @ a_mat @ k_2
# The superoperator was given as a Choi matrix:
if isinstance(phi_op, np.ndarray):
mat_size = np.array(list(mat.shape))
phi_size = np.array(list(phi_op.shape)) / mat_size
a_mat = np.kron(vec(mat).T[0], np.identity(int(phi_size[0])))
b_mat = np.reshape(
swap(
phi_op.T,
[1, 2],
[[mat_size[1], phi_size[1]], [mat_size[0], phi_size[0]]],
True,
).T,
(int(phi_size[0] * np.prod(mat_size)), int(phi_size[1])),
order="F",
)
return a_mat @ b_mat
raise ValueError("Invalid: The variable `phi_op` must either be a list of Kraus operators or as a Choi matrix.")
|