Leakage-Aware Decoding with LCD Demo#

Want to follow along? Download this notebook.

In this notebook, we briefly demonstrate Leakage functionality. In particular, we define a leakage noise model and add this to a generated surface code circuit. We then perform decoding with Riverlane’s Local Clustering Decoder (LCD), benchmarking leakage-aware decoding against leakage-unaware decoding.

Necessary imports#

from __future__ import annotations

from pathlib import Path

import matplotlib.pyplot as plt
from deltakit.explorer import Logging, Client, enums, types

Logging.set_log_to_console(False)
client = Client.get_instance()
data_folder = Path("../..") / "data"

Circuit generation and leakage noise#

distance = 5

# Generate a surface code circuit
compiled_circuit = client.generate_circuit(
      types.QECExperimentDefinition.get_rotated_planar_z_quantum_memory(
            distance=distance,
            num_rounds=distance,
            basis_gates=["CZ", "H", "MZ", "RZ"],
      )
)

Define SI1000+leakage noise model, where \(p\) is the physical error rate and \(p_l\) is the probability a 2-qubit gate causes a qubit to leak.

leakage_noise_model = types.SI1000NoiseModel(p=0.001, p_l=0.001)

# Add leakage noise to circuit
noisy_circuit = client.add_noise(
      stim_circuit=compiled_circuit,
      noise_model=leakage_noise_model,
)

Simulation and leakage-aware decoding#

def simulate_and_decode(
    noisy_circuit: str,
    num_shots: int,
    leakage_aware: bool,
    weighted: bool
) -> types.DecodingResult:
    # Circuit simulation
    measurements, leakage = client.simulate_stim_circuit(
        stim_circuit=noisy_circuit,
        shots=num_shots,
    )
    # Obtaining detector and observable data
    detectors, observables = measurements.to_detectors_and_observables(noisy_circuit)

    decoder = types.Decoder(
        decoder_type=enums.DecoderType.LCD,
        parameters={"weighted": weighted} if leakage_aware else None,
        parallel_jobs=4,
        use_experimental_graph=False,
    )
    # Decoding — providing leakage data with LCD allows for leakage-aware decoding
    return client.decode(
            detectors=detectors,
            observables=observables,
            decoder=decoder,
            noisy_stim_circuit=noisy_circuit,
            leakage_flags=leakage if leakage_aware else None,
    )
num_shots = 100000
rounds = [1, 3, 5]
decoding_experiments = {"leakage_unaware" : (False, False),
                        "leakage_aware" : (True, False),
                        "weighted_leakage_aware" : (True, True)}

results_dict = {key: [] for key in decoding_experiments}
errors_dict = {key: [] for key in decoding_experiments}

for num_rounds in rounds:
    # Generate a surface code circuit
    compiled_circuit = client.generate_circuit(
        types.QECExperimentDefinition.get_rotated_planar_z_quantum_memory(
            distance=distance,
            num_rounds=num_rounds,
            basis_gates=["CZ", "H", "MZ", "RZ"],
        )
    )
    # Add leakage noise
    noisy_circuit = client.add_noise(
        stim_circuit=compiled_circuit,
        noise_model=leakage_noise_model,
    )

    # Run the experiment with leakage-unaware, leakage-aware, and weighted leakage-aware
    for exp_type, specs in decoding_experiments.items():
        result = simulate_and_decode(noisy_circuit, num_shots, *specs)
        results_dict[exp_type].append(result.get_logical_error_probability())
        errors_dict[exp_type].append(result.get_standard_deviation())
simulation batches: 100%|██████████| 2/2 [00:02<00:00,  1.31s/it]
simulation batches: 100%|██████████| 2/2 [00:02<00:00,  1.31s/it]
simulation batches: 100%|██████████| 2/2 [00:02<00:00,  1.37s/it]
simulation batches: 100%|██████████| 2/2 [00:05<00:00,  2.65s/it]
simulation batches: 100%|██████████| 2/2 [00:05<00:00,  2.70s/it]
simulation batches: 100%|██████████| 2/2 [00:05<00:00,  2.72s/it]
simulation batches: 100%|██████████| 4/4 [00:08<00:00,  2.15s/it]
simulation batches: 100%|██████████| 4/4 [00:07<00:00,  1.97s/it]
simulation batches: 100%|██████████| 4/4 [00:08<00:00,  2.12s/it]
colours = ["#ff7500", "#006f62", "#1d3c34"]
linestyles = [None, None, "--"]

plt.figure(figsize=(10, 7))
plt.grid(color="gray", linestyle=":", linewidth=1)

for i, (key, value) in enumerate(results_dict.items()):
    plt.plot(rounds, value, label=key, color=colours[i], linestyle=linestyles[i])
    plt.errorbar(
        rounds,
        value,
        yerr=errors_dict[key],
        fmt=".",
        color=colours[i],
    )

plt.xticks(rounds)
plt.xlabel("Rounds")
plt.ylabel("Logical error probability")
plt.yscale("log")
plt.legend(fontsize=10)
plt.show()
../../../_images/39997ef9e26c4e0669a98f3224724dcc677ab74c5f7d55de8c42641c8af57559.png