autoresearch-quantum/notebooks/plan_a/01_encoded_magic_state.ipynb

1588 lines
546 KiB
Text
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Notebook 1: What Is an Encoded Magic State?\n",
"\n",
"**Welcome.** This notebook will take you from a single qubit to a fault-tolerant building block, step by step. Every concept is introduced with motivation first, then code, then a quiz to check your understanding.\n",
"\n",
"### The big picture\n",
"\n",
"In fault-tolerant quantum computing, most logical gates can be implemented transversally using **Clifford operations** (H, S, CNOT). But Cliffords alone are not enough for universal computation. The **Gottesman-Knill theorem** proves that any circuit built only from Clifford gates can be efficiently simulated on a classical computer — no quantum advantage.\n",
"\n",
"To break out of this classical-simulability trap, you need a **non-Clifford resource**. The simplest one is the **T-gate** ($\\pi/8$ rotation). But implementing T fault-tolerantly is hard — you cannot do it transversally in most codes. The workaround: prepare a special quantum state called the **magic state**, then consume it to perform the T-gate via gate teleportation.\n",
"\n",
"$$|T\\rangle = \\frac{|0\\rangle + e^{i\\pi/4}|1\\rangle}{\\sqrt{2}}$$\n",
"\n",
"This notebook teaches you to:\n",
"1. Build a magic state and see it on the Bloch sphere\n",
"2. Understand *why* there are multiple preparation methods and when each matters\n",
"3. Encode it into the [[4,2,2]] error-detecting code\n",
"4. Verify the encoding using stabilizer algebra\n",
"5. See error detection in action — break the state and watch the code catch it\n",
"6. Run a full syndrome-measurement simulation with postselection"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Imports OK.\n"
]
}
],
"source": [
"%matplotlib inline\n",
"\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from math import pi, sqrt\n",
"\n",
"from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
"from qiskit.quantum_info import Statevector, SparsePauliOp, state_fidelity, DensityMatrix\n",
"from qiskit.visualization import plot_bloch_multivector, plot_histogram\n",
"from qiskit_aer import AerSimulator\n",
"\n",
"from autoresearch_quantum.codes.four_two_two import (\n",
" build_preparation_circuit,\n",
" build_encoder,\n",
" apply_magic_seed,\n",
" encoded_magic_statevector,\n",
" STABILIZERS,\n",
" MEASUREMENT_OPERATORS,\n",
" DATA_QUBITS,\n",
")\n",
"from autoresearch_quantum.experiments.encoded_magic_state import build_circuit_bundle\n",
"from autoresearch_quantum.models import ExperimentSpec\n",
"\n",
"print(\"Imports OK.\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Learning tracker active. Quizzes will appear as interactive widgets.\n"
]
}
],
"source": [
"from autoresearch_quantum.teaching import LearningTracker\n",
"from autoresearch_quantum.teaching.assess import quiz, predict_choice, reflect, order, checkpoint_summary\n",
"\n",
"tracker = LearningTracker(\"plan_a_01\")\n",
"print(\"Learning tracker active. Quizzes will appear as interactive widgets.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 1. The Single-Qubit Magic State\n",
"\n",
"### Why this state?\n",
"\n",
"Imagine you have a quantum computer that can only do Clifford gates. You can create entanglement, teleport states, do error correction — but you **cannot** solve any problem faster than a classical computer. You are stuck.\n",
"\n",
"The T-state is the key that unlocks universality. By preparing $|T\\rangle$ with high fidelity and \"injecting\" it into your Clifford circuit, you gain the ability to perform the T-gate:\n",
"\n",
"$$T = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\pi/4} \\end{pmatrix}$$\n",
"\n",
"The T-state itself is prepared by applying Hadamard followed by a $P(\\pi/4)$ phase gate to $|0\\rangle$:\n",
"\n",
"$$|T\\rangle = P(\\pi/4) \\cdot H \\, |0\\rangle = \\frac{|0\\rangle + e^{i\\pi/4}|1\\rangle}{\\sqrt{2}}$$\n",
"\n",
"Let's build it and look at its amplitudes."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"T-state amplitudes: [0.70710678+0.j 0.5 +0.5j]\n",
" |0> amplitude: 0.7071+0.0000j\n",
" |1> amplitude: 0.5000+0.5000j\n",
" |1> phase: 0.7854 rad = 45.0 deg\n",
" Expected phase: pi/4 = 0.7854 rad = 45.0 deg\n"
]
}
],
"source": [
"# Build a single-qubit T-state using H then P(pi/4)\n",
"qc_single = QuantumCircuit(1, name=\"T-state\")\n",
"qc_single.h(0)\n",
"qc_single.p(pi / 4, 0)\n",
"\n",
"t_state = Statevector.from_instruction(qc_single)\n",
"print(\"T-state amplitudes:\", t_state.data)\n",
"print(f\" |0> amplitude: {t_state.data[0]:.4f}\")\n",
"print(f\" |1> amplitude: {t_state.data[1]:.4f}\")\n",
"print(f\" |1> phase: {np.angle(t_state.data[1]):.4f} rad = {np.angle(t_state.data[1]) * 180 / pi:.1f} deg\")\n",
"print(f\" Expected phase: pi/4 = {pi/4:.4f} rad = 45.0 deg\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "616e4cb7639a40eebf12fcef7f3c9de3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"quiz(tracker, \"q1_tstate_phase\",\n",
" question=\"What is the phase angle of the |1\\u27E9 coefficient in the T-state?\",\n",
" options=[\n",
" \"\\u03C0/2 (90\\u00b0)\",\n",
" \"\\u03C0/4 (45\\u00b0)\",\n",
" \"\\u03C0/8 (22.5\\u00b0)\",\n",
" \"\\u03C0 (180\\u00b0)\",\n",
" ],\n",
" correct=1,\n",
" section=\"1. The T-state\",\n",
" bloom=\"remember\",\n",
" explanation=(\n",
" \"The T-state is \\\\((|0\\\\rangle + e^{i\\\\pi/4}|1\\\\rangle)/\\\\sqrt{2}\\\\). \"\n",
" \"The phase is \\\\(\\\\pi/4 = 45\\u00b0\\\\). \"\n",
" \"Confusingly, the gate is called T (for \\\\(\\\\pi/8\\\\)) because the Bloch sphere rotation \"\n",
" \"angle is half the gate phase.\"\n",
" ))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Bloch sphere picture\n",
"\n",
"Every single-qubit pure state can be visualized as a point on the Bloch sphere. The T-state sits at:\n",
"- **Polar angle** $\\theta = \\pi/2$ (on the equator — equal probability of $|0\\rangle$ and $|1\\rangle$)\n",
"- **Azimuthal angle** $\\phi = \\pi/4$ (45° between the X and Y axes)\n",
"\n",
"This means $\\langle X \\rangle = \\langle Y \\rangle = 1/\\sqrt{2} \\approx 0.707$ and $\\langle Z \\rangle = 0$.\n",
"\n",
"Stabilizer states ($|0\\rangle$, $|+\\rangle$, $|i\\rangle$, etc.) always sit at the poles or on the axes. The T-state is **between** axes — that's what makes it non-stabilizer and therefore useful."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 480x581 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Expectation values:\n",
" <X> = 0.7071\n",
" <Y> = 0.7071\n",
" <Z> = 0.0000\n"
]
}
],
"source": [
"# Visualize on the Bloch sphere\n",
"fig = plot_bloch_multivector(t_state, title=\"Single-Qubit T-State\")\n",
"plt.show()\n",
"\n",
"# Verify the expectation values numerically\n",
"print(\"\\nExpectation values:\")\n",
"for pauli in [\"X\", \"Y\", \"Z\"]:\n",
" op = SparsePauliOp.from_list([(pauli, 1.0)])\n",
" val = t_state.expectation_value(op).real\n",
" print(f\" <{pauli}> = {val:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ca91609b2e464d7a8efd46208ce70058",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#e65100; margin-bottom:8px;\">&#1…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ca91609b2e464d7a8efd46208ce70058",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#e65100; margin-bottom:8px;\">&#1…"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"predict_choice(tracker, \"q2_bloch_position\",\n",
" question=\"The T-state Bloch vector: where does it point?\",\n",
" options=[\n",
" \"North pole (along +Z)\",\n",
" \"Along the +X axis\",\n",
" \"On the equator, 45\\u00b0 between X and Y\",\n",
" \"At the south pole (along \\u2212Z)\",\n",
" ],\n",
" correct=2,\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"The T-state has equal \\u27E8X\\u27E9 and \\u27E8Y\\u27E9 (both 1/\\u221A2 \\u2248 0.707) \"\n",
" \"and \\u27E8Z\\u27E9 = 0, placing it on the equator at azimuthal angle \\u03C0/4.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "868d2b996fbb475ca34b1eec2a4ae3ae",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<div style=\"border:2px solid #4caf50; padding:12px 16px; margin:16px 0; border-radius:8px; background:#fafafa;\"><strong>Checkpoint — 1. The T-state:</strong> 3/3 correct (100.0%)<div style=\"background:#ddd; border-radius:6px; height:18px; margin:4px 0;\"><div style=\"background:#4caf50; width:100.0%; height:100%; border-radius:6px;\"></div></div><br>Good grasp of this section. Moving on!</div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"quiz(tracker, \"q3_why_tstate\",\n",
" question=\"Why can't we just use Clifford gates for everything?\",\n",
" options=[\n",
" \"Clifford gates are too slow on real hardware\",\n",
" \"Clifford gates cannot create entanglement\",\n",
" \"Clifford-only circuits can be efficiently simulated classically (Gottesman-Knill theorem)\",\n",
" \"Clifford gates introduce too many errors\",\n",
" ],\n",
" correct=2,\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"The Gottesman-Knill theorem proves that stabilizer circuits (Cliffords + Pauli measurements + stabilizer inputs) \"\n",
" \"can be simulated in polynomial time on a classical computer. \"\n",
" \"Adding a non-Clifford resource like the T-state breaks this and enables quantum advantage.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"1. The T-state\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 2. Three Seed Styles — Same State, Different Gates\n",
"\n",
"### Why multiple preparations?\n",
"\n",
"There is more than one way to prepare the T-state. The codebase implements three:\n",
"\n",
"| Style | Gates | Why it exists |\n",
"|-------|-------|---------------|\n",
"| `h_p` | $H \\to P(\\pi/4)$ | The textbook definition. Clearest to read. |\n",
"| `ry_rz` | $R_y(\\pi/2) \\to R_z(\\pi/4)$ | Uses rotation gates that some hardware supports natively. |\n",
"| `u_magic` | $U(\\pi/2, \\pi/4, 0)$ | Single-gate form. Fewest gates before transpilation. |\n",
"\n",
"**Why does this matter?** Different quantum processors have different **native gate sets**. IBM's processors natively support $\\{\\sqrt{X}, R_z, CX\\}$. When you write `H`, the transpiler decomposes it into native gates. A preparation that uses fewer non-native gates may transpile to a shorter, less noisy circuit.\n",
"\n",
"Let's verify all three produce the same quantum state."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"h_p : amplitudes = [0.70710678+0.j 0.5 +0.5j]\n",
"ry_rz : amplitudes = [0.65328148-0.27059805j 0.65328148+0.27059805j]\n",
"u_magic : amplitudes = [0.70710678+0.j 0.5 +0.5j]\n",
"\n",
"Fidelity(h_p, ry_rz) = 1.000000\n",
"Fidelity(h_p, u_magic) = 1.000000\n",
"Fidelity(ry_rz, u_magic) = 1.000000\n"
]
}
],
"source": [
"seed_styles = [\"h_p\", \"ry_rz\", \"u_magic\"]\n",
"states = {}\n",
"\n",
"for style in seed_styles:\n",
" qc = QuantumCircuit(1, name=style)\n",
" apply_magic_seed(qc, 0, style)\n",
" sv = Statevector.from_instruction(qc)\n",
" states[style] = sv\n",
" print(f\"{style:10s}: amplitudes = {sv.data}\")\n",
"\n",
"# Compute pairwise fidelities\n",
"print()\n",
"for s1 in seed_styles:\n",
" for s2 in seed_styles:\n",
" if s1 < s2:\n",
" fid = state_fidelity(states[s1], states[s2])\n",
" print(f\"Fidelity({s1}, {s2}) = {fid:.6f}\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 480x581 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 480x581 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 480x581 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Bloch sphere for each seed style\n",
"for style in seed_styles:\n",
" fig = plot_bloch_multivector(states[style], title=f\"Seed: {style}\")\n",
" plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All three fidelities are 1.0 (or extremely close) and the Bloch spheres all point to the same spot. The amplitudes may differ by a **global phase** factor $e^{i\\theta}$, which has no physical significance — all measurements yield identical results.\n",
"\n",
"> **Take-away:** The choice of seed style is not about physics (they all give the same state). It is about **engineering**: which one transpiles to the fewest noisy gates on your target hardware?"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "41366b76c8b84a8592f2e3f117f3ad0d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<div style=\"border:2px solid #4caf50; padding:12px 16px; margin:16px 0; border-radius:8px; background:#fafafa;\"><strong>Checkpoint — 2. Seed styles:</strong> 1/1 correct (100.0%)<div style=\"background:#ddd; border-radius:6px; height:18px; margin:4px 0;\"><div style=\"background:#4caf50; width:100.0%; height:100%; border-radius:6px;\"></div></div><br>Good grasp of this section. Moving on!</div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"quiz(tracker, \"q4_global_phase\",\n",
" question=\"Two states have different complex amplitudes but fidelity = 1.0. Why?\",\n",
" options=[\n",
" \"Floating-point rounding errors\",\n",
" \"A global phase factor has no physical consequence \\u2014 only relative phases matter\",\n",
" \"The Bloch sphere representation is approximate\",\n",
" ],\n",
" correct=1,\n",
" section=\"2. Seed styles\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"Multiplying all amplitudes by the same phase factor does not change any measurement outcome. \"\n",
" \"Two states related by a global phase are physically identical.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"2. Seed styles\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 3. Why Encode? The Fragility Problem\n",
"\n",
"### The dilemma\n",
"\n",
"A bare single-qubit T-state is **fragile**. Any noise — bit-flips, phase drifts, measurement crosstalk — corrupts it. And we cannot protect it the way we protect classical data:\n",
"\n",
"- **No cloning**: Quantum mechanics forbids copying an unknown quantum state.\n",
"- **No majority vote**: We cannot make 3 copies and take the majority.\n",
"- **Measurement destroys**: Reading the state to check it collapses the superposition.\n",
"\n",
"The solution is **quantum error correction**: encode the logical qubit into multiple physical qubits in a way that errors can be detected (or corrected) without revealing the logical information.\n",
"\n",
"### The [[4,2,2]] code\n",
"\n",
"The **[[4,2,2]]** code is one of the smallest useful quantum codes:\n",
"- **4** physical qubits\n",
"- **2** logical qubits (one for the T-state, one \"spectator\" in $|0\\rangle_L$)\n",
"- **Distance 2**: can **detect** any single-qubit error, but cannot correct it\n",
"\n",
"What \"distance 2\" means concretely: if **one** qubit suffers an error (X, Y, or Z), the code's stabilizer measurements will flag it. The strategy is **postselection**: discard any shot where an error was detected, and keep only the clean shots.\n",
"\n",
"This is a trade-off: you lose some shots (reduced acceptance rate) but the surviving shots have higher quality. Whether this trade-off is worthwhile depends on the noise level — we'll explore this quantitatively in Notebook 2."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "92ebaa2a6b0e4b7aaa3152bf917b851e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "92ebaa2a6b0e4b7aaa3152bf917b851e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quiz(tracker, \"q5_distance_2\",\n",
" question='The [[4,2,2]] code has distance 2. What does this mean in practice?',\n",
" options=[\n",
" \"It can correct any 1-qubit error\",\n",
" \"It can detect any 1-qubit error but not correct it\",\n",
" \"It can detect any 2-qubit error\",\n",
" \"It uses 2 ancilla qubits\",\n",
" ],\n",
" correct=1,\n",
" section=\"3. Why encode\",\n",
" bloom=\"remember\",\n",
" explanation=(\n",
" \"Distance d means the code can detect up to d\\u22121 errors. \"\n",
" \"Distance 2 \\u2192 detects 1-qubit errors. \"\n",
" \"Correction requires distance \\u2265 3. \"\n",
" \"The [[4,2,2]] code uses detection + postselection instead of correction.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "44f725b76d284ec89ec859138d9ff7f9",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<div style=\"border:2px solid #4caf50; padding:12px 16px; margin:16px 0; border-radius:8px; background:#fafafa;\"><strong>Checkpoint — 3. Why encode:</strong> 1/1 correct (100.0%)<div style=\"background:#ddd; border-radius:6px; height:18px; margin:4px 0;\"><div style=\"background:#4caf50; width:100.0%; height:100%; border-radius:6px;\"></div></div><br>Good grasp of this section. Moving on!</div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"quiz(tracker, \"q6_no_cloning\",\n",
" question=\"Why can't we protect a qubit by simply making backup copies?\",\n",
" options=[\n",
" \"Quantum hardware doesn't support the COPY gate yet\",\n",
" \"The no-cloning theorem forbids copying an unknown quantum state\",\n",
" \"Copies would entangle with the original and cause errors\",\n",
" ],\n",
" correct=1,\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"The no-cloning theorem (Wootters & Zurek, 1982) is a fundamental result: \"\n",
" \"there is no quantum operation that can copy an arbitrary unknown state. \"\n",
" \"This is why quantum error correction works so differently from classical error correction \\u2014 \"\n",
" \"it encodes information into entanglement patterns rather than redundant copies.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"3. Why encode\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 4. Building the Encoder Step by Step\n",
"\n",
"### What the encoder does\n",
"\n",
"The encoder takes 4 qubits in the state $|T\\rangle|0\\rangle|0\\rangle|0\\rangle$ and entangles them into a 4-qubit codeword. After encoding, **no single qubit carries the T-state information** — it is distributed across all four qubits. This redundancy is what enables error detection.\n",
"\n",
"The `cx_chain` encoder uses 5 CNOT gates and 1 Hadamard:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cx_chain encoder circuit:\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 538.33x367.889 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Build and display the cx_chain encoder\n",
"encoder_cx = build_encoder(\"cx_chain\")\n",
"print(\"cx_chain encoder circuit:\")\n",
"fig = encoder_cx.draw('mpl', style='iqp')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reading the circuit\n",
"\n",
"| Step | Gate | What it does |\n",
"|------|------|-------------|\n",
"| 1 | CNOT(0, 2) | Spreads qubit 0's state to qubit 2 — begins creating the logical $X_L = X_0 X_2$ structure |\n",
"| 2 | CNOT(1, 0) | Entangles the spectator qubit 1 with qubit 0 |\n",
"| 3 | H(3) | Puts qubit 3 in superposition $|+\\rangle$ |\n",
"| 4-6 | CNOT(3, 0), CNOT(3, 1), CNOT(3, 2) | Qubit 3 fans out to all others, creating the $XXXX$ stabilizer structure |\n",
"\n",
"The CNOTs create **entanglement** between the qubits. After step 6, measuring any single qubit gives a random outcome — but measuring the **parity** of all four (the stabilizer) gives a deterministic result."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c8ffe4bf788f43afb540cab02f2940e7",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c8ffe4bf788f43afb540cab02f2940e7",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quiz(tracker, \"q7_gate_count\",\n",
" question=\"How many 2-qubit (CNOT) gates are in the cx_chain encoder?\",\n",
" options=[\"3\", \"4\", \"5\", \"6\"],\n",
" correct=2,\n",
" section=\"4. Encoder circuit\",\n",
" bloom=\"apply\",\n",
" explanation=(\n",
" \"CX(0,2), CX(1,0), CX(3,0), CX(3,1), CX(3,2) = 5 CNOT gates. \"\n",
" \"Two-qubit gates are the noisiest operations on real hardware, so this count \"\n",
" \"is the primary driver of circuit cost.\"\n",
" ))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 5. Full Preparation Circuit\n",
"\n",
"The complete preparation is: **seed** (T-state on qubit 0) followed by **encoder** (spread across all 4 qubits).\n",
"\n",
"### What to expect\n",
"\n",
"A 4-qubit system has $2^4 = 16$ possible basis states ($|0000\\rangle$ through $|1111\\rangle$). But the encoded T-state only occupies a small subspace — the **codespace** of the [[4,2,2]] code. We expect only a few basis states to have non-zero amplitude."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7f5e9ed02046404bbf511d479e40cc53",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#e65100; margin-bottom:8px;\">&#1…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7f5e9ed02046404bbf511d479e40cc53",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#e65100; margin-bottom:8px;\">&#1…"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"predict_choice(tracker, \"q8_nonzero_amplitudes\",\n",
" question=\"How many of the 16 basis states will have non-zero amplitude in the encoded T-state?\",\n",
" options=[\"2 (just |0000\\u27E9 and |1111\\u27E9)\", \"4\", \"8\", \"All 16\"],\n",
" correct=1,\n",
" section=\"5. Encoded state\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"The [[4,2,2]] codespace has 4 basis codewords (2 logical qubits \\u2192 2\\u00b2 = 4 states). \"\n",
" \"The T-state is a superposition of |0\\u27E9_L and |1\\u27E9_L, each mapping to 2 physical states, \"\n",
" \"giving exactly 4 non-zero amplitudes.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Preparation circuit: 4 qubits, depth 7\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 705.552x367.889 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Full preparation circuit\n",
"prep = build_preparation_circuit(seed_style=\"h_p\", encoder_style=\"cx_chain\")\n",
"print(f\"Preparation circuit: {prep.num_qubits} qubits, depth {prep.depth()}\")\n",
"fig = prep.draw('mpl', style='iqp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Statevector has 16 amplitudes (2^4 = 16)\n",
"\n",
"Non-zero amplitudes:\n",
" |0000> : 0.5000+0.0000j (magnitude: 0.5000)\n",
" |0101> : 0.3536+0.3536j (magnitude: 0.5000)\n",
" |1010> : 0.3536+0.3536j (magnitude: 0.5000)\n",
" |1111> : 0.5000+0.0000j (magnitude: 0.5000)\n"
]
}
],
"source": [
"# Compute the encoded statevector\n",
"encoded_sv = Statevector.from_instruction(prep)\n",
"print(f\"Statevector has {len(encoded_sv.data)} amplitudes (2^{prep.num_qubits} = {2**prep.num_qubits})\")\n",
"print(\"\\nNon-zero amplitudes:\")\n",
"for i, amp in enumerate(encoded_sv.data):\n",
" if abs(amp) > 1e-10:\n",
" binary = format(i, f'0{prep.num_qubits}b')\n",
" print(f\" |{binary}> : {amp:.4f} (magnitude: {abs(amp):.4f})\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Interpreting the output\n",
"\n",
"You should see exactly **4** non-zero amplitudes: $|0000\\rangle$, $|0101\\rangle$, $|1010\\rangle$, $|1111\\rangle$. These are the codewords of the [[4,2,2]] code. Notice:\n",
"- All four have the **same magnitude** (0.5) — equal probability\n",
"- The **phases** encode the T-state information (the $e^{i\\pi/4}$ factor appears on $|0101\\rangle$ and $|1010\\rangle$)\n",
"- No single qubit's measurement alone reveals the T-state — the information lives in the *correlations* between qubits"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"border:2px solid #4caf50; padding:12px 16px; margin:16px 0; border-radius:8px; background:#fafafa;\"><strong>Checkpoint — 5. Encoded state:</strong> 1/1 correct (100.0%)<div style=\"background:#ddd; border-radius:6px; height:18px; margin:4px 0;\"><div style=\"background:#4caf50; width:100.0%; height:100%; border-radius:6px;\"></div></div><br>Good grasp of this section. Moving on!</div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"checkpoint_summary(tracker, \"5. Encoded state\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 6. Stabilizer Verification — The Quantum Checksum\n",
"\n",
"### What are stabilizers?\n",
"\n",
"A **stabilizer** is an operator that leaves the code's valid states unchanged. For the [[4,2,2]] code, the two stabilizers are:\n",
"\n",
"$$XXXX = X \\otimes X \\otimes X \\otimes X \\quad\\text{and}\\quad ZZZZ = Z \\otimes Z \\otimes Z \\otimes Z$$\n",
"\n",
"A valid codeword $|\\psi\\rangle$ satisfies:\n",
"$$XXXX|\\psi\\rangle = +|\\psi\\rangle \\quad\\text{and}\\quad ZZZZ|\\psi\\rangle = +|\\psi\\rangle$$\n",
"\n",
"In terms of expectation values: $\\langle XXXX \\rangle = +1$ and $\\langle ZZZZ \\rangle = +1$.\n",
"\n",
"Think of this as a **checksum**: just as a classical checksum detects corrupted data, the stabilizer eigenvalue detects corrupted quantum states. If an error occurs, at least one stabilizer flips to $-1$."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<z_stabilizer> = <ZZZZ> = +1.000000\n",
"<x_stabilizer> = <XXXX> = +1.000000\n",
"\n",
"Both stabilizers should be +1.0 for a valid codeword.\n"
]
}
],
"source": [
"# Compute stabilizer expectation values\n",
"for name, operator in STABILIZERS.items():\n",
" expectation = encoded_sv.expectation_value(operator)\n",
" print(f\"<{name}> = <{operator.to_list()[0][0]}> = {expectation.real:+.6f}\")\n",
"\n",
"print(\"\\nBoth stabilizers should be +1.0 for a valid codeword.\")"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2efb7eba17864530a1bf7f4a6da64edb",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2efb7eba17864530a1bf7f4a6da64edb",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HTML(value='<div style=\"font-size:14px; font-weight:600; color:#4a148c; margin-bottom:8px;\">&#9…"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quiz(tracker, \"q9_stabilizer_meaning\",\n",
" question=\"What does it mean when \\u27E8ZZZZ\\u27E9 = +1?\",\n",
" options=[\n",
" \"All four qubits are in the |0\\u27E9 state\",\n",
" \"The state is in the codespace \\u2014 no X-type error has been detected\",\n",
" \"The Z-gate has been applied to all four qubits\",\n",
" \"The state has zero energy\",\n",
" ],\n",
" correct=1,\n",
" section=\"6. Stabilizers\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"\\u27E8ZZZZ\\u27E9 = +1 means the state is an eigenstate of ZZZZ with eigenvalue +1. \"\n",
" \"This is the codespace condition. If a single X-error occurs on any qubit, \"\n",
" \"ZZZZ anti-commutes with that X, flipping the eigenvalue to \\u22121.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"quiz(tracker, \"q10_which_detects_what\",\n",
" question=\"A single Z error on qubit 3 occurs. Which stabilizer detects it?\",\n",
" options=[\n",
" \"ZZZZ (because Z commutes with Z, so ZZZZ stays at +1) \\u2014 wait, that means ZZZZ does NOT detect it\",\n",
" \"XXXX detects it (because Z anti-commutes with X)\",\n",
" \"Both XXXX and ZZZZ detect it\",\n",
" \"Neither \\u2014 Z errors are undetectable\",\n",
" ],\n",
" correct=1,\n",
" bloom=\"apply\",\n",
" explanation=(\n",
" \"Z commutes with Z (ZZ = ZZ), so ZZZZ is unaffected by a Z error. \"\n",
" \"But Z anti-commutes with X (ZX = \\u2212XZ), so XXXX flips to \\u22121. \"\n",
" \"Rule of thumb: X-errors are caught by the Z-stabilizer, and Z-errors by the X-stabilizer.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"6. Stabilizers\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 7. Error Detection in Action — Break It on Purpose\n",
"\n",
"### The experiment\n",
"\n",
"Let's deliberately inject errors and watch the stabilizers respond. We'll apply X (bit-flip), Z (phase-flip), and Y (both) errors on every qubit.\n",
"\n",
"**Prediction guide** before you run the next cell:\n",
"- An **X error** on any qubit: $X_j$ anti-commutes with $Z_j$ in $ZZZZ$, so $ZZZZ$ flips to $-1$. $XXXX$ is unaffected.\n",
"- A **Z error** on any qubit: $Z_j$ anti-commutes with $X_j$ in $XXXX$, so $XXXX$ flips to $-1$. $ZZZZ$ is unaffected.\n",
"- A **Y error** ($Y = iXZ$): both stabilizers flip to $-1$."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"predict_choice(tracker, \"q11_y_error_prediction\",\n",
" question=\"A Y error on qubit 2: how many stabilizers will flip to \\u22121?\",\n",
" options=[\"0 \\u2014 Y errors are undetectable\", \"1 \\u2014 either XXXX or ZZZZ\", \"2 \\u2014 both XXXX and ZZZZ\"],\n",
" correct=2,\n",
" section=\"7. Error detection\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"Y = iXZ contains both an X-part and a Z-part. \"\n",
" \"The X-part is caught by ZZZZ and the Z-part by XXXX. \"\n",
" \"Both stabilizers flip \\u2192 Y errors have the most distinctive syndrome signature.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Single error example: X on qubit 1\n",
"error_circuit = prep.copy()\n",
"error_circuit.x(1)\n",
"corrupted_sv = Statevector.from_instruction(error_circuit)\n",
"\n",
"print(\"Stabilizers AFTER X error on qubit 1:\")\n",
"for name, operator in STABILIZERS.items():\n",
" expectation = corrupted_sv.expectation_value(operator)\n",
" status = \"PASS\" if abs(expectation.real - 1.0) < 1e-6 else \"FAIL (error detected!)\"\n",
" print(f\" <{operator.to_list()[0][0]}> = {expectation.real:+.6f} [{status}]\")\n",
"\n",
"print(\"\\nCompare with the error-free case:\")\n",
"for name, operator in STABILIZERS.items():\n",
" expectation = encoded_sv.expectation_value(operator)\n",
" print(f\" <{operator.to_list()[0][0]}> = {expectation.real:+.6f} [PASS]\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Complete error detection table\n",
"print(\"Error detection summary:\")\n",
"print(f\"{'Error':>12s} | {'<XXXX>':>8s} | {'<ZZZZ>':>8s} | Detected by\")\n",
"print(\"-\" * 55)\n",
"\n",
"for qubit in range(4):\n",
" for error_name, error_gate in [(\"X\", \"x\"), (\"Z\", \"z\"), (\"Y\", \"y\")]:\n",
" err_circ = prep.copy()\n",
" getattr(err_circ, error_gate)(qubit)\n",
" err_sv = Statevector.from_instruction(err_circ)\n",
" xxxx = err_sv.expectation_value(STABILIZERS[\"x_stabilizer\"]).real\n",
" zzzz = err_sv.expectation_value(STABILIZERS[\"z_stabilizer\"]).real\n",
" detected_by = []\n",
" if abs(xxxx - 1.0) > 0.01:\n",
" detected_by.append(\"XXXX\")\n",
" if abs(zzzz - 1.0) > 0.01:\n",
" detected_by.append(\"ZZZZ\")\n",
" print(f\"{error_name}(q{qubit}): | {xxxx:+.4f} | {zzzz:+.4f} | {', '.join(detected_by) or 'none'}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reading the table\n",
"\n",
"Every single-qubit error is caught by at least one stabilizer:\n",
"\n",
"| Error type | Caught by | Reason |\n",
"|-----------|-----------|--------|\n",
"| X (bit-flip) | ZZZZ | X anti-commutes with Z |\n",
"| Z (phase-flip) | XXXX | Z anti-commutes with X |\n",
"| Y (both) | XXXX and ZZZZ | Y = iXZ, so both parts are caught |\n",
"\n",
"This is the **distance-2 guarantee**: the code detects all weight-1 errors. A weight-2 error (two qubits affected simultaneously) could go undetected — that's the limitation of distance 2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"order(tracker, \"q12_error_ranking\",\n",
" instruction=\"Sort error types by number of stabilizers they trigger (fewest \\u2192 most):\",\n",
" items=[\"X\", \"Z\", \"Y\"],\n",
" correct_order=[\"X\", \"Z\", \"Y\"],\n",
" bloom=\"analyze\",\n",
" explanation=(\n",
" \"X and Z each trigger exactly 1 stabilizer (tied). \"\n",
" \"Y triggers 2. So the order is X=Z < Y. \"\n",
" \"(X and Z are interchangeable in this ranking.)\"\n",
" ),\n",
" ties=[[\"X\", \"Z\"]])\n",
"\n",
"checkpoint_summary(tracker, \"7. Error detection\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 8. Comparing Encoder Styles\n",
"\n",
"### Why two encoders?\n",
"\n",
"Just as there are multiple seed styles, there are multiple ways to build the encoder circuit. The project implements:\n",
"\n",
"| Style | Native gates | Pre-transpilation depth |\n",
"|-------|-------------|------------------------|\n",
"| `cx_chain` | CNOT (CX) | 7 |\n",
"| `cz_compiled` | CZ (controlled-Z) | 11 |\n",
"\n",
"Both produce the **exact same** logical state. The choice matters after **transpilation**: if your hardware natively supports CZ gates, then `cz_compiled` may actually be *shorter* after transpilation than `cx_chain` (which would need each CNOT decomposed into CZ + Hadamard pairs)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Compare the two encoder styles\n",
"encoder_cz = build_encoder(\"cz_compiled\")\n",
"print(\"cz_compiled encoder circuit:\")\n",
"fig = encoder_cz.draw('mpl', style='iqp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Verify both encoders produce the same state\n",
"prep_cx = build_preparation_circuit(\"h_p\", \"cx_chain\")\n",
"prep_cz = build_preparation_circuit(\"h_p\", \"cz_compiled\")\n",
"\n",
"sv_cx = Statevector.from_instruction(prep_cx)\n",
"sv_cz = Statevector.from_instruction(prep_cz)\n",
"\n",
"fid = state_fidelity(sv_cx, sv_cz)\n",
"print(f\"Fidelity between cx_chain and cz_compiled: {fid:.6f}\")\n",
"print(f\"cx_chain depth: {prep_cx.depth()}, cz_compiled depth: {prep_cz.depth()}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"reflect(tracker, \"q13_encoder_tradeoff\",\n",
" question=\"The cz_compiled encoder has depth 11 vs cx_chain's depth 7. When might you prefer the deeper circuit?\",\n",
" section=\"8. Encoder comparison\",\n",
" bloom=\"evaluate\",\n",
" model_answer=(\n",
" \"If the hardware natively supports CZ gates (like many superconducting processors), \"\n",
" \"cx_chain would need each CNOT decomposed into CZ + Hadamard pairs, \"\n",
" \"potentially making it deeper AFTER transpilation. \"\n",
" \"The lesson: pre-transpilation depth is misleading. \"\n",
" \"What matters is depth after transpilation to the hardware's native gate set.\"\n",
" ))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 9. Verification Circuits with Ancilla Qubits\n",
"\n",
"### The measurement problem\n",
"\n",
"We just computed $\\langle ZZZZ \\rangle$ and $\\langle XXXX \\rangle$ using the full statevector. But on a real quantum computer, we don't have access to the statevector — we can only **measure** qubits.\n",
"\n",
"**The catch:** If we measure the 4 data qubits directly, the measurement collapses the superposition and **destroys** the encoded state. We'd learn the stabilizer value, but the T-state would be gone.\n",
"\n",
"### The solution: ancilla qubits\n",
"\n",
"Instead, we use **ancilla** (helper) qubits. The idea:\n",
"1. Prepare an ancilla qubit in $|0\\rangle$\n",
"2. Apply controlled gates between the ancilla and each data qubit to transfer the stabilizer's **parity** onto the ancilla\n",
"3. Measure **only the ancilla** — the data qubits remain untouched\n",
"\n",
"The ancilla measurement result (0 or 1) tells us the stabilizer eigenvalue ($+1$ or $-1$) without collapsing the data qubits. This is called **syndrome extraction**.\n",
"\n",
"The result is a **syndrome** bitstring. For our code with two stabilizers, the syndrome is 2 bits:\n",
"- `00` → both stabilizers +1 → no error detected → **keep this shot**\n",
"- Anything else → error detected → **discard this shot** (postselection)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Build the full circuit bundle for a standard experiment\n",
"spec = ExperimentSpec(\n",
" rung=1,\n",
" seed_style=\"h_p\",\n",
" encoder_style=\"cx_chain\",\n",
" verification=\"both\",\n",
" postselection=\"all_measured\",\n",
" ancilla_strategy=\"dedicated_pair\",\n",
" shots=256,\n",
" repeats=1,\n",
")\n",
"\n",
"bundle = build_circuit_bundle(spec)\n",
"print(f\"Bundle contains:\")\n",
"print(f\" prep circuit: {bundle.prep.num_qubits} qubits (data only)\")\n",
"print(f\" acceptance circuit: {bundle.acceptance.num_qubits} qubits ({DATA_QUBITS} data + {bundle.acceptance.num_qubits - DATA_QUBITS} ancilla)\")\n",
"print(f\" witness circuits: {list(bundle.witness_circuits.keys())}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Show the acceptance circuit\n",
"print(\"Acceptance circuit (syndrome extraction + data readout):\")\n",
"print(f\" Classical registers: {[creg.name + f'[{creg.size}]' for creg in bundle.acceptance.cregs]}\")\n",
"fig = bundle.acceptance.draw('mpl', style='iqp')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reading the acceptance circuit\n",
"\n",
"The circuit has two **classical registers**:\n",
"- **syndrome** [2 bits]: Results from ancilla measurements. Bit 0 = $ZZZZ$ check, bit 1 = $XXXX$ check.\n",
"- **readout** [4 bits]: Results from measuring the data qubits.\n",
"\n",
"In the circuit diagram, look for:\n",
"- The **ancilla qubits** (extra qubits above/below the data register)\n",
"- **Controlled gates** connecting ancillas to data qubits (these extract the parity)\n",
"- **Measurement gates** (the meter symbol) on the ancillas and data qubits"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"quiz(tracker, \"q14_ancilla_purpose\",\n",
" question=\"Why can't we just measure the 4 data qubits to check the stabilizers?\",\n",
" options=[\n",
" \"We can, but ancillas make it faster\",\n",
" \"Direct measurement collapses the superposition and destroys the encoded state\",\n",
" \"The stabilizer operators are not physical observables\",\n",
" ],\n",
" correct=1,\n",
" section=\"9. Verification circuits\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"Measuring individual qubits in the Z basis projects them into |0\\u27E9 or |1\\u27E9, \"\n",
" \"destroying the superposition that encodes the T-state. \"\n",
" \"Ancilla-based syndrome extraction reads the stabilizer eigenvalue \"\n",
" \"without disturbing the logical information.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Show a witness circuit (logical_x)\n",
"print(\"Logical X witness circuit:\")\n",
"print(f\" Measures operator: {MEASUREMENT_OPERATORS['logical_x']}\")\n",
"fig = bundle.witness_circuits[\"logical_x\"].draw('mpl', style='iqp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"quiz(tracker, \"q15_three_circuits\",\n",
" question=\"The bundle has 3 witness circuits (logical_x, logical_y, spectator_z). Why not measure all operators in one circuit?\",\n",
" options=[\n",
" \"The operators don't commute \\u2014 measuring one would disturb the others\",\n",
" \"It would require too many qubits\",\n",
" \"The simulator can only handle one operator at a time\",\n",
" ],\n",
" correct=0,\n",
" bloom=\"analyze\",\n",
" explanation=(\n",
" \"Logical X (X\\u2080X\\u2082) and Logical Y (Y\\u2080Z\\u2081X\\u2082) do not commute. \"\n",
" \"Measuring one changes the state in a way that invalidates the other measurement. \"\n",
" \"So each must be measured on a separate, independently prepared copy of the state.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"9. Verification circuits\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 10. Running an Ideal Simulation\n",
"\n",
"### What to expect\n",
"\n",
"In a **noiseless** simulation, the state is always in the codespace. That means:\n",
"- Both stabilizers always return +1\n",
"- Syndrome is always `00`\n",
"- **Every** shot passes postselection → acceptance rate = 100%\n",
"\n",
"This is our baseline. Real hardware will be much noisier."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Run on ideal AerSimulator\n",
"sim = AerSimulator()\n",
"shots = 512\n",
"\n",
"result = sim.run(bundle.acceptance, shots=shots).result()\n",
"counts = result.get_counts()\n",
"\n",
"print(f\"Ran {shots} shots on ideal simulator.\")\n",
"print(f\"Number of distinct outcomes: {len(counts)}\")\n",
"print(f\"\\nRaw counts (syndrome + readout):\")\n",
"for bitstring, count in sorted(counts.items(), key=lambda x: -x[1]):\n",
" parts = bitstring.split(\" \")\n",
" if len(parts) == 2:\n",
" syndrome, readout = parts[0], parts[1]\n",
" else:\n",
" syndrome, readout = \"\", parts[0]\n",
" print(f\" syndrome={syndrome} readout={readout} : {count} shots ({100*count/shots:.1f}%)\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"quiz(tracker, \"q16_ideal_acceptance\",\n",
" question=\"In the ideal simulation above, what fraction of shots have syndrome = '00'?\",\n",
" options=[\"About 25%\", \"About 50%\", \"About 75%\", \"100%\"],\n",
" correct=3,\n",
" section=\"10. Ideal simulation\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"With no noise, the state never leaves the codespace. \"\n",
" \"Every stabilizer measurement returns +1, giving syndrome 00 on every shot.\"\n",
" ))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Visualize\n",
"fig = plot_histogram(counts, figsize=(12, 5), title=\"Ideal Simulation: Syndrome + Readout\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 11. Postselection — Keeping Only the Good Shots\n",
"\n",
"### The idea\n",
"\n",
"**Postselection** is a filter: after collecting all measurement results, we look at the syndrome bits and **discard** any shot where the syndrome indicates an error was detected.\n",
"\n",
"In the ideal case (above), this filter has no effect — all shots pass. But under noise (Notebook 2), many shots will fail the syndrome check. The trade-off:\n",
"\n",
"| | Without postselection | With postselection |\n",
"|---|---|---|\n",
"| **Shots used** | All | Only syndrome = \"00\" |\n",
"| **Quality** | Lower (includes error-corrupted shots) | Higher (only clean shots) |\n",
"| **Statistical power** | More data points | Fewer data points |\n",
"| **Cost** | Lower | Higher (need more total shots for same statistics) |\n",
"\n",
"The scoring formula in this project captures this tension directly:\n",
"\n",
"$$\\text{score} = \\frac{\\text{quality} \\times \\text{acceptance\\_rate}}{\\text{cost}}$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from autoresearch_quantum.execution.analysis import (\n",
" postselection_passes, local_memory_records, summarize_context,\n",
")\n",
"\n",
"# Run with memory to access individual shot records\n",
"shots = 1024\n",
"sim = AerSimulator()\n",
"result = sim.run(bundle.acceptance, shots=shots, memory=True).result()\n",
"memory = result.get_memory(bundle.acceptance)\n",
"\n",
"# Parse into structured records\n",
"records = local_memory_records(memory, [creg.name for creg in bundle.acceptance.cregs])\n",
"syndrome_labels = bundle.acceptance.metadata.get(\"syndrome_labels\", [])\n",
"postselection_rule = bundle.acceptance.metadata.get(\"postselection\", \"all_measured\")\n",
"\n",
"summary = summarize_context(records, syndrome_labels, postselection_rule)\n",
"\n",
"print(f\"Total shots: {summary['total_shots']}\")\n",
"print(f\"Accepted shots: {summary['accepted_shots']}\")\n",
"print(f\"Acceptance rate: {summary['acceptance_rate']:.4f}\")\n",
"print(f\"\\nSyndrome distribution:\")\n",
"for syndrome, count in sorted(summary['syndrome_counts'].items()):\n",
" pct = count / summary['total_shots'] * 100\n",
" label = \"PASS\" if all(b == '0' for b in syndrome) else \"FAIL\"\n",
" print(f\" syndrome={syndrome} count={count:4d} ({pct:5.1f}%) [{label}]\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"quiz(tracker, \"q17_postselection_cost\",\n",
" question=\"What is the fundamental cost of postselection?\",\n",
" options=[\n",
" \"It makes the circuit deeper and noisier\",\n",
" \"It throws away shots, reducing the amount of usable data\",\n",
" \"It introduces classical computation overhead\",\n",
" \"It requires extra qubits\",\n",
" ],\n",
" correct=1,\n",
" section=\"11. Postselection\",\n",
" bloom=\"understand\",\n",
" explanation=(\n",
" \"Postselection discards shots where errors were detected. \"\n",
" \"Fewer usable shots means worse statistics or more total shots needed. \"\n",
" \"This is why acceptance_rate appears in the scoring formula \\u2014 \"\n",
" \"a code that rejects 90% of shots must produce 10x the quality to break even.\"\n",
" ))\n",
"\n",
"checkpoint_summary(tracker, \"11. Postselection\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 12. Summary\n",
"\n",
"In this notebook you learned:\n",
"\n",
"| Concept | What you now know |\n",
"|---------|------------------|\n",
"| **T-state** | The non-Clifford resource $|T\\rangle = (|0\\rangle + e^{i\\pi/4}|1\\rangle)/\\sqrt{2}$ needed for universal QC |\n",
"| **Seed styles** | Three equivalent gate sequences (h_p, ry_rz, u_magic) — same physics, different engineering trade-offs |\n",
"| **[[4,2,2]] code** | 4 physical qubits, 2 logical qubits, distance 2 — detects but doesn't correct single errors |\n",
"| **Stabilizers** | XXXX and ZZZZ act as quantum checksums — eigenvalue +1 means \"no error\" |\n",
"| **Error detection** | X→caught by ZZZZ, Z→caught by XXXX, Y→caught by both |\n",
"| **Ancilla qubits** | Allow syndrome extraction without destroying the encoded state |\n",
"| **Postselection** | Discard error-flagged shots to improve quality at the cost of acceptance rate |\n",
"\n",
"**Next up (Notebook 2):** What happens when we add realistic noise? How bad does it get? And how do we measure whether the encoding actually *helped*? We'll introduce the magic witness formula, the full scoring function, and explore how noise degrades each metric."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## Final Assessment"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tracker.dashboard()\n",
"path = tracker.save()\n",
"print(f\"\\nProgress saved to: {path}\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}