The Wire That Smudges Qubits

quantum channel · Kraus operators · conjugate transpose · completeness relation

A wire on a chip does not always pass a qubit through untouched. Any such noisy process (a channel) can be written with a list of matrices K_0, K_1, \dots, its Kraus operators: a density matrix \rho goes in and

\rho' = \sum_k K_k\,\rho\,K_k^\dagger

comes out, where K^\dagger is the conjugate transpose of K (K^\dagger_{ij} = \overline{K_{ji}}) and the products are matrix products. A list of matrices is a valid channel only if it satisfies the completeness relation

\sum_k K_k^\dagger K_k = I,

which is what keeps the trace of \rho' equal to 1. A single unitary gate U is the channel with one Kraus operator: \rho' = U\rho U^\dagger.

Write apply_channel(rho, kraus) that returns \rho' as a list of rows, or None if the list kraus breaks the completeness relation: some entry of \sum_k K_k^\dagger K_k - I has size greater than 1e-9. rho is a d \times d density matrix with d = 2 or 4, and every matrix in kraus is d \times d (all lists of rows). In the tests, a list that breaks the relation misses by more than 0.01 in some entry.

Examples

Input:  rho = [[0.5, 0.5], [0.5, 0.5]], kraus = [[[0.8, 0], [0, 0.8]], [[0.6, 0], [0, -0.6]]]
Output: [[0.5, 0.14], [0.14, 0.5]]
Explanation: 0.64 * rho + 0.36 * (Z rho Z); Z rho Z has -0.5 off the diagonal.

Input:  rho = [[0, 0], [0, 1]], kraus = [[[1, 0], [0, 0.8]], [[0, 0.6], [0, 0]]]
Output: [[0.36, 0], [0, 0.64]]
Explanation: the second operator moves |1> to |0>, the first keeps |1> with weight 0.64.

Input:  rho = [[0, 0], [0, 1]], kraus = [[[1, 0], [0, 1]], [[0, 0.5], [0, 0]]]
Output: None
Explanation: the sum K^dagger K is [[1, 0], [0, 1.25]], not I.

Entries may be ints, floats or complex numbers; each is compared with a tolerance of 1e-6.

Goals

  • Apply a channel given by Kraus operators: $\rho \mapsto \sum_k K_k\rho K_k^\dagger$
  • Check the completeness relation $\sum_k K_k^\dagger K_k = I$ within a tolerance
Starting Python…