{ "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "display_name": "Python 3 (ipywidgets)", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.14.0" } }, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Experiment 1: Can Quantum Error Detection Protect a Magic State?\n", "\n", "---\n", "\n", "## Hypothesis\n", "\n", "> **H1:** The $[\\![4,2,2]\\!]$ quantum error-detecting code can encode a\n", "> single-qubit magic state $|T\\rangle$ such that (a) the magic-state\n", "> character is fully preserved, and (b) every single-qubit error is\n", "> detectable by stabiliser measurement.\n", "\n", "### Why this matters\n", "\n", "Fault-tolerant quantum computing needs the $T$-gate, but the $T$-gate\n", "cannot be implemented transversally on most error-correcting codes\n", "(Eastin\u2013Knill theorem). The workaround is to prepare a **magic state**\n", "$|T\\rangle = (|0\\rangle + e^{i\\pi/4}|1\\rangle)/\\sqrt{2}$ and consume\n", "it via gate teleportation.\n", "\n", "But a bare qubit has no error protection. If noise corrupts $|T\\rangle$\n", "before we use it, the entire computation is silently wrong. We need to\n", "**encode** $|T\\rangle$ into an error-detecting code so that corrupted\n", "copies can be identified and discarded.\n", "\n", "**The question:** Does the encoding actually work? Does it preserve the\n", "magic, and can it catch errors?\n", "\n", "### Claim\n", "\n", "We claim that after encoding into the $[\\![4,2,2]\\!]$ code:\n", "1. The magic witness $W = 1.0$ (perfect magic preserved).\n", "2. Both stabiliser expectations are $+1$ (valid codeword).\n", "3. Every single-qubit Pauli error ($X$, $Z$, $Y$) flips at least one\n", " stabiliser from $+1$ to $-1$.\n", "4. Postselection on syndrome \"00\" correctly filters all detected errors." ] }, { "cell_type": "code", "metadata": {}, "source": [ "%matplotlib inline\n", "import warnings; warnings.filterwarnings(\"ignore\")\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from math import pi, sqrt\n", "\n", "from qiskit import QuantumCircuit\n", "from qiskit.quantum_info import Statevector, SparsePauliOp, state_fidelity\n", "from qiskit.visualization import plot_bloch_multivector\n", "from qiskit_aer import AerSimulator\n", "\n", "from autoresearch_quantum.codes.four_two_two import (\n", " build_preparation_circuit, build_encoder, apply_magic_seed,\n", " encoded_magic_statevector, STABILIZERS, MEASUREMENT_OPERATORS, DATA_QUBITS,\n", ")\n", "from autoresearch_quantum.experiments.encoded_magic_state import build_circuit_bundle\n", "from autoresearch_quantum.models import ExperimentSpec\n", "from autoresearch_quantum.execution.analysis import logical_magic_witness\n", "\n", "print(\"All imports successful.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "from autoresearch_quantum.teaching import LearningTracker\n", "from autoresearch_quantum.teaching.assess import quiz, predict_choice, reflect, order, checkpoint_summary\n", "tracker = LearningTracker(\"plan_d_exp1\")\n", "print(\"Learning tracker active.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 1: The Magic State on a Single Qubit\n", "\n", "Before we can test the encoding, we need to understand what we're\n", "encoding. The magic state is:\n", "\n", "$$|T\\rangle = \\frac{|0\\rangle + e^{i\\pi/4}|1\\rangle}{\\sqrt{2}}$$\n", "\n", "It lives on the **equator** of the Bloch sphere, at $45\u00b0$ between the\n", "$+X$ and $+Y$ axes. Its special property: it enables the $T$-gate via\n", "gate teleportation \u2014 the key non-Clifford resource for universal quantum\n", "computing." ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Build the T-state\n", "qc = QuantumCircuit(1, name=\"|T>\")\n", "qc.h(0)\n", "qc.p(pi/4, 0)\n", "\n", "t_state = Statevector.from_instruction(qc)\n", "print(\"T-state amplitudes:\")\n", "print(f\" |0>: {t_state[0]:.4f}\")\n", "print(f\" |1>: {t_state[1]:.4f}\")\n", "print(f\" |1> phase: {np.angle(t_state[1])*180/pi:.1f} degrees = pi/4\")\n", "\n", "# Bloch coordinates\n", "bloch = [t_state.expectation_value(SparsePauliOp(p)).real for p in ['X', 'Y', 'Z']]\n", "print(f\"\\nBloch coordinates:\")\n", "print(f\" = {bloch[0]:.4f} (expected: 1/sqrt(2) = {1/sqrt(2):.4f})\")\n", "print(f\" = {bloch[1]:.4f} (expected: 1/sqrt(2) = {1/sqrt(2):.4f})\")\n", "print(f\" = {bloch[2]:.4f} (on the equator)\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q1_tstate_phase\",\n", " question=\"What is the phase of the |1\\u27E9 coefficient in the T-state?\",\n", " options=[\"\\u03C0/2 (90\\u00b0)\", \"\\u03C0/4 (45\\u00b0)\", \"\\u03C0/8 (22.5\\u00b0)\"],\n", " correct=1, section=\"1. T-state\", bloom=\"remember\",\n", " explanation=\"\\u03C0/4 = 45\\u00b0. The gate is called T (\\u03C0/8 on the Bloch sphere), but the state phase is \\u03C0/4.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 2: Encoding into the $[\\![4,2,2]\\!]$ Code\n", "\n", "The $[\\![4,2,2]\\!]$ code uses **4 physical qubits** to encode **2 logical\n", "qubits** with **distance 2** (detects any single-qubit error).\n", "\n", "- **Logical qubit 0** (\"the magic qubit\"): will hold $|T\\rangle$.\n", "- **Logical qubit 1** (\"the spectator\"): stays in $|0\\rangle_L$.\n", "\n", "The codespace is the simultaneous $+1$ eigenspace of two stabilisers:\n", "- $S_X = XXXX$\n", "- $S_Z = ZZZZ$\n", "\n", "Any state inside the codespace satisfies $\\langle XXXX \\rangle = +1$\n", "and $\\langle ZZZZ \\rangle = +1$. An error kicks the state out of the\n", "codespace, flipping at least one eigenvalue to $-1$." ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Build the full preparation: seed (H+P) on qubit 0, then encode all 4\n", "prep = build_preparation_circuit(\"h_p\", \"cx_chain\")\n", "print(f\"Preparation circuit: {prep.num_qubits} qubits, depth {prep.depth()}\")\n", "prep.draw(\"mpl\", style=\"iqp\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "# Compute the encoded statevector\n", "state = encoded_magic_statevector()\n", "print(f\"Statevector has {len(state)} amplitudes (2^4 = 16)\")\n", "print(f\"\\nNon-zero amplitudes (the codespace):\")\n", "for i, amp in enumerate(state.data):\n", " if abs(amp) > 1e-10:\n", " print(f\" |{i:04b}> : {amp:.4f} (magnitude: {abs(amp):.4f})\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "predict_choice(tracker, \"q2_nonzero\",\n", " question=\"How many of the 16 basis states have non-zero amplitude?\",\n", " options=[\"2\", \"4\", \"8\", \"All 16\"],\n", " correct=1, section=\"2. Encoding\", bloom=\"understand\",\n", " explanation=\"Only 4 basis states (0000, 0101, 1010, 1111) have non-zero amplitude. These span the codespace of the [[4,2,2]] code.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 3: Testing Claim (2) \u2014 Stabiliser Verification\n", "\n", "**Claim:** Both stabiliser expectations are $+1$, confirming the\n", "encoded state is a valid codeword." ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Verify stabiliser expectations\n", "state = encoded_magic_statevector()\n", "for name, stab in STABILIZERS.items():\n", " exp = state.expectation_value(stab).real\n", " status = \"PASS\" if abs(exp - 1.0) < 1e-6 else \"FAIL\"\n", " print(f\" <{name}> = {exp:+.6f} [{status}]\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Result:** Both stabilisers read $+1$. The state is in the codespace. \\checkmark" ] }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q3_stabilizer_meaning\",\n", " question=\"\\u27E8ZZZZ\\u27E9 = +1 tells us:\",\n", " options=[\n", " \"All four qubits are in |0\\u27E9\",\n", " \"The state is in the codespace \\u2014 no X-type error detected\",\n", " \"The Z-gate has been applied to all qubits\",\n", " ],\n", " correct=1, section=\"3. Stabilisers\", bloom=\"understand\",\n", " explanation=\"ZZZZ detects X errors (X anti-commutes with Z). Eigenvalue +1 means no X error is present.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 4: Testing Claim (3) \u2014 Every Single-Qubit Error Is Detectable\n", "\n", "**Claim:** Every single-qubit Pauli error ($X$, $Z$, $Y$ on any of the\n", "4 qubits) flips at least one stabiliser from $+1$ to $-1$.\n", "\n", "We will systematically inject every possible single-qubit error and\n", "check the stabilisers." ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Complete error detection table\n", "from qiskit.quantum_info import Operator\n", "state = encoded_magic_statevector()\n", "\n", "errors_detected = 0\n", "errors_total = 0\n", "\n", "header = f\"{'Error':14s} {'':>8s} {'':>8s} {'Detected by':>15s}\"\n", "print(header)\n", "print(\"=\" * len(header))\n", "\n", "for error_type in ['X', 'Y', 'Z']:\n", " for qubit in range(4):\n", " # Apply single-qubit error\n", " error_gate = {'X': np.array([[0,1],[1,0]]),\n", " 'Y': np.array([[0,-1j],[1j,0]]),\n", " 'Z': np.array([[1,0],[0,-1]])}[error_type]\n", " full_error = np.eye(1)\n", " for q in range(4):\n", " full_error = np.kron(full_error, error_gate if q == qubit else np.eye(2))\n", " corrupted = Statevector(full_error @ state.data)\n", "\n", " xxxx = corrupted.expectation_value(STABILIZERS[\"x_stabilizer\"]).real\n", " zzzz = corrupted.expectation_value(STABILIZERS[\"z_stabilizer\"]).real\n", "\n", " detected_by = []\n", " if abs(xxxx - (-1)) < 0.01: detected_by.append(\"XXXX\")\n", " if abs(zzzz - (-1)) < 0.01: detected_by.append(\"ZZZZ\")\n", "\n", " errors_total += 1\n", " if detected_by:\n", " errors_detected += 1\n", "\n", " det_str = \", \".join(detected_by) if detected_by else \"NONE!\"\n", " print(f\"{error_type}(q{qubit}): {xxxx:+.1f} {zzzz:+.1f} {det_str}\")\n", "\n", "print(f\"\\nDetected: {errors_detected}/{errors_total} single-qubit errors\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Result:** All 12 single-qubit errors detected (12/12). \\checkmark\n", "\n", "- $X$ errors: detected by $ZZZZ$ (because $X$ anti-commutes with $Z$)\n", "- $Z$ errors: detected by $XXXX$ (because $Z$ anti-commutes with $X$)\n", "- $Y$ errors: detected by **both** (because $Y = iXZ$)" ] }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q4_which_detects\",\n", " question=\"A Z error on qubit 2 occurs. Which stabiliser detects it?\",\n", " options=[\n", " \"ZZZZ (because Z commutes with Z \\u2014 wait, that means it does NOT detect it)\",\n", " \"XXXX (because Z anti-commutes with X, flipping the eigenvalue)\",\n", " \"Neither \\u2014 Z errors are invisible\",\n", " ],\n", " correct=1, section=\"4. Error detection\", bloom=\"apply\",\n", " explanation=\"Z anti-commutes with X. A Z error on any qubit flips \\u27E8XXXX\\u27E9 from +1 to \\u22121.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "order(tracker, \"q5_error_severity\",\n", " instruction=\"Rank error types by how many stabilisers they trigger (fewest \\u2192 most):\",\n", " items=[\"X\", \"Z\", \"Y\"],\n", " correct_order=[\"X\", \"Z\", \"Y\"],\n", " section=\"4. Error detection\", bloom=\"analyze\",\n", " explanation=\"X \\u2192 1 (ZZZZ). Z \\u2192 1 (XXXX). Y \\u2192 2 (both). X and Z are tied at 1.\",\n", " ties=[[\"X\", \"Z\"]])" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 5: Testing Claim (1) \u2014 The Magic Witness\n", "\n", "**Claim:** The magic witness $W = 1.0$, proving the encoded state fully\n", "preserves the $T$-state character.\n", "\n", "The witness formula:\n", "$$W = \\frac{1 + \\frac{\\langle X_L \\rangle + \\langle Y_L \\rangle}{\\sqrt{2}}}{2}\n", "\\times \\frac{1 + \\langle Z_{\\text{spec}} \\rangle}{2}$$" ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Measure logical operators\n", "state = encoded_magic_statevector()\n", "results = {}\n", "for name, op_dict in MEASUREMENT_OPERATORS.items():\n", " pauli_str = [\"I\"] * 4\n", " for qubit, basis in op_dict.items():\n", " pauli_str[qubit] = basis\n", " label = \"\".join(reversed(pauli_str))\n", " op = SparsePauliOp(label)\n", " results[name] = state.expectation_value(op).real\n", "\n", "lx, ly, sz = results[\"logical_x\"], results[\"logical_y\"], results[\"spectator_z\"]\n", "print(f\" = {lx:+.6f} (ideal: +1/sqrt(2) = +{1/sqrt(2):.6f})\")\n", "print(f\" = {ly:+.6f} (ideal: +1/sqrt(2) = +{1/sqrt(2):.6f})\")\n", "print(f\" = {sz:+.6f} (ideal: +1.000000)\")\n", "\n", "magic_factor = (1 + (lx + ly)/sqrt(2)) / 2\n", "spec_factor = (1 + sz) / 2\n", "W = magic_factor * spec_factor\n", "\n", "print(f\"\\nMagic factor = {magic_factor:.6f}\")\n", "print(f\"Spectator factor = {spec_factor:.6f}\")\n", "print(f\"Witness W = {W:.6f}\")\n", "print(f\"Library check = {logical_magic_witness(lx, ly, sz):.6f}\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Result:** $W = 1.0$. The encoding perfectly preserves the magic-state character. \\checkmark" ] }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q6_ideal_witness\",\n", " question=\"For a perfect T-state, the magic witness W equals:\",\n", " options=[\"0.0\", \"0.5\", \"1/\\u221A2 \\u2248 0.707\", \"1.0\"],\n", " correct=3, section=\"5. Witness\", bloom=\"apply\",\n", " explanation=\"Ideal: magic_factor = 1.0, spectator_factor = 1.0. Product = 1.0.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Part 6: Testing Claim (4) \u2014 Postselection Works\n", "\n", "**Claim:** Syndrome-based postselection correctly identifies all\n", "detected errors. On an ideal simulator, 100% of shots have syndrome \"00\"\n", "(no error detected)." ] }, { "cell_type": "code", "metadata": {}, "source": [ "# Build the full circuit bundle and run on ideal simulator\n", "spec = ExperimentSpec(rung=1, seed_style=\"h_p\", encoder_style=\"cx_chain\",\n", " verification=\"both\", postselection=\"all_measured\",\n", " shots=512, repeats=1)\n", "bundle = build_circuit_bundle(spec)\n", "\n", "sim = AerSimulator()\n", "from autoresearch_quantum.execution.analysis import summarize_context, local_memory_records\n", "\n", "total_accepted = 0\n", "total_shots = 0\n", "for name, circ in bundle.witness_circuits.items():\n", " job = sim.run(circ, shots=512, memory=True)\n", " memory = job.result().get_memory()\n", " records = local_memory_records(memory, [cr.name for cr in circ.cregs])\n", " summary = summarize_context(records, [\"z_stabilizer\", \"x_stabilizer\"],\n", " spec.postselection, MEASUREMENT_OPERATORS[name])\n", " total_accepted += summary[\"accepted_shots\"]\n", " total_shots += summary[\"total_shots\"]\n", " print(f\"{name:15s}: acceptance = {summary['acceptance_rate']:.4f}, \"\n", " f\" = {summary['expectation']:+.4f}\")\n", "\n", "print(f\"\\nOverall acceptance: {total_accepted}/{total_shots} \"\n", " f\"= {total_accepted/total_shots:.4f}\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Result:** 100% acceptance on the ideal simulator. Every shot has syndrome \"00\". \\checkmark" ] }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q7_acceptance_ideal\",\n", " question=\"On an ideal simulator, what fraction of shots pass the syndrome check?\",\n", " options=[\"About 50%\", \"About 75%\", \"100%\"],\n", " correct=2, section=\"6. Postselection\", bloom=\"understand\",\n", " explanation=\"No noise means no errors. Every shot is in the codespace, so every syndrome is 00.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Proof Summary\n", "\n", "| Claim | Result | Status |\n", "|-------|--------|--------|\n", "| (1) Magic witness $W = 1.0$ | $W = 1.000000$ | **Proven** |\n", "| (2) Both stabilisers at $+1$ | $\\langle XXXX \\rangle = +1$, $\\langle ZZZZ \\rangle = +1$ | **Proven** |\n", "| (3) Every 1-qubit error detected | 12/12 detected | **Proven** |\n", "| (4) Postselection filters correctly | 100% acceptance (ideal) | **Proven** |\n", "\n", "**Hypothesis H1 is confirmed.** The $[\\![4,2,2]\\!]$ code can encode a\n", "magic state with perfect fidelity, and its error detection works exactly\n", "as the theory predicts.\n", "\n", "---\n", "\n", "## But Wait \u2014 Next Hypothesis\n", "\n", "> **H2 (for Experiment 2):** Everything above was on a **perfect\n", "> simulator** with zero noise. On a realistic noise model (mimicking\n", "> IBM Brisbane, 127 qubits, real error rates), the magic-state quality\n", "> will degrade \u2014 but the degradation is **quantifiable**, and by tuning\n", "> circuit parameters we can recover significantly more magic than a\n", "> naive default configuration.\n", "\n", "**The question Experiment 2 will answer:** How much magic survives\n", "real-world noise, and can we measure the damage precisely enough to\n", "optimise against it?" ] }, { "cell_type": "code", "metadata": {}, "source": [ "checkpoint_summary(tracker, \"6. Postselection\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Assessment" ] }, { "cell_type": "code", "metadata": {}, "source": [ "tracker.dashboard()\n", "path = tracker.save()\n", "print(f\"\\nProgress saved to: {path}\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "d129382e", "source": "---\n## Navigation \u2014 Plan D\n\n**\u2192 Next: [Experiment 2 \u2014 How Much Magic Survives Noise?](experiment_2_noise.ipynb)**\n\n*\u2190 Back to [Start Here](../00_START_HERE.ipynb)*", "metadata": {} } ] }