Skip to content

Commit 2173906

Browse files
Add bitflip error depending on amount of time qubits will sit idle.
1 parent ea033bf commit 2173906

File tree

1 file changed

+59
-26
lines changed

1 file changed

+59
-26
lines changed

src/bloqade/cirq_utils/noise/model.py

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ def __post_init__(self):
6767
_default_cz_paired_correlated_rates(),
6868
)
6969
elif (
70-
self.cz_paired_correlated_rates is not None
71-
and self.cz_paired_error_probabilities is None
70+
self.cz_paired_correlated_rates is not None
71+
and self.cz_paired_error_probabilities is None
7272
):
7373

7474
if self.cz_paired_correlated_rates.shape != (4, 4):
@@ -83,8 +83,8 @@ def __post_init__(self):
8383
correlated_noise_array_to_dict(self.cz_paired_correlated_rates),
8484
)
8585
elif (
86-
self.cz_paired_correlated_rates is not None
87-
and self.cz_paired_error_probabilities is not None
86+
self.cz_paired_correlated_rates is not None
87+
and self.cz_paired_error_probabilities is not None
8888
):
8989
raise ValueError(
9090
"Received both `cz_paired_correlated_rates` and `cz_paired_correlated_rates` as input. This is ambiguous, please only set one."
@@ -113,7 +113,7 @@ def validate_moments(moments: Iterable[cirq.Moment]):
113113
)
114114

