1# Copyright 2019 The Cirq Developers
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from typing import Sequence, TYPE_CHECKING
16
17from cirq import devices, value, ops
18from cirq.devices.noise_model import validate_all_measurements
19
20if TYPE_CHECKING:
21    import cirq
22
23
24class DepolarizingNoiseModel(devices.NoiseModel):
25    """Applies depolarizing noise to each qubit individually at the end of
26    every moment.
27
28    If a circuit contains measurements, they must be in moments that don't
29    also contain gates.
30    """
31
32    def __init__(self, depol_prob: float):
33        """A depolarizing noise model
34
35        Args:
36            depol_prob: Depolarizing probability.
37        """
38        value.validate_probability(depol_prob, 'depol prob')
39        self.qubit_noise_gate = ops.DepolarizingChannel(depol_prob)
40
41    def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
42        if validate_all_measurements(moment) or self.is_virtual_moment(moment):
43            # coverage: ignore
44            return moment
45
46        return [
47            moment,
48            ops.Moment(self.qubit_noise_gate(q).with_tags(ops.VirtualTag()) for q in system_qubits),
49        ]
50
51
52class ReadoutNoiseModel(devices.NoiseModel):
53    """NoiseModel with probabilistic bit flips preceding measurement.
54
55    This simulates readout error. Note that since noise is applied before the
56    measurement moment, composing this model on top of another noise model will
57    place the bit flips immediately before the measurement (regardless of the
58    previously-added noise).
59
60    If a circuit contains measurements, they must be in moments that don't
61    also contain gates.
62    """
63
64    def __init__(self, bitflip_prob: float):
65        """A noise model with readout error.
66
67        Args:
68            bitflip_prob: Probability of a bit-flip during measurement.
69        """
70        value.validate_probability(bitflip_prob, 'bitflip prob')
71        self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob)
72
73    def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
74        if self.is_virtual_moment(moment):
75            return moment
76        if validate_all_measurements(moment):
77            return [
78                ops.Moment(
79                    self.readout_noise_gate(q).with_tags(ops.VirtualTag()) for q in system_qubits
80                ),
81                moment,
82            ]
83        return moment
84
85
86class DampedReadoutNoiseModel(devices.NoiseModel):
87    """NoiseModel with T1 decay preceding measurement.
88
89    This simulates asymmetric readout error. Note that since noise is applied
90    before the measurement moment, composing this model on top of another noise
91    model will place the T1 decay immediately before the measurement
92    (regardless of the previously-added noise).
93
94    If a circuit contains measurements, they must be in moments that don't
95    also contain gates.
96    """
97
98    def __init__(self, decay_prob: float):
99        """A depolarizing noise model with damped readout error.
100
101        Args:
102            decay_prob: Probability of T1 decay during measurement.
103        """
104        value.validate_probability(decay_prob, 'decay_prob')
105        self.readout_decay_gate = ops.AmplitudeDampingChannel(decay_prob)
106
107    def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
108        if self.is_virtual_moment(moment):
109            return moment
110        if validate_all_measurements(moment):
111            return [
112                ops.Moment(
113                    self.readout_decay_gate(q).with_tags(ops.VirtualTag()) for q in system_qubits
114                ),
115                moment,
116            ]
117        return moment
118
119
120class DepolarizingWithReadoutNoiseModel(devices.NoiseModel):
121    """DepolarizingNoiseModel with probabilistic bit flips preceding
122    measurement.
123    This simulates readout error.
124    If a circuit contains measurements, they must be in moments that don't
125    also contain gates.
126    """
127
128    def __init__(self, depol_prob: float, bitflip_prob: float):
129        """A depolarizing noise model with readout error.
130        Args:
131            depol_prob: Depolarizing probability.
132            bitflip_prob: Probability of a bit-flip during measurement.
133        """
134        value.validate_probability(depol_prob, 'depol prob')
135        value.validate_probability(bitflip_prob, 'bitflip prob')
136        self.qubit_noise_gate = ops.DepolarizingChannel(depol_prob)
137        self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob)
138
139    def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
140        if validate_all_measurements(moment):
141            return [
142                ops.Moment(self.readout_noise_gate(q) for q in system_qubits),
143                moment,
144            ]
145        return [
146            moment,
147            ops.Moment(self.qubit_noise_gate(q) for q in system_qubits),
148        ]
149
150
151class DepolarizingWithDampedReadoutNoiseModel(devices.NoiseModel):
152    """DepolarizingWithReadoutNoiseModel with T1 decay preceding
153    measurement.
154    This simulates asymmetric readout error. The noise is structured
155    so the T1 decay is applied, then the readout bitflip, then measurement.
156    If a circuit contains measurements, they must be in moments that don't
157    also contain gates.
158    """
159
160    def __init__(
161        self,
162        depol_prob: float,
163        bitflip_prob: float,
164        decay_prob: float,
165    ):
166        """A depolarizing noise model with damped readout error.
167        Args:
168            depol_prob: Depolarizing probability.
169            bitflip_prob: Probability of a bit-flip during measurement.
170            decay_prob: Probability of T1 decay during measurement.
171                Bitflip noise is applied first, then amplitude decay.
172        """
173        value.validate_probability(depol_prob, 'depol prob')
174        value.validate_probability(bitflip_prob, 'bitflip prob')
175        value.validate_probability(decay_prob, 'decay_prob')
176        self.qubit_noise_gate = ops.DepolarizingChannel(depol_prob)
177        self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob)
178        self.readout_decay_gate = ops.AmplitudeDampingChannel(decay_prob)
179
180    def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
181        if validate_all_measurements(moment):
182            return [
183                ops.Moment(self.readout_decay_gate(q) for q in system_qubits),
184                ops.Moment(self.readout_noise_gate(q) for q in system_qubits),
185                moment,
186            ]
187        else:
188            return [moment, ops.Moment(self.qubit_noise_gate(q) for q in system_qubits)]
189