Anyone have any idea how I can implement a depolarizing noise channel for qutrits using cirq? Say using the kraus operators within a class inheriting from cirq.Gate or so?


1 Answer 1


The depolarizing channel can be represented as a probabilistic mixture of unitaries. You can represent mixtures in Cirq by implementing the _mixture_ and _has_mixture_ magic methods on a class.

I'm following https://arxiv.org/pdf/1101.3986 for the Kraus operators (which are unitary):

enter image description here

I reimplemented the DepolarizingChannel but only for a single qutrit as an example:

SHIFT = np.array([[0,1,0],
ω = np.exp(1j * 2/3 * np.pi)
CLOCK = np.array([[1,0,0],

class QutritDepolarizingChannel(cirq.Gate):
    r"""A channel that depolarizes one qutrit.

    def __init__(self, p: float) -> None:
        """Constructs a depolarization channel on a qutrit.

            p: The probability that one of the shift/clock matrices is applied. Each of
                the 8 shift/clock gates is applied independently with probability
                $p / 8$.
            n_qubits: the number of qubits.

            ValueError: if p is not a valid probability.

        error_probabilities = {}

        p_depol = p / 8
        p_identity = 1.0 - p
        for gate_pows in itertools.product(range(3), range(3)):          
            if gate_pows == (0,0):
                error_probabilities[gate_pows] = p_identity
                error_probabilities[gate_pows] = p_depol
        self.error_probabilities = error_probabilities
        self._p = p        

    def _qid_shape_(self):
        return (3,) 

    def _mixture_(self) -> Sequence[Tuple[float, np.ndarray]]:
        op = lambda shift_pow, clock_pow: np.linalg.matrix_power(SHIFT, shift_pow) @ np.linalg.matrix_power(CLOCK, clock_pow)
        return [(self.error_probabilities[(shift_pow, clock_pow)], op(shift_pow, clock_pow))
                for (shift_pow, clock_pow) in self.error_probabilities.keys()]

    def _has_mixture_(self) -> bool:
        return True

    def _value_equality_values_(self):
        return self._p
    def _circuit_diagram_info_(self, args):        
        if args.precision is not None:
            return (f"D3({self._p:.{args.precision}g})",)
            return (f"D3({self._p})",)        
        return result

    def p(self) -> float:
        """The probability that one of the qutrit gates is applied.

        Each of the 8 Pauli gates is applied independently with probability
        $p / 8$.
        return self._p

    def n_qubits(self) -> int:
        """The number of qubits"""
        return 1

Then you can use it as any other channel/gate:

t = cirq.NamedQid("my qutrit", 3)
c = cirq.Circuit(QutritDepolarizingChannel(0.12)(t), cirq.measure(t))
cirq.DensityMatrixSimulator().run(c, repetitions=100)

Results in:

my qutrit (d=3): ───D3(0.12)───M───
my qutrit (d=3)=0000000000000000100000000100010000000020000000000000000000000000000000000000000000000000000000000100

colab: https://colab.research.google.com/drive/1l8v3YAOxCtDP3Ccxgv5wbGfRRqnLbgIp#scrollTo=EqkzGHaul-N7

  • $\begingroup$ Are you not missing a square root when putting your probabilities in your dictionary, as technically the coefficients to the Kraus operators are not just probabilites, right? Or does cirq specifically need probabilities and operators, and then it fills out the rest? $\endgroup$
    – Son100
    Commented May 2 at 22:48
  • $\begingroup$ Also I don't think you can use the cirq.DensityMatrixSimulator() after using this channel. $\endgroup$
    – Son100
    Commented May 2 at 23:50
  • $\begingroup$ You don't need square root when doing a probabilistic mixture of unitaries. Why do you think you can't use the density matrix simulator? $\endgroup$ Commented May 3 at 20:12
  • $\begingroup$ added a colab link to the bottom, also showed a DensityMatrixSimulator execution of 100 trials, which shows nicely the roughly 12% non-zero measurement results starting from |0> $\endgroup$ Commented May 3 at 21:37
  • $\begingroup$ Oh I see, I had a typo when implementing my mixture method, I wasn't returning a list of tuples, but it seems to work with the simulators now. I was trying to generalize the noise channel to a d-dimensional qudit, which has now worked. Thank you for the help! But I'm a bit curious as to how the mixture methods work with the circuit and simulators, how is the noise actually being implemented within the cirq framework? I assume the mixture of unitaries and corresponding probabilities represent the kraus operators in some capacity. $\endgroup$
    – Son100
    Commented May 4 at 7:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.