Skip to content

Model

GeminiNoiseModelABC dataclass

GeminiNoiseModelABC(
    check_input_circuit: bool = True,
    cz_paired_correlated_rates: ndarray | None = None,
    cz_paired_error_probabilities: dict | None = None,
    *,
    local_px: float = 0.0004102,
    local_py: float = 0.0004102,
    local_pz: float = 0.0004112,
    local_loss_prob: float = 0.0,
    local_unaddressed_px: float = 2e-07,
    local_unaddressed_py: float = 2e-07,
    local_unaddressed_pz: float = 1.2e-06,
    local_unaddressed_loss_prob: float = 0.0,
    global_px: float = 6.5e-05,
    global_py: float = 6.5e-05,
    global_pz: float = 6.5e-05,
    global_loss_prob: float = 0.0,
    cz_paired_gate_px: float = 0.0006549,
    cz_paired_gate_py: float = 0.0006549,
    cz_paired_gate_pz: float = 0.003184,
    cz_gate_loss_prob: float = 0.0,
    cz_unpaired_gate_px: float = 0.0005149,
    cz_unpaired_gate_py: float = 0.0005149,
    cz_unpaired_gate_pz: float = 0.002185,
    cz_unpaired_loss_prob: float = 0.0,
    mover_px: float = 0.000806,
    mover_py: float = 0.000806,
    mover_pz: float = 0.002458,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0003066,
    sitter_py: float = 0.0003066,
    sitter_pz: float = 0.0004639,
    sit_loss_prob: float = 0.0
)

Bases: NoiseModel, MoveNoiseModelABC


              flowchart TD
              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC[GeminiNoiseModelABC]
              bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC[MoveNoiseModelABC]

                              bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiNoiseModelABC
                


              click bloqade.cirq_utils.noise.model.GeminiNoiseModelABC href "" "bloqade.cirq_utils.noise.model.GeminiNoiseModelABC"
              click bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC href "" "bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC"
            

Abstract base class for all Gemini noise models.

check_input_circuit class-attribute instance-attribute

check_input_circuit: bool = True

Determine whether or not to verify that the circuit only contains native gates.

Caution: Disabling this for circuits containing non-native gates may lead to incorrect results!

cz_paired_correlated_rates class-attribute instance-attribute

cz_paired_correlated_rates: ndarray | None = None

The correlated CZ error rates as a 4x4 array.

cz_paired_error_probabilities class-attribute instance-attribute

cz_paired_error_probabilities: dict | None = None

The correlated CZ error rates as a dictionary

parallel_cz_errors

parallel_cz_errors(
    ctrls: Sequence[int],
    qargs: Sequence[int],
    rest: Sequence[int],
) -> dict[tuple[float, float, float, float], list[int]]

Takes a set of ctrls and qargs and returns a noise model for all qubits.

Source code in .venv/lib/python3.12/site-packages/bloqade/cirq_utils/noise/model.py
122
123
124
125
126
127
def parallel_cz_errors(
    self, ctrls: Sequence[int], qargs: Sequence[int], rest: Sequence[int]
) -> dict[tuple[float, float, float, float], list[int]]:
    raise NotImplementedError(
        "This noise model doesn't support rewrites on bloqade kernels, but should be used with cirq."
    )

GeminiOneZoneNoiseModel dataclass

GeminiOneZoneNoiseModel(
    check_input_circuit: bool = True,
    cz_paired_correlated_rates: ndarray | None = None,
    cz_paired_error_probabilities: dict | None = None,
    parallelize_circuit: bool = False,
    *,
    local_px: float = 0.0004102,
    local_py: float = 0.0004102,
    local_pz: float = 0.0004112,
    local_loss_prob: float = 0.0,
    local_unaddressed_px: float = 2e-07,
    local_unaddressed_py: float = 2e-07,
    local_unaddressed_pz: float = 1.2e-06,
    local_unaddressed_loss_prob: float = 0.0,
    global_px: float = 6.5e-05,
    global_py: float = 6.5e-05,
    global_pz: float = 6.5e-05,
    global_loss_prob: float = 0.0,
    cz_paired_gate_px: float = 0.0006549,
    cz_paired_gate_py: float = 0.0006549,
    cz_paired_gate_pz: float = 0.003184,
    cz_gate_loss_prob: float = 0.0,
    cz_unpaired_gate_px: float = 0.0005149,
    cz_unpaired_gate_py: float = 0.0005149,
    cz_unpaired_gate_pz: float = 0.002185,
    cz_unpaired_loss_prob: float = 0.0,
    mover_px: float = 0.000806,
    mover_py: float = 0.000806,
    mover_pz: float = 0.002458,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0003066,
    sitter_py: float = 0.0003066,
    sitter_pz: float = 0.0004639,
    sit_loss_prob: float = 0.0
)

