From 78c075460b0e68bfdc2de787cbed6a06a45273e5 Mon Sep 17 00:00:00 2001 From: Dennis Wayo <117969019+DennisWayo@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:29:47 +0500 Subject: [PATCH 1/2] Add GKP QEC photonic demo --- .../tutorial_gkp_qec_photonic_s01/demo.py | 1107 +++++++++++++++++ .../metadata.json | 103 ++ 2 files changed, 1210 insertions(+) create mode 100644 demonstrations_v2/tutorial_gkp_qec_photonic_s01/demo.py create mode 100644 demonstrations_v2/tutorial_gkp_qec_photonic_s01/metadata.json diff --git a/demonstrations_v2/tutorial_gkp_qec_photonic_s01/demo.py b/demonstrations_v2/tutorial_gkp_qec_photonic_s01/demo.py new file mode 100644 index 0000000000..e31c03f860 --- /dev/null +++ b/demonstrations_v2/tutorial_gkp_qec_photonic_s01/demo.py @@ -0,0 +1,1107 @@ +r"""GKP-Based Quantum Error Correction in Photonic Systems +====================================================== + +**Bundled series:** S01-S05 + +This bundled demo keeps the original storyline across S01 to S05 in one `demo.py`, with the +section narratives preserved in sequence. +""" + +###################################################################### +# Introduction +# ------------ +# +# Let’s start with the big picture. Photonic hardware is continuous-variable, but most quantum +# algorithms are written in terms of discrete qubits. A GKP-encoded logical qubit is the bridge +# between those worlds: it hides the oscillator details and exposes a clean two-level abstraction to +# software. +# +# That abstraction makes programming easier, but it doesn’t make noise disappear. As soon as we encode +# information, errors creep in. So we need error correction to keep the logical information stable. +# +# There are many codes out there—repetition, Shor, Steane, surface codes, and bosonic codes. For +# photonic systems, bosonic codes are a natural fit. This family includes GKP, cat codes, binomial +# codes, and Fock-state encodings. +# +# Among these, the Gottesman–Kitaev–Preskill (GKP) code plays a central role. GKP encoding stores +# logical qubits in grid-like structures in phase space, allowing small displacement errors—common in +# photonic systems—to be detected and corrected. +# +# In this demo we stay at the software layer. We’ll follow a simple flow: logical state → error +# syndrome → correction. We won’t simulate optics; we’ll focus on the logical effect. +# + +###################################################################### +# Logical Qubit Model in PennyLane +# -------------------------------- +# +# From a software point of view, a GKP logical qubit can be treated as an effective two-level system +# with a density matrix :math:`\rho`. The messy continuous-variable details live underneath, and their +# net effect shows up as an effective logical noise channel: +# +# .. math:: +# +# +# \rho \;\longrightarrow\; \mathcal{E}(\rho). +# +# Here :math:`\mathcal{E}` is a completely positive, trace-preserving (CPTP) map that represents +# residual logical errors after correction. This is the architecture-level view used in the original +# GKP proposal and later fault-tolerant extensions [1,2]. +# +# In practice, many different logical noise models are possible. PennyLane [5] provides a range of +# quantum channels for this purpose, including ``qml.PhaseDamping``, ``qml.BitFlip``, +# ``qml.PhaseFlip``, ``qml.AmplitudeDamping``, and ``qml.GeneralizedAmplitudeDamping``. Each +# corresponds to a different way logical information can degrade once the system is viewed as an +# effective qubit. +# +# In this demo, we focus on the depolarizing channel, implemented in PennyLane as +# ``qml.DepolarizingChannel``. At the mathematical level, it acts as +# +# .. math:: +# +# +# \mathcal{E}_{\text{dep}}(\rho) +# \;=\; +# (1 - p)\,\rho +# \;+ +# \;\frac{p}{3} +# \left( +# X \rho X +# + +# Y \rho Y +# + +# Z \rho Z +# \right), +# +# where :math:`p \in [0,1]` is the effective logical noise strength and :math:`X`, :math:`Y`, +# :math:`Z` are the Pauli operators. You can read this as: with total probability :math:`p`, a random +# Pauli error is applied; otherwise the state is left alone. +# +# The appeal of this model is clarity, not physical realism. In a real photonic system, residual +# logical noise after GKP correction arises from finite squeezing, photon loss, measurement +# imprecision, and imperfect decoding [1,4]. Modeling all of that explicitly would obscure the main +# point here. +# +# Instead, the depolarizing channel gives us a clean, hardware-agnostic way to represent the net +# outcome of imperfect GKP error correction: a single parameter :math:`p` that tells us how much +# logical noise remains once the physical correction procedures have done their work. +# + +###################################################################### +# Requirements +# ------------ +# +# This demo uses PennyLane to illustrate logical noise and error correction at the software level. +# Plots are generated with Matplotlib. +# +# If PennyLane is not already installed, it can be installed with: +# +# .. code:: bash +# +# pip install pennylane matplotlib +# + +###################################################################### +# Case 1: Logical coherence under effective noise +# ----------------------------------------------- +# +# *Thinking question: “What does logical noise do if we don’t correct it well enough?”* +# +# Before thinking about error correction, it’s useful to see how logical information degrades in the +# presence of noise. +# +# From a software perspective, one of the simplest indicators of whether a logical qubit is behaving +# well is its coherence. For a qubit prepared in a superposition state, coherence tells us how +# reliably quantum information can be processed and interfered. +# +# In this example, we prepare a logical qubit in a superposition using a Hadamard gate and then apply +# an effective logical noise channel. We monitor the expectation value ``⟨X⟩``, which serves as a +# proxy for logical coherence. As the strength of the effective noise increases, we expect this +# coherence to decrease. +# +# The goal here is not to model the physical noise acting on a photonic system, but to observe how +# residual imperfections, after encoding and (imperfect) error correction, appear at the logical level +# seen by quantum software. +# + +import numpy as np +import matplotlib.pyplot as plt +import pennylane as qml + +# Use a mixed-state simulator to model logical noise +dev = qml.device("default.mixed", wires=1) + + +def apply_plot_style(): + plt.rcParams.update( + { + "figure.dpi": 120, + "savefig.dpi": 300, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "axes.axisbelow": True, + "grid.alpha": 0.25, + "grid.linestyle": "--", + "axes.labelsize": 12, + "axes.titlesize": 13, + "axes.titlepad": 10, + "legend.frameon": False, + "legend.fontsize": 11, + "lines.linewidth": 2.4, + "lines.markersize": 5, + } + ) + + +apply_plot_style() +colors = { + "raw": "#1b9e77", + "corrected": "#d95f02", +} + + +@qml.qnode(dev) +def logical_gkp_coherence(noise_strength): + '''Logical qubit prepared in a superposition and subjected to effective logical noise.''' + qml.Hadamard(wires=0) # logical Clifford operation + qml.DepolarizingChannel(noise_strength, wires=0) # effective logical noise + return qml.expval(qml.PauliX(0)) # logical coherence + + +print("Logical GKP qubit circuit (effective model):") +print(qml.draw(logical_gkp_coherence)(0.1)) + + +# --- Sweep effective logical noise strength --- +ps = np.linspace(0.0, 0.30, 61) +coherences = np.array([logical_gkp_coherence(p) for p in ps]) + +# --- Plot logical coherence decay --- +fig, ax = plt.subplots(figsize=(6.5, 4)) +ax.plot(ps, coherences, color=colors["raw"], marker="o", markevery=6, label="Logical coherence") +ax.set_xlabel("Effective logical noise strength p") +ax.set_ylabel(r"Logical coherence $\langle X \rangle$") +ax.set_title("Case 1: Coherence decay under effective noise") +ax.set_xlim(ps.min(), ps.max()) +ax.set_ylim(0.5, 1.02) +ax.legend() +fig.tight_layout() +plt.show() + + +###################################################################### +# *What are we seeing here in case 1 above?* +# +# Let’s walk through the results in plain language. +# +# We prepare a logical qubit in a superposition using a Hadamard gate. In a noiseless world, this +# state is perfectly coherent. Measuring ``⟨X⟩`` gives ``1.0``, which tells us the superposition is +# intact. +# +# Now we dial up effective logical noise using the depolarizing channel. This noise is not meant to +# describe the detailed physics of photons; it just captures the net effect of imperfections after +# encoding and imperfect correction. +# +# As the noise strength ``p`` increases, the trend is clear: +# +# - When ``p = 0.00``, ``⟨X⟩ = 1.000`` -> the logical qubit is perfectly coherent. +# - As ``p`` increases, ``⟨X⟩`` gradually decreases. +# - By ``p = 0.30``, ``⟨X⟩`` is about ``0.60``. +# +# This is the simplest picture of logical noise: the circuit is still trivial, but the coherence +# steadily fades. +# +# *How do we correct this?* +# +# In Case 2, we model how GKP correction reduces the effective logical noise. +# + +###################################################################### +# Case 2: What changes when error correction does its job? +# -------------------------------------------------------- +# +# In Case 1, we deliberately looked at what happens when effective logical noise is left unchecked. +# The takeaway was simple: as logical noise increases, coherence steadily decays, and the quantum +# state becomes less useful for computation. +# +# Now let’s flip the question: +# +# *What if error correction successfully suppresses logical noise?* +# +# At the software level, this does not mean that noise disappears completely. Instead, it means that +# the effective logical noise strength is reduced. The circuit stays the same; the noise parameter +# changes. +# + +# Effective logical noise ranges +p_raw = np.linspace(0.0, 0.30, 61) # before correction +alpha = 0.25 # correction efficiency factor +p_corrected = alpha * p_raw # after correction + +# Compute coherences +coh_raw = np.array([logical_gkp_coherence(p) for p in p_raw]) +coh_corrected = np.array([logical_gkp_coherence(p) for p in p_corrected]) + +# Plot +fig, ax = plt.subplots(figsize=(6.5, 4)) +ax.plot(p_raw, coh_raw, "o-", color=colors["raw"], markevery=6, label="Before correction") +ax.plot(p_raw, coh_corrected, "s--", color=colors["corrected"], markevery=6, label="After correction") +ax.fill_between(p_raw, coh_corrected, coh_raw, color=colors["corrected"], alpha=0.12) +ax.text(0.02, 0.52, rf"$\alpha = {alpha:.2f}$", transform=ax.transAxes, color=colors["corrected"]) + +ax.set_xlabel("Effective logical noise strength p") +ax.set_ylabel(r"Logical coherence $\langle X \rangle$") +ax.set_title("Case 2: Coherence improvement after GKP correction") +ax.set_xlim(p_raw.min(), p_raw.max()) +ax.set_ylim(0.5, 1.02) +ax.legend() +fig.tight_layout() +plt.show() + + +###################################################################### +# In Case 2, we model the effect of GKP error correction by reducing the effective logical noise +# strength according to +# +# .. math:: +# +# +# p_{\text{corrected}} = \alpha \, p_{\text{raw}} . +# +# Here, ``p_raw`` represents the effective logical noise seen by a qubit before error correction, +# while ``p_corrected`` represents the noise that remains after correction. The parameter +# :math:`\alpha \in (0,1)` captures how effective the error-correction process is at suppressing +# logical errors. +# +# Intuitively, :math:`\alpha` acts as a correction efficiency factor. Values of :math:`\alpha` closer +# to one correspond to weaker correction, where a large fraction of the logical noise survives. +# Smaller values of :math:`\alpha` correspond to stronger correction, where logical errors are more +# effectively suppressed. +# +# It is important to emphasize that :math:`\alpha` is not derived from hardware physics in this demo. +# In a real photonic system, its value would depend on concrete physical factors such as squeezing +# levels, photon loss rates, measurement precision, and decoding strategies. Here, we deliberately +# treat :math:`\alpha` as a tunable knob that lets us explore how improved error correction would +# appear at the software level, without committing to a specific hardware implementation. +# +# *How should we interpret the result in Case 2?* +# +# The key thing to notice in the figure above is that the logical circuit itself never changes. +# +# In both cases, ``before and after correction``, we prepare the same logical qubit, apply the same +# Hadamard gate, and measure the same observable ``⟨X⟩``. There are no additional logical gates, no +# explicit correction steps, and no extra measurements introduced at the circuit level. From the +# software’s point of view, everything looks identical. +# +# What does change is the effective logical noise associated with the qubit. Before correction, +# increasing logical noise leads to a steady decay of coherence. After correction, the same sweep of +# conditions corresponds to a reduced effective logical noise, and the coherence remains significantly +# higher across the entire range. +# +# **The separation between the two curves is therefore the software-level signature of GKP error +# correction.** +# +# *What is actually happening under the hood?* +# +# GKP error correction operates on the physical photonic degrees of freedom—continuous variables such +# as small displacements in phase space, well below the level of this circuit. Those physical +# processes never appear explicitly in the logical program. They can, however, introduce substantial +# overhead at the hardware and control layers (syndrome extraction, decoding, feedforward, and time). +# +# Instead, their net effect is captured by a reduction in the logical noise experienced by the qubit. +# In this demo, that reduction is modeled by scaling the effective logical noise parameter through +# :math:`\alpha`. Smaller values of :math:`\alpha` correspond to more effective correction, while +# larger values indicate that more logical noise remains. +# +# While the numerical value of :math:`\alpha` is hardware-dependent in practice, the qualitative +# outcome is universal: successful GKP correction suppresses logical errors before the qubit is +# exposed to the program. +# +# *Why this matters for quantum software* +# +# From the perspective of an algorithm designer, error correction is not something you manually +# invoke. It is something that improves the quality of the logical qubits you are given. +# +# This is why high-level frameworks like PennyLane can treat logical qubits uniformly, regardless of +# whether they come from superconducting devices, trapped ions, or photonic GKP encodings. The +# software interacts with the same abstraction; only the effective noise differs. +# +# *Lessons drawn from Case 2* +# +# Effective error correction shows up at the software level as noise suppression, not circuit +# complexity. GKP encoding allows photonic hardware to deliver logical qubits that behave closer to +# ideal qubits, while keeping the continuous-variable physics hidden beneath the abstraction layer. +# + +###################################################################### +# Summary: What we did — and what we didn’t +# ----------------------------------------- +# +# *What we did* +# +# We treated a GKP-encoded photonic qubit as a logical two-level system with an effective noise +# channel. Using PennyLane’s ``DepolarizingChannel`` on ``default.mixed``, we saw that: +# +# - logical coherence decays as effective logical noise increases (Case 1). +# - improved error correction appears as a reduction in that effective noise, leading to higher +# coherence without changing the circuit (Case 2). +# +# *What we didn’t do* +# +# We did not simulate the physical implementation of GKP error correction. In particular, this demo +# does not include: +# +# - non-Gaussian continuous-variable simulations of GKP states. +# - explicit syndrome extraction or displacement correction. +# - feedforward operations or decoding circuits. +# - hardware-specific noise models such as photon loss or finite squeezing. +# +# The correction efficiency parameter :math:`\alpha` is treated as a tunable abstraction, not derived +# from first-principles hardware physics. +# + +###################################################################### +# Conclusion +# ---------- +# +# If you’re writing quantum software, GKP error correction shows up as better logical qubits, not as +# extra gates in your program. That’s the key takeaway of this demo. +# +# We kept the circuit fixed and watched how logical noise affects coherence. Then we modeled +# correction as a reduction in that noise. The result is a clear software-level picture of GKP error +# correction: the logical circuit stays the same, while the effective noise gets smaller. +# + +###################################################################### +# AI-use disclosure +# ----------------- +# +# ChatGPT model support was used only for language editing and writing clarity checks. +# +# Experimental design, implementation, tuning, verification, and all technical conclusions are the +# author’s own work and responsibility. +# +# All notebook content was reviewed by the author before submission. +# +# Any opinions, findings, conclusions, or recommendations expressed in this demo are those of the +# author(s) and do not necessarily reflect the views of PennyLane. +# + +###################################################################### +# Further reading +# --------------- +# +# For readers who would like to explore these ideas in more depth, the following references provide +# useful background on GKP encoding, bosonic error correction, and photonic quantum computing: +# +# - [1] **D. Gottesman, A. Kitaev, and J. Preskill**, *Encoding a qubit in an oscillator*, +# arXiv:quant-ph/0008040 (2000). https://arxiv.org/abs/quant-ph/0008040 +# +# - [2] **N. C. Menicucci**, *Fault-tolerant measurement-based quantum computing with +# continuous-variable cluster states*, *Physical Review Letters* **112**, 120504 (2014). +# https://doi.org/10.1103/PhysRevLett.112.120504 +# +# - [3] **M. Mirrahimi et al.**, *Dynamically protected cat-qubits: a new paradigm for universal +# quantum computation*, *New Journal of Physics* **16**, 045014 (2014). +# https://doi.org/10.1088/1367-2630/16/4/045014 +# +# - [4] **M. Banić et al.**, *Exact simulation of realistic Gottesman–Kitaev–Preskill cluster states*, +# *Physical Review A* **112**, 052425 (2025). https://doi.org/10.1103/PhysRevA.112.052425 +# +# - [5] **V. Bergholm et al.**, *PennyLane: Automatic differentiation of hybrid quantum–classical +# computations*, arXiv:1811.04968 (2018). https://arxiv.org/abs/1811.04968 +# + +###################################################################### +# Series continuation (S02) +# ------------------------- + +###################################################################### +# Error correction as noise suppression +# ------------------------------------- +# +# In S01 we treated the logical noise strength ``p`` as a direct knob. In this installment we connect +# that knob to a more physical idea: phase-space displacement noise. +# +# The circuit stays the same. What changes is how we *generate* the effective logical noise strength +# we feed into it. +# + +###################################################################### +# From phase-space noise to logical errors +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# In photonic systems, a common physical noise process is a small displacement in phase space. We can +# write it as +# +# .. math:: +# +# +# D(\epsilon_q, \epsilon_p), +# +# where :math:`\epsilon_q` and :math:`\epsilon_p` are small shifts in the position and momentum +# quadratures of the oscillator. +# +# The GKP code protects against these displacements by measuring syndromes and applying corrective +# displacements. If a physical displacement exceeds the correction threshold, a logical error occurs. +# +# In this demo we do not simulate the full oscillator dynamics. Instead, we map a *displacement scale* +# to an effective logical noise strength and study how correction suppresses that logical noise. +# + +###################################################################### +# Simple correction model +# ~~~~~~~~~~~~~~~~~~~~~~~ +# +# To keep things simple, we introduce a toy mapping from a displacement scale :math:`\sigma` to a +# logical error rate: +# +# .. math:: +# +# +# p_{\text{raw}}(\sigma) = 1 - e^{-(\sigma / \sigma_0)^2}. +# +# This is not derived from hardware physics. It is just a smooth, monotonic map from a physical noise +# scale to a logical error probability. The parameter :math:`\sigma_0` sets the scale. +# +# We then model correction as a suppression of that logical noise: +# +# .. math:: +# +# +# p_{\text{corrected}} = \\alpha \, p_{\text{raw}}, +# +# with :math:`\\alpha \in (0,1)`. Smaller :math:`\\alpha` means stronger correction. +# + +import os + +# Ensure a writable Matplotlib cache and a safe backend for notebooks +os.environ.setdefault("MPLCONFIGDIR", "/tmp/matplotlib") +os.environ.setdefault("IPYTHONDIR", "/tmp/ipython") + +import matplotlib +try: + from IPython import get_ipython + + if get_ipython() is not None: + matplotlib.use("module://matplotlib_inline.backend_inline") +except Exception: + pass + +import numpy as np +import matplotlib.pyplot as plt +import pennylane as qml + +# Use a mixed-state simulator to model logical noise +dev = qml.device("default.mixed", wires=1) + + +def apply_plot_style(): + plt.rcParams.update( + { + "figure.dpi": 120, + "savefig.dpi": 300, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "axes.axisbelow": True, + "grid.alpha": 0.25, + "grid.linestyle": "--", + "axes.labelsize": 12, + "axes.titlesize": 13, + "axes.titlepad": 10, + "legend.frameon": False, + "legend.fontsize": 11, + "lines.linewidth": 2.4, + "lines.markersize": 5, + } + ) + + +apply_plot_style() +colors = { + "raw": "#1b9e77", + "corrected": "#d95f02", +} + + +@qml.qnode(dev) +def logical_gkp_coherence(noise_strength): + """Logical qubit prepared in a superposition and subjected to logical noise.""" + qml.Hadamard(wires=0) + qml.DepolarizingChannel(noise_strength, wires=0) + return qml.expval(qml.PauliX(0)) + + +# Physical noise scale (toy model) +sigma = np.linspace(0.0, 0.6, 61) +sigma0 = 0.35 + +# Map displacement scale to logical noise strength +p_raw = 1.0 - np.exp(-(sigma / sigma0) ** 2) + +# Apply correction model +alpha = 0.25 +p_corrected = alpha * p_raw + +# Compute coherence +coh_raw = np.array([logical_gkp_coherence(p) for p in p_raw]) +coh_corrected = np.array([logical_gkp_coherence(p) for p in p_corrected]) + +# Plot +fig, ax = plt.subplots(figsize=(6.5, 4)) +ax.plot(sigma, coh_raw, "o-", color=colors["raw"], markevery=6, label="Before correction") +ax.plot(sigma, coh_corrected, "s--", color=colors["corrected"], markevery=6, label="After correction") +ax.fill_between(sigma, coh_corrected, coh_raw, color=colors["corrected"], alpha=0.12) +ax.text(0.02, 0.52, rf"$\alpha = {alpha:.2f}$", transform=ax.transAxes, color=colors["corrected"]) + +ax.set_xlabel(r"Displacement scale $\sigma$ (toy model)") +ax.set_ylabel(r"Logical coherence $\langle X \rangle$") +ax.set_title("S02: Error correction as noise suppression") +ax.set_xlim(sigma.min(), sigma.max()) +ax.set_ylim(0.5, 1.02) +ax.legend() +fig.tight_layout() +plt.show() + + +###################################################################### +# What to take away +# ~~~~~~~~~~~~~~~~~ +# +# This demo is still software-level, but now the logical noise strength is tied to a physical noise +# scale. We don’t simulate the oscillator itself, yet we can see how stronger displacement noise leads +# to lower coherence, and how correction suppresses that effect. +# + +###################################################################### +# Series continuation (S03) +# ------------------------- + +###################################################################### +# Logical noise model exploration +# ------------------------------- +# +# In S01 and S02 we treated logical noise as one clean knob. That is a good starting point, but real +# logical noise is not always symmetric. This demo asks a more specific question: what kind of logical +# noise is acting on the logical qubit? +# +# We keep the circuit fixed and only swap the noise channel. The circuit is always: prepare \|+⟩, +# apply a noise channel, then measure ⟨X⟩. We sweep the same noise strength p for every channel so the +# curves are comparable. +# +# Why this setup? Because it isolates the noise model as the only difference. Any change you see in +# the plot is caused by the channel itself, not by a different circuit or a different measurement. +# +# If you want to explore, edit the ``channels`` list or the ``ps`` range in the code cell and rerun. +# That is the simplest way to make the comparison more or less aggressive. +# + +import os + +# Ensure a writable Matplotlib cache and a safe backend for notebooks +os.environ.setdefault("MPLCONFIGDIR", "/tmp/matplotlib") +os.environ.setdefault("IPYTHONDIR", "/tmp/ipython") + +import matplotlib +try: + from IPython import get_ipython + + if get_ipython() is not None: + matplotlib.use("module://matplotlib_inline.backend_inline") +except Exception: + pass + +import numpy as np +import matplotlib.pyplot as plt +import pennylane as qml + +# Use a mixed-state simulator to model logical noise +dev = qml.device("default.mixed", wires=1) + + +def apply_plot_style(): + plt.rcParams.update( + { + "figure.dpi": 120, + "savefig.dpi": 300, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "axes.axisbelow": True, + "grid.alpha": 0.25, + "grid.linestyle": "--", + "axes.labelsize": 12, + "axes.titlesize": 13, + "axes.titlepad": 10, + "legend.frameon": False, + "legend.fontsize": 10, + "lines.linewidth": 2.2, + "lines.markersize": 4.5, + } + ) + + +apply_plot_style() + + +@qml.qnode(dev) +def coherence_with_channel(channel, p): + qml.Hadamard(wires=0) + + if channel == "depolarizing": + qml.DepolarizingChannel(p, wires=0) + elif channel == "bit_flip": + qml.BitFlip(p, wires=0) + elif channel == "phase_flip": + qml.PhaseFlip(p, wires=0) + elif channel == "amplitude_damping": + qml.AmplitudeDamping(p, wires=0) + elif channel == "phase_damping": + qml.PhaseDamping(p, wires=0) + else: + raise ValueError(f"Unknown channel: {channel}") + + return qml.expval(qml.PauliX(0)) + + +channels = [ + ("Depolarizing", "depolarizing"), + ("Bit flip", "bit_flip"), + ("Phase flip", "phase_flip"), + ("Amplitude damping", "amplitude_damping"), + ("Phase damping", "phase_damping"), +] + +ps = np.linspace(0.0, 0.30, 61) + +fig, ax = plt.subplots(figsize=(6.8, 4.2)) +for label, name in channels: + coh = np.array([coherence_with_channel(name, p) for p in ps]) + ax.plot(ps, coh, label=label) + +ax.set_xlabel("Noise strength p") +ax.set_ylabel(r"Logical coherence $\langle X \rangle$") +ax.set_title("S03: Comparing logical noise channels") +ax.set_xlim(ps.min(), ps.max()) +ax.set_ylim(0.5, 1.02) +ax.legend(ncol=2) +fig.tight_layout() +plt.show() + + +###################################################################### +# What we’re measuring and why +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# We prepare \|+⟩ because it is maximally coherent in the X basis. Measuring ⟨X⟩ directly reports how +# much of that phase coherence is left after noise. +# +# Phase-type errors (phase flip, phase damping) attack that coherence directly, so their curves drop +# quickly. Bit-flip noise flips \|0⟩ and \|1⟩ but does not immediately erase X-basis coherence, so it +# can look gentler in this specific measurement. Amplitude damping has its own signature because it +# pushes population toward \|0⟩ while also reducing coherence. +# +# The key point is that the measurement choice matters. The same physical device can look “more” or +# “less” noisy depending on which logical observable you use to probe it. +# + +###################################################################### +# What to take away +# ~~~~~~~~~~~~~~~~~ +# +# The curves do not match, and that is the lesson. Different logical error models degrade coherence in +# different ways, even when they are given the same noise strength parameter. +# +# If you are trying to model a hardware stack at the logical layer, this plot is a reminder to be +# precise about the channel you choose. “Logical noise” is not one thing. It is a family of models, +# and each one predicts a different coherence decay. +# +# A practical way to use this demo is to treat the curve shapes as fingerprints. If your measured +# coherence drops quickly in the X basis, phase-type noise is a likely culprit. If it decays more +# slowly, bit-flip-like noise may dominate. The goal is not to fit perfectly here, but to build +# intuition about how channel choice changes the story. +# + +###################################################################### +# Series continuation (S04) +# ------------------------- + +###################################################################### +# Multi-qubit logical systems +# --------------------------- +# +# So far we have looked at single logical qubits. Now we move to entanglement, because that is where +# logical noise really shows its teeth. +# +# We study two simple states: a Bell state (2 qubits) and a GHZ state (3 qubits). In both cases we +# apply the same logical noise to every qubit and then measure correlation observables. +# +# These observables are near 1 in the ideal state, so their decay is a direct, software-level signal +# that entanglement is being washed out. +# +# If you want to explore further, change the ``ps`` range or swap the noise channel in the code cells +# and rerun. You will see how basis choice and noise type change the decay. +# + +import os + +# Ensure a writable Matplotlib cache and a safe backend for notebooks +os.environ.setdefault("MPLCONFIGDIR", "/tmp/matplotlib") +os.environ.setdefault("IPYTHONDIR", "/tmp/ipython") + +import matplotlib +try: + from IPython import get_ipython + + if get_ipython() is not None: + matplotlib.use("module://matplotlib_inline.backend_inline") +except Exception: + pass + +import numpy as np +import matplotlib.pyplot as plt +import pennylane as qml + + +def apply_plot_style(): + plt.rcParams.update( + { + "figure.dpi": 120, + "savefig.dpi": 300, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "axes.axisbelow": True, + "grid.alpha": 0.25, + "grid.linestyle": "--", + "axes.labelsize": 12, + "axes.titlesize": 13, + "axes.titlepad": 10, + "legend.frameon": False, + "legend.fontsize": 10, + "lines.linewidth": 2.2, + "lines.markersize": 4.5, + } + ) + + +apply_plot_style() + + +###################################################################### +# Bell state correlations +# ~~~~~~~~~~~~~~~~~~~~~~~ +# +# For a Bell state, the correlations ⟨X⊗X⟩ and ⟨Z⊗Z⟩ are both strong. That is why we measure them: +# they are simple, high-contrast indicators that the two qubits are still entangled. +# +# As noise increases, both correlations decay. The rate of decay is the logical signature of how +# quickly entanglement is lost under the chosen noise channel. +# + +dev2 = qml.device("default.mixed", wires=2) + + +@qml.qnode(dev2) +def bell_correlations(p): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + + qml.DepolarizingChannel(p, wires=0) + qml.DepolarizingChannel(p, wires=1) + + xx = qml.expval(qml.PauliX(0) @ qml.PauliX(1)) + zz = qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + return xx, zz + + +ps = np.linspace(0.0, 0.30, 61) +xx_vals = [] +zz_vals = [] +for p in ps: + xx, zz = bell_correlations(p) + xx_vals.append(xx) + zz_vals.append(zz) + +fig, ax = plt.subplots(figsize=(6.5, 4)) +ax.plot(ps, xx_vals, label=r"$\langle X \otimes X \rangle$") +ax.plot(ps, zz_vals, label=r"$\langle Z \otimes Z \rangle$") +ax.set_xlabel("Noise strength p") +ax.set_ylabel("Correlation") +ax.set_title("S04: Bell-state correlations under logical noise") +ax.set_xlim(ps.min(), ps.max()) +ax.set_ylim(0.5, 1.02) +ax.legend() +fig.tight_layout() +plt.show() + + +###################################################################### +# How to read the Bell plot +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Because we use depolarizing noise here, the decay is fairly symmetric and both curves fall together. +# If you swap the noise channel in the code cell to phase flip or bit flip, you will see the basis +# dependence show up as different decay rates between ⟨X⊗X⟩ and ⟨Z⊗Z⟩. +# +# That is a useful reminder that “entanglement loss” can look different depending on how you probe it. +# + +###################################################################### +# GHZ state coherence +# ~~~~~~~~~~~~~~~~~~~ +# +# A GHZ state spreads its coherence across all three qubits, so it is even more fragile. We track +# ⟨X⊗X⊗X⟩ as a proxy for global coherence and ⟨Z0 Z1⟩ as a more local check. +# +# As noise increases, the global term typically drops faster because it depends on every qubit staying +# coherent at once. This is why multi-qubit logical noise models matter so much for algorithm-level +# behavior. +# + +dev3 = qml.device("default.mixed", wires=3) + + +@qml.qnode(dev3) +def ghz_correlations(p): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.CNOT(wires=[0, 2]) + + for w in [0, 1, 2]: + qml.DepolarizingChannel(p, wires=w) + + xxx = qml.expval(qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliX(2)) + zz = qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + return xxx, zz + + +ps = np.linspace(0.0, 0.30, 61) +xxx_vals = [] +zz_vals = [] +for p in ps: + xxx, zz = ghz_correlations(p) + xxx_vals.append(xxx) + zz_vals.append(zz) + +fig, ax = plt.subplots(figsize=(6.5, 4)) +ax.plot(ps, xxx_vals, label=r"$\langle X \otimes X \otimes X \rangle$") +ax.plot(ps, zz_vals, label=r"$\langle Z_0 Z_1 \rangle$") +ax.set_xlabel("Noise strength p") +ax.set_ylabel("Correlation") +ax.set_title("S04: GHZ coherence under logical noise") +ax.set_xlim(ps.min(), ps.max()) +ax.set_ylim(0.5, 1.02) +ax.legend() +fig.tight_layout() +plt.show() + + +###################################################################### +# What to take away +# ~~~~~~~~~~~~~~~~~ +# +# Single-qubit noise already reduces coherence, but entangled states amplify that effect. A small +# amount of logical noise on each wire can erase the correlations that make Bell and GHZ states +# useful. +# +# This is the software-level reason error correction is essential for multi-qubit algorithms. It is +# not just about keeping individual qubits clean. It is about preserving the correlations that +# algorithms depend on. +# + +###################################################################### +# Series continuation (S05) +# ------------------------- + +###################################################################### +# Interactive logical noise playground +# ------------------------------------ +# +# This final demo is a sandbox for everything we built in S01 to S04. You choose a noise model, a +# noise strength p, a correction factor α, and the number of qubits. The circuit and measurement +# update when you rerun the cell; with widgets they update live. +# +# Under the hood the circuit is simple: for 1 qubit we prepare \|+⟩, for 2 qubits we prepare a Bell +# state, and for 3 qubits we prepare a GHZ state. We then apply the chosen logical noise channel to +# every qubit and measure an X-type observable (⟨X⟩, ⟨X⊗X⟩, or ⟨X⊗X⊗X⟩). +# +# Correction is modeled as noise suppression: raw noise uses p, corrected noise uses α·p. This is not +# a physical GKP simulation, but it is a clean logical proxy for “correction makes the effective noise +# smaller.” +# +# In this notebook you can type values directly by editing the ``simulate(...)`` call. If +# ``ipywidgets`` is available, you may also see sliders. The desktop app provides the same controls +# with live plots and typed inputs (no sliders). +# + +import os + +# Ensure a writable Matplotlib cache and a safe backend for notebooks +os.environ.setdefault("MPLCONFIGDIR", "/tmp/matplotlib") +os.environ.setdefault("IPYTHONDIR", "/tmp/ipython") + +import matplotlib +try: + from IPython import get_ipython + + if get_ipython() is not None: + matplotlib.use("module://matplotlib_inline.backend_inline") +except Exception: + pass + +import numpy as np +import matplotlib.pyplot as plt +import pennylane as qml + + +def apply_plot_style(): + plt.rcParams.update( + { + "figure.dpi": 120, + "savefig.dpi": 300, + "axes.spines.top": False, + "axes.spines.right": False, + "axes.grid": True, + "axes.axisbelow": True, + "grid.alpha": 0.25, + "grid.linestyle": "--", + "axes.labelsize": 12, + "axes.titlesize": 13, + "axes.titlepad": 10, + "legend.frameon": False, + "legend.fontsize": 10, + "lines.linewidth": 2.2, + "lines.markersize": 4.5, + } + ) + + +apply_plot_style() + + +def apply_noise(noise_model, p, wires): + for w in wires: + if noise_model == "depolarizing": + qml.DepolarizingChannel(p, wires=w) + elif noise_model == "bit_flip": + qml.BitFlip(p, wires=w) + elif noise_model == "phase_flip": + qml.PhaseFlip(p, wires=w) + elif noise_model == "amplitude_damping": + qml.AmplitudeDamping(p, wires=w) + elif noise_model == "phase_damping": + qml.PhaseDamping(p, wires=w) + else: + raise ValueError(f"Unknown noise model: {noise_model}") + + +def make_circuit(n_qubits, noise_model): + dev = qml.device("default.mixed", wires=n_qubits) + + @qml.qnode(dev) + def circuit(p): + if n_qubits == 1: + qml.Hadamard(wires=0) + elif n_qubits == 2: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + else: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.CNOT(wires=[0, 2]) + + apply_noise(noise_model, p, range(n_qubits)) + + if n_qubits == 1: + return qml.expval(qml.PauliX(0)) + elif n_qubits == 2: + return qml.expval(qml.PauliX(0) @ qml.PauliX(1)) + else: + return qml.expval(qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliX(2)) + + return circuit + + +def simulate(noise_model="depolarizing", p=0.2, alpha=0.25, n_qubits=2): + circuit = make_circuit(n_qubits, noise_model) + raw = circuit(p) + corrected = circuit(alpha * p) + + fig, ax = plt.subplots(figsize=(5.5, 3.6)) + ax.bar(["Raw", "Corrected"], [raw, corrected], color=["#1b9e77", "#d95f02"]) + ax.set_ylim(0.0, 1.02) + ax.set_ylabel("Coherence") + ax.set_title(f"Noise model: {noise_model}, qubits: {n_qubits}") + for i, val in enumerate([raw, corrected]): + ax.text(i, val + 0.02, f"{val:.2f}", ha="center") + fig.tight_layout() + plt.show() + + +# Try to create interactive controls; fall back to a static example if unavailable +try: + import ipywidgets as widgets + from ipywidgets import interact + + interact( + simulate, + noise_model=widgets.Dropdown( + options=[ + "depolarizing", + "bit_flip", + "phase_flip", + "amplitude_damping", + "phase_damping", + ], + value="depolarizing", + description="Noise", + ), + p=widgets.FloatSlider(min=0.0, max=0.5, step=0.05, value=0.2, description="p"), + alpha=widgets.FloatSlider(min=0.0, max=1.0, step=0.05, value=0.25, description="alpha"), + n_qubits=widgets.Dropdown(options=[1, 2, 3], value=2, description="Qubits"), + ) +except Exception: + simulate() + + +###################################################################### +# What to try +# ~~~~~~~~~~~ +# +# Start with a baseline so you can calibrate your intuition. Set ``noise_model="depolarizing"``, +# ``p=0.2``, ``alpha=0.25``, ``n_qubits=1``. You should see the corrected bar higher than the raw bar. +# +# Then try these small experiments, one at a time: +# +# 1. Hold p fixed and reduce alpha. The corrected bar should rise because you are suppressing noise +# more aggressively. +# 2. Hold alpha fixed and increase p. Both bars should fall, but the corrected bar should fall more +# slowly. +# 3. Switch to ``phase_flip`` and compare ``n_qubits=1`` vs ``n_qubits=3``. The three-qubit coherence +# should collapse faster because it depends on all qubits staying coherent. +# 4. Try ``amplitude_damping`` and notice how it tends to pull states toward \|0⟩, which changes the +# coherence in a different way than pure phase noise. +# +# If you want a quick sanity check, set ``alpha=1.0``. The corrected bar should match the raw bar +# exactly. +# + +###################################################################### +# Download the desktop playground +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Use the latest release builds: +# +# - macOS: +# https://github.com/denniswayo/bosonicflow-gkp/releases/latest/download/bosonicflow-gkp-macos.zip +# - Windows: +# https://github.com/denniswayo/bosonicflow-gkp/releases/latest/download/bosonicflow-gkp-windows.zip +# - Linux: +# https://github.com/denniswayo/bosonicflow-gkp/releases/latest/download/bosonicflow-gkp-linux.zip +# +# If you are running locally from source, see the build scripts in ``pyqt_gui/``. +# diff --git a/demonstrations_v2/tutorial_gkp_qec_photonic_s01/metadata.json b/demonstrations_v2/tutorial_gkp_qec_photonic_s01/metadata.json new file mode 100644 index 0000000000..b58b47978c --- /dev/null +++ b/demonstrations_v2/tutorial_gkp_qec_photonic_s01/metadata.json @@ -0,0 +1,103 @@ +{ + "title": "GKP-based quantum error correction in photonic systems", + "authors": [ + { + "username": "DennisWayo" + } + ], + "executable_stable": true, + "executable_latest": true, + "dateOfPublication": "2026-03-12T00:00:00+00:00", + "dateOfLastModification": "2026-03-12T00:00:00+00:00", + "categories": [ + "Quantum Hardware", + "Quantum Computing" + ], + "tags": [], + "previewImages": [ + { + "type": "thumbnail", + "uri": "/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_gkp_qec_photonic_s01.png" + }, + { + "type": "large_thumbnail", + "uri": "/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_gkp_qec_photonic_s01.png" + } + ], + "seoDescription": "Understand how GKP error correction appears at the software layer in PennyLane through an effective logical-noise model.", + "doi": "", + "references": [ + { + "id": "gkp2000", + "type": "preprint", + "title": "Encoding a qubit in an oscillator", + "authors": "Daniel Gottesman, Alexei Kitaev, and John Preskill", + "year": "2000", + "url": "https://arxiv.org/abs/quant-ph/0008040" + }, + { + "id": "menicucci2014", + "type": "article", + "title": "Fault-tolerant measurement-based quantum computing with continuous-variable cluster states", + "authors": "Nicolas C. Menicucci", + "year": "2014", + "journal": "Physical Review Letters", + "volume": "112", + "number": "12", + "doi": "10.1103/PhysRevLett.112.120504", + "url": "https://doi.org/10.1103/PhysRevLett.112.120504" + }, + { + "id": "mirrahimi2014", + "type": "article", + "title": "Dynamically protected cat-qubits: a new paradigm for universal quantum computation", + "authors": "Mazyar Mirrahimi, Zaki Leghtas, Victor V. Albert, Steven Touzard, Robert J. Schoelkopf, Liang Jiang, and Michel H. Devoret", + "year": "2014", + "journal": "New Journal of Physics", + "volume": "16", + "number": "4", + "pages": "045014", + "doi": "10.1088/1367-2630/16/4/045014", + "url": "https://doi.org/10.1088/1367-2630/16/4/045014" + }, + { + "id": "banic2025", + "type": "article", + "title": "Exact simulation of realistic Gottesman-Kitaev-Preskill cluster states", + "authors": "Marko Bani\u0107, Tori Hodgkinson, Mark M. Wilde, and Nicolas C. Menicucci", + "year": "2025", + "journal": "Physical Review A", + "volume": "112", + "pages": "052425", + "doi": "10.1103/PhysRevA.112.052425", + "url": "https://doi.org/10.1103/PhysRevA.112.052425" + }, + { + "id": "bergholm2018", + "type": "preprint", + "title": "PennyLane: Automatic differentiation of hybrid quantum-classical computations", + "authors": "Ville Bergholm, Josh Izaac, Maria Schuld, Christian Gogolin, Carsten Blank, Keri McKiernan, Nathan Killoran, and Juan Miguel Arrazola", + "year": "2018", + "url": "https://arxiv.org/abs/1811.04968" + } + ], + "basedOnPapers": [], + "referencedByPapers": [], + "relatedContent": [ + { + "type": "demonstration", + "id": "tutorial_error_mitigation", + "weight": 1.0 + }, + { + "type": "demonstration", + "id": "tutorial_error_prop", + "weight": 1.0 + }, + { + "type": "demonstration", + "id": "tutorial_how_to_use_noise_models", + "weight": 1.0 + } + ] +} From 146f18e81f35155fbd60a907895deed231a31d5e Mon Sep 17 00:00:00 2001 From: Dennis Wayo <117969019+DennisWayo@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:55:47 +0500 Subject: [PATCH 2/2] Add placeholder thumbnails for gkp_qec_photonic_s01 --- .../thumbnail_large_gkp_qec_photonic_s01.png | Bin 0 -> 41074 bytes .../thumbnail_gkp_qec_photonic_s01.png | Bin 0 -> 7108 bytes .../tutorial_gkp_qec_photonic_s01/metadata.json | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 _static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_gkp_qec_photonic_s01.png create mode 100644 _static/demo_thumbnails/regular_demo_thumbnails/thumbnail_gkp_qec_photonic_s01.png diff --git a/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_gkp_qec_photonic_s01.png b/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_gkp_qec_photonic_s01.png new file mode 100644 index 0000000000000000000000000000000000000000..6c02628b1669eb9039f57971497bd8a55581c26b GIT binary patch literal 41074 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
#DXUMMM}rfPy5E!~ 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 literal 0 HcmV?d00001 diff --git a/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_gkp_qec_photonic_s01.png b/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_gkp_qec_photonic_s01.png new file mode 100644 index 0000000000000000000000000000000000000000..590570e20a6c8ba48d3007349ef97b6f1fdb1dd2 GIT binary patch literal 7108 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