115115
def parallel_cz_errors(
116-
self, ctrls: list[int], qargs: list[int], rest: list[int]
116+
self, ctrls: list[int], qargs: list[int], rest: list[int]
117117
) -> dict[tuple[float, float, float, float], list[int]]:
118118
raise NotImplementedError(
119119
"This noise model doesn't support rewrites on bloqade kernels, but should be used with cirq."
@@ -179,7 +179,7 @@ class GeminiOneZoneNoiseModel(GeminiNoiseModelABC):
179179
parallelize_circuit: bool = False
180180

181181
def _single_qubit_moment_noise_ops(
182-
self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]
182+
self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]
183183
) -> tuple[list, list]:
184184
"""
185185
Helper function to determine the noise operations for a single qubit moment.
@@ -211,7 +211,7 @@ def _single_qubit_moment_noise_ops(
211211
op.qubits[0]
212212
for op in moment.operations
213213
if not (
214-
np.isclose(op.gate.x_exponent, 0) and np.isclose(op.gate.z_exponent, 0)
214+
np.isclose(op.gate.x_exponent, 0) and np.isclose(op.gate.z_exponent, 0)
215215
)
216216
]
217217

@@ -247,7 +247,8 @@ def noisy_moment(self, moment, system_qubits):
247247
gate_noise_ops = []
248248
# Check if the moment contains 1-qubit gates or 2-qubit gates
249249
elif len(moment.operations[0].qubits) == 1:
250-
if (isinstance(moment.operations[0].gate, cirq.ResetChannel)) or (cirq.is_measurement(moment.operations[0])):
250+
if (isinstance(moment.operations[0].gate, cirq.ResetChannel)) or (
251+
cirq.is_measurement(moment.operations[0])) or (isinstance(moment.operations[0].gate, cirq.BitFlipChannel)):
251252
move_noise_ops = []
252253
gate_noise_ops = []
253254
else:
@@ -301,7 +302,7 @@ def noisy_moment(self, moment, system_qubits):
301302
]
302303

303304
def noisy_moments(
304-
self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
305+
self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
305306
) -> Sequence[cirq.OP_TREE]:
306307
"""Adds possibly stateful noise to a series of moments.
307308
@@ -319,7 +320,8 @@ def noisy_moments(
319320

320321
# Split into moments with only 1Q and 2Q gates
321322
moments_1q = [
322-
cirq.Moment([op for op in moment.operations if (len(op.qubits) == 1) and (not cirq.is_measurement(op)) and (not isinstance(op.gate, cirq.ResetChannel))])
323+
cirq.Moment([op for op in moment.operations if (len(op.qubits) == 1) and (not cirq.is_measurement(op)) and (
324+
not isinstance(op.gate, cirq.ResetChannel))])
323325
for moment in moments
324326
]
325327
moments_2q = [
@@ -328,16 +330,46 @@ def noisy_moments(
328330
]
329331

330332
moments_measurement = [
331-
cirq.Moment([op for op in moment.operations if (cirq.is_measurement(op)) or (isinstance(op.gate, cirq.ResetChannel))])
333+
cirq.Moment([op for op in moment.operations if
334+
(cirq.is_measurement(op)) or (isinstance(op.gate, cirq.ResetChannel))])
332335
for moment in moments
333336
]
334337

335338
assert len(moments_1q) == len(moments_2q) == len(moments_measurement)
336339

337340
interleaved_moments = []
341+
342+
def count_remaining_cz_moments(moments_2q):
343+
cz = cirq.CZ
344+
remaining_cz_counts = []
345+
count = 0
346+
for m in moments_2q[::-1]:
347+
if any(isinstance(op.gate, type(cz)) for op in m.operations):
348+
count += 1
349+
remaining_cz_counts = [count] + remaining_cz_counts
350+
return remaining_cz_counts
351+
352+
remaining_cz_moments = count_remaining_cz_moments(moments_2q)
353+
354+
pm = 2 * self.sitter_pauli_rates[0]
355+
ps = 2 * self.cz_unpaired_pauli_rates[0]
356+
357+
#probability of a bitflip error for a sitting, unpaired qubit during a move/cz/move cycle.
358+
heuristic_1step_bitflip_error: float = 2 * pm * (1 - ps) * (1- pm) + (1 - pm)**2 * ps + pm**2 * ps
359+
338360
for idx, moment in enumerate(moments_1q):
339361
interleaved_moments.append(moment)
340362
interleaved_moments.append(moments_2q[idx])
363+
# Measurements on Gemini will be at the end, so for circuits with mid-circuit measurements we will insert a
364+
# bitflip error proportional to the number of moments left in the circuit to account for the decoherence
365+
# that will happen before the final terminal measurement.
366+
measured_qubits = []
367+
for op in moments_measurement[idx].operations:
368+
if cirq.is_measurement(op):
369+
measured_qubits += list(op.qubits)
370+
# probability of a bitflip error should be Binomial(moments_left,heuristic_1step_bitflip_error)
371+
delayed_measurement_error = (1 - (1 - 2 * heuristic_1step_bitflip_error) ** (remaining_cz_moments[idx])) / 2
372+
interleaved_moments.append(cirq.Moment(cirq.bit_flip(delayed_measurement_error).on_each(measured_qubits)))
341373
interleaved_moments.append(moments_measurement[idx])
342374

343375
interleaved_circuit = cirq.Circuit.from_moments(*interleaved_moments)
@@ -379,7 +411,8 @@ def noisy_moment(self, moment, system_qubits):
379411
gate_noise_ops = []
380412
# Check if the moment contains 1-qubit gates or 2-qubit gates
381413
elif len(moment.operations[0].qubits) == 1:
382-
if (isinstance(moment.operations[0].gate, cirq.ResetChannel)) or (cirq.is_measurement(moment.operations[0])):
414+
if (isinstance(moment.operations[0].gate, cirq.ResetChannel)) or (
415+
cirq.is_measurement(moment.operations[0])) or (isinstance(moment.operations[0].gate, cirq.BitFlipChannel)):
383416
gate_noise_ops = []
384417
else:
385418
gate_noise_ops, _ = self._single_qubit_moment_noise_ops(
@@ -449,7 +482,7 @@ def noisy_moment(self, moment, system_qubits):
449482
@dataclass(frozen=True)
450483
class GeminiTwoZoneNoiseModel(GeminiNoiseModelABC):
451484
def noisy_moments(
452-
self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
485+
self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
453486
) -> Sequence[cirq.OP_TREE]:
454487
"""Adds possibly stateful noise to a series of moments.
455488
@@ -481,12 +514,12 @@ def noisy_moments(
481514
[
482515
moment
483516
for moment in _two_zone_utils.get_move_error_channel_two_zoned(
484-
moments[i],
485-
prev_moment,
486-
np.array(self.mover_pauli_rates),
487-
np.array(self.sitter_pauli_rates),
488-
nqubs,
489-
).moments
517+
moments[i],
518+
prev_moment,
519+
np.array(self.mover_pauli_rates),
520+
np.array(self.sitter_pauli_rates),
521+
nqubs,
522+
).moments
490523
if len(moment) > 0
491524
]
492525
)
@@ -497,13 +530,13 @@ def noisy_moments(
497530
[
498531
moment
499532
for moment in _two_zone_utils.get_gate_error_channel(
500-
moments[i],
501-
np.array(self.local_pauli_rates),
502-
np.array(self.global_pauli_rates),
503-
self.two_qubit_pauli,
504-
np.array(self.cz_unpaired_pauli_rates),
505-
nqubs,
506-
).moments
533+
moments[i],
534+
np.array(self.local_pauli_rates),
535+
np.array(self.global_pauli_rates),
536+
self.two_qubit_pauli,
537+
np.array(self.cz_unpaired_pauli_rates),
538+
nqubs,
539+
).moments
507540
if len(moment) > 0
508541
]
509542
)

0 commit comments

Comments
 (0)