Bases: GeminiNoiseModelABC


              flowchart TD
              bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel[GeminiOneZoneNoiseModel]
              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC[GeminiNoiseModelABC]
              bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC[MoveNoiseModelABC]

                              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel
                                bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiNoiseModelABC
                



              click bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel href "" "bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel"
              click bloqade.cirq_utils.noise.model.GeminiNoiseModelABC href "" "bloqade.cirq_utils.noise.model.GeminiNoiseModelABC"
              click bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC href "" "bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC"
            

A Cirq-compatible noise model for a one-zone implementation of the Gemini architecture.

This model introduces custom asymmetric depolarizing noise for both single- and two-qubit gates depending on whether operations are global, local, or part of a CZ interaction. Since the model assumes all atoms are in the entangling zone, errors are applied that stem from application of Rydberg error, even for qubits not actively involved in a gate operation.

Note, that the noise applied to entangling pairs is correlated.

noisy_moments

noisy_moments(
    moments: Iterable[Moment], system_qubits: Sequence[Qid]
) -> Sequence[cirq.OP_TREE]

Adds possibly stateful noise to a series of moments.

Parameters:

Name Type Description Default
moments Iterable[Moment]

The moments to add noise to.

required
system_qubits Sequence[Qid]

A list of all qubits in the system.

required

Returns:

Type Description
Sequence[OP_TREE]

A sequence of OP_TREEEs, with the k'th tree corresponding to the

Sequence[OP_TREE]

noisy operations for the k'th moment.

Source code in .venv/lib/python3.12/site-packages/bloqade/cirq_utils/noise/model.py
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def noisy_moments(
    self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
) -> Sequence[cirq.OP_TREE]:
    """Adds possibly stateful noise to a series of moments.

    Args:
        moments: The moments to add noise to.
        system_qubits: A list of all qubits in the system.

    Returns:
        A sequence of OP_TREEEs, with the k'th tree corresponding to the
        noisy operations for the k'th moment.
    """

    if self.check_input_circuit:
        self.validate_moments(moments)

    # Split into moments with only 1Q and 2Q gates
    moments_1q = [
        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))
            ]
        )
        for moment in moments
    ]
    moments_2q = [
        cirq.Moment(
            [
                op
                for op in moment.operations
                if (len(op.qubits) == 2) and (not cirq.is_measurement(op))
            ]
        )
        for moment in moments
    ]

    moments_measurement = [
        cirq.Moment(
            [
                op
                for op in moment.operations
                if (cirq.is_measurement(op))
                or (isinstance(op.gate, cirq.ResetChannel))
            ]
        )
        for moment in moments
    ]

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

    interleaved_moments = []

    def count_remaining_cz_moments(moments_2q):
        remaining_cz_counts = []
        count = 0
        for m in moments_2q[::-1]:
            if any(isinstance(op.gate, cirq.CZPowGate) for op in m.operations):
                count += 1
            remaining_cz_counts = [count] + remaining_cz_counts
        return remaining_cz_counts

    remaining_cz_moments = count_remaining_cz_moments(moments_2q)

    pm = 2 * self.sitter_pauli_rates[0]
    ps = 2 * self.cz_unpaired_pauli_rates[0]

    # probability of a bitflip error for a sitting, unpaired qubit during a move/cz/move cycle.
    heuristic_1step_bitflip_error: float = (
        2 * pm * (1 - ps) * (1 - pm) + (1 - pm) ** 2 * ps + pm**2 * ps
    )

    for idx, moment in enumerate(moments_1q):
        interleaved_moments.append(moment)
        interleaved_moments.append(moments_2q[idx])
        # Measurements on Gemini will be at the end, so for circuits with mid-circuit measurements we will insert a
        # bitflip error proportional to the number of moments left in the circuit to account for the decoherence
        # that will happen before the final terminal measurement.
        measured_qubits = []
        for op in moments_measurement[idx].operations:
            if cirq.is_measurement(op):
                measured_qubits += list(op.qubits)
        # probability of a bitflip error should be Binomial(moments_left,heuristic_1step_bitflip_error)
        delayed_measurement_error = (
            1
            - (1 - 2 * heuristic_1step_bitflip_error) ** (remaining_cz_moments[idx])
        ) / 2
        interleaved_moments.append(
            cirq.Moment(
                cirq.bit_flip(delayed_measurement_error).on_each(measured_qubits)
            )
        )
        interleaved_moments.append(moments_measurement[idx])

    interleaved_circuit = cirq.Circuit.from_moments(*interleaved_moments)

    # Combine subsequent 1Q gates
    compressed_circuit = cirq.merge_single_qubit_moments_to_phxz(
        interleaved_circuit
    )
    if self.parallelize_circuit:
        compressed_circuit = parallelize(compressed_circuit)

    return self._noisy_moments_impl_moment(
        compressed_circuit.moments, system_qubits
    )

GeminiOneZoneNoiseModelConflictGraphMoves dataclass

GeminiOneZoneNoiseModelConflictGraphMoves(
    check_input_circuit: bool = True,
    cz_paired_correlated_rates: ndarray | None = None,
    cz_paired_error_probabilities: dict | None = None,
    parallelize_circuit: bool = False,
    max_parallel_movers: int = 10000,
    *,
    local_px: float = 0.0004102,
    local_py: float = 0.0004102,
    local_pz: float = 0.0004112,
    local_loss_prob: float = 0.0,
    local_unaddressed_px: float = 2e-07,
    local_unaddressed_py: float = 2e-07,
    local_unaddressed_pz: float = 1.2e-06,
    local_unaddressed_loss_prob: float = 0.0,
    global_px: float = 6.5e-05,
    global_py: float = 6.5e-05,
    global_pz: float = 6.5e-05,
    global_loss_prob: float = 0.0,
    cz_paired_gate_px: float = 0.0006549,
    cz_paired_gate_py: float = 0.0006549,
    cz_paired_gate_pz: float = 0.003184,
    cz_gate_loss_prob: float = 0.0,
    cz_unpaired_gate_px: float = 0.0005149,
    cz_unpaired_gate_py: float = 0.0005149,
    cz_unpaired_gate_pz: float = 0.002185,
    cz_unpaired_loss_prob: float = 0.0,
    mover_px: float = 0.000806,
    mover_py: float = 0.000806,
    mover_pz: float = 0.002458,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0003066,
    sitter_py: float = 0.0003066,
    sitter_pz: float = 0.0004639,
    sit_loss_prob: float = 0.0
)

Bases: GeminiOneZoneNoiseModel


              flowchart TD
              bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModelConflictGraphMoves[GeminiOneZoneNoiseModelConflictGraphMoves]
              bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel[GeminiOneZoneNoiseModel]
              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC[GeminiNoiseModelABC]
              bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC[MoveNoiseModelABC]

                              bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel --> bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModelConflictGraphMoves
                                bloqade.cirq_utils.noise.model.GeminiNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel
                                bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiNoiseModelABC
                




              click bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModelConflictGraphMoves href "" "bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModelConflictGraphMoves"
              click bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel href "" "bloqade.cirq_utils.noise.model.GeminiOneZoneNoiseModel"
              click bloqade.cirq_utils.noise.model.GeminiNoiseModelABC href "" "bloqade.cirq_utils.noise.model.GeminiNoiseModelABC"
              click bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC href "" "bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC"
            

A Cirq noise model that uses a conflict graph to schedule moves in a one-zone Gemini architecture.

Assumes that the qubits are cirq.GridQubits, such that the assignment of row, column coordinates define the initial geometry. An SLM site at the two qubit interaction distance is also assumed next to each cirq.GridQubit to allow for multiple moves before a single Rydberg pulse is applied for a parallel CZ.

GeminiTwoZoneNoiseModel dataclass

GeminiTwoZoneNoiseModel(
    check_input_circuit: bool = True,
    cz_paired_correlated_rates: ndarray | None = None,
    cz_paired_error_probabilities: dict | None = None,
    *,
    local_px: float = 0.0004102,
    local_py: float = 0.0004102,
    local_pz: float = 0.0004112,
    local_loss_prob: float = 0.0,
    local_unaddressed_px: float = 2e-07,
    local_unaddressed_py: float = 2e-07,
    local_unaddressed_pz: float = 1.2e-06,
    local_unaddressed_loss_prob: float = 0.0,
    global_px: float = 6.5e-05,
    global_py: float = 6.5e-05,
    global_pz: float = 6.5e-05,
    global_loss_prob: float = 0.0,
    cz_paired_gate_px: float = 0.0006549,
    cz_paired_gate_py: float = 0.0006549,
    cz_paired_gate_pz: float = 0.003184,
    cz_gate_loss_prob: float = 0.0,
    cz_unpaired_gate_px: float = 0.0005149,
    cz_unpaired_gate_py: float = 0.0005149,
    cz_unpaired_gate_pz: float = 0.002185,
    cz_unpaired_loss_prob: float = 0.0,
    mover_px: float = 0.000806,
    mover_py: float = 0.000806,
    mover_pz: float = 0.002458,
    move_loss_prob: float = 0.0,
    sitter_px: float = 0.0003066,
    sitter_py: float = 0.0003066,
    sitter_pz: float = 0.0004639,
    sit_loss_prob: float = 0.0
)

Bases: GeminiNoiseModelABC


              flowchart TD
              bloqade.cirq_utils.noise.model.GeminiTwoZoneNoiseModel[GeminiTwoZoneNoiseModel]
              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC[GeminiNoiseModelABC]
              bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC[MoveNoiseModelABC]

                              bloqade.cirq_utils.noise.model.GeminiNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiTwoZoneNoiseModel
                                bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC --> bloqade.cirq_utils.noise.model.GeminiNoiseModelABC
                



              click bloqade.cirq_utils.noise.model.GeminiTwoZoneNoiseModel href "" "bloqade.cirq_utils.noise.model.GeminiTwoZoneNoiseModel"
              click bloqade.cirq_utils.noise.model.GeminiNoiseModelABC href "" "bloqade.cirq_utils.noise.model.GeminiNoiseModelABC"
              click bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC href "" "bloqade.qasm2.dialects.noise.model.MoveNoiseModelABC"
            

noisy_moments

noisy_moments(
    moments: Iterable[Moment], system_qubits: Sequence[Qid]
) -> Sequence[cirq.OP_TREE]

Adds possibly stateful noise to a series of moments.

Parameters:

Name Type Description Default
moments Iterable[Moment]

The moments to add noise to.

required
system_qubits Sequence[Qid]

A list of all qubits in the system.

required

Returns:

Type Description
Sequence[OP_TREE]

A sequence of OP_TREEEs, with the k'th tree corresponding to the

Sequence[OP_TREE]

noisy operations for the k'th moment.

Source code in .venv/lib/python3.12/site-packages/bloqade/cirq_utils/noise/model.py
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
def noisy_moments(
    self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
) -> Sequence[cirq.OP_TREE]:
    """Adds possibly stateful noise to a series of moments.

    Args:
        moments: The moments to add noise to.
        system_qubits: A list of all qubits in the system.

    Returns:
        A sequence of OP_TREEEs, with the k'th tree corresponding to the
        noisy operations for the k'th moment.
    """

    if self.check_input_circuit:
        self.validate_moments(moments)

    moments = list(moments)

    if len(moments) == 0:
        return []

    nqubs = len(system_qubits)
    noisy_moment_list = []

    prev_moment: cirq.Moment | None = None

    # TODO: clean up error getters so they return a list moments rather than circuits
    for i in range(len(moments)):
        noisy_moment_list.extend(
            [
                moment
                for moment in _two_zone_utils.get_move_error_channel_two_zoned(
                    moments[i],
                    prev_moment,
                    np.array(self.mover_pauli_rates),
                    np.array(self.sitter_pauli_rates),
                    nqubs,
                ).moments
                if len(moment) > 0
            ]
        )

        noisy_moment_list.append(moments[i])

        noisy_moment_list.extend(
            [
                moment
                for moment in _two_zone_utils.get_gate_error_channel(
                    moments[i],
                    np.array(self.local_pauli_rates),
                    np.array(self.global_pauli_rates),
                    self.two_qubit_pauli,
                    np.array(self.cz_unpaired_pauli_rates),
                    nqubs,
                ).moments
                if len(moment) > 0
            ]
        )

        prev_moment = moments[i]

    return noisy_moment_list