mirror of
https://github.com/saymrwulf/autoresearch-quantum.git
synced 2026-09-04 18:53:39 +00:00
- Create notebooks/00_START_HERE.ipynb as the single entry point with plan descriptions, audience guidance, and links to all 4 plans - Add navigation footer cells to all 11 content notebooks with Next/Previous links and back-link to Start Here - Terminal notebooks (plan endings) offer cross-plan links to explore other plans - Plan C dashboard gets explicit recommended reading order (Track A → B → C) - Add test_start_here_exists_and_links_all_plans and test_every_notebook_has_navigation_footer to test suite - Skip navigation-only notebooks in code-cell and assessment tests
690 lines
No EOL
27 KiB
Text
690 lines
No EOL
27 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Track B: The Engineering \u2014 Noise, Transpilation, and Cost\n",
|
|
"\n",
|
|
"**Plan C \u2014 Parallel Tracks**\n",
|
|
"\n",
|
|
"This track is about making quantum circuits work on noisy hardware. You will learn how noise degrades the encoded state, how transpilation maps logical circuits to physical hardware, and how the scoring formula balances quality against cost.\n",
|
|
"\n",
|
|
"> **Dashboard:** Open `00_dashboard.ipynb` to interactively compare settings."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"%matplotlib inline\n",
|
|
"import warnings\n",
|
|
"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, DensityMatrix, state_fidelity\n",
|
|
"from qiskit.visualization import plot_histogram\n",
|
|
"from qiskit_aer import AerSimulator\n",
|
|
"from qiskit_aer.noise import NoiseModel\n",
|
|
"\n",
|
|
"from autoresearch_quantum.codes.four_two_two import (\n",
|
|
" build_preparation_circuit, encoded_magic_statevector,\n",
|
|
" STABILIZERS, MEASUREMENT_OPERATORS, DATA_QUBITS,\n",
|
|
")\n",
|
|
"from autoresearch_quantum.experiments.encoded_magic_state import build_circuit_bundle\n",
|
|
"from autoresearch_quantum.models import (\n",
|
|
" ExperimentSpec, RungConfig, EvaluationMetrics,\n",
|
|
" QualityWeights, CostWeights, ScoreConfig, SearchSpaceConfig,\n",
|
|
" TierPolicyConfig, HardwareConfig,\n",
|
|
")\n",
|
|
"from autoresearch_quantum.execution.local import LocalCheapExecutor\n",
|
|
"from autoresearch_quantum.execution.analysis import (\n",
|
|
" logical_magic_witness, stability_score, summarize_context,\n",
|
|
" local_memory_records,\n",
|
|
")\n",
|
|
"from autoresearch_quantum.execution.backends import resolve_backend, backend_metadata\n",
|
|
"from autoresearch_quantum.execution.transpile import (\n",
|
|
" transpile_circuits, count_two_qubit_gates, circuit_metadata, runtime_estimate,\n",
|
|
")\n",
|
|
"from autoresearch_quantum.scoring.score import (\n",
|
|
" score_metrics, weighted_acceptance_cost, factory_throughput_score,\n",
|
|
")\n",
|
|
"from autoresearch_quantum.config import load_rung_config\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_c_track_b\")\n",
|
|
"print(\"Learning tracker active.\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 1. Ideal vs Noisy Simulation\n",
|
|
"\n",
|
|
"Let us build an encoded magic state circuit and run it in two regimes: perfect (no noise) and realistic (fake_brisbane noise model)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Build the circuit\n",
|
|
"spec = ExperimentSpec(\n",
|
|
" rung=1, seed_style=\"h_p\", encoder_style=\"cx_chain\",\n",
|
|
" verification=\"both\", postselection=\"all_measured\",\n",
|
|
" target_backend=\"fake_brisbane\", noise_backend=\"fake_brisbane\",\n",
|
|
" optimization_level=2, shots=512, repeats=1,\n",
|
|
")\n",
|
|
"bundle = build_circuit_bundle(spec)\n",
|
|
"backend = resolve_backend(\"fake_brisbane\")\n",
|
|
"\n",
|
|
"# Transpile\n",
|
|
"transpiled = transpile_circuits([bundle.acceptance], spec, backend)[0]\n",
|
|
"\n",
|
|
"# Ideal\n",
|
|
"ideal_sim = AerSimulator()\n",
|
|
"ideal_result = ideal_sim.run(transpiled, shots=512, memory=True, seed_simulator=42).result()\n",
|
|
"\n",
|
|
"# Noisy\n",
|
|
"noise_model = NoiseModel.from_backend(backend)\n",
|
|
"noisy_sim = AerSimulator(\n",
|
|
" noise_model=noise_model,\n",
|
|
" basis_gates=noise_model.basis_gates,\n",
|
|
" coupling_map=backend.coupling_map,\n",
|
|
")\n",
|
|
"noisy_result = noisy_sim.run(transpiled, shots=512, memory=True, seed_simulator=42).result()\n",
|
|
"\n",
|
|
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 4))\n",
|
|
"plot_histogram(ideal_result.get_counts(), ax=ax1, title=\"Ideal\")\n",
|
|
"plot_histogram(noisy_result.get_counts(), ax=ax2, title=\"Noisy (fake_brisbane)\")\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"predict_choice(tracker, \"q1_noise_histogram\",\n",
|
|
" question=\"Comparing the ideal and noisy histograms: what is the main visible difference?\",\n",
|
|
" options=[\n",
|
|
" \"The noisy histogram has fewer bars\",\n",
|
|
" \"The noisy histogram spreads probability across many more bitstrings\",\n",
|
|
" \"They look identical\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"1. Ideal vs noisy\", bloom=\"understand\",\n",
|
|
" explanation=\"Noise causes probability to leak from the valid codewords to other basis states. This spreading is the visual signature of decoherence.\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Observe:** The ideal histogram concentrates on a few bitstrings (valid codewords). Noise spreads probability across many bitstrings \u2014 errors kick the state out of the codespace.\n",
|
|
"\n",
|
|
"---\n",
|
|
"## 2. What Is a Noise Model?\n",
|
|
"\n",
|
|
"A noise model describes the errors each gate introduces. The fake_brisbane backend models the real IBM Brisbane device."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"meta = backend_metadata(backend)\n",
|
|
"print(f\"Backend: {meta['name']}\")\n",
|
|
"print(f\"Qubits: {meta['num_qubits']}\")\n",
|
|
"print(f\"Native gates: {meta['operation_names'][:8]}...\")\n",
|
|
"print(f\"Coupling edges: {meta['coupling_edges']}\")\n",
|
|
"\n",
|
|
"noise_dict = noise_model.to_dict()\n",
|
|
"print(f\"\\nNoise model: {len(noise_dict['errors'])} error channels\")\n",
|
|
"\n",
|
|
"# Show a sample of error rates\n",
|
|
"error_types = {}\n",
|
|
"for err in noise_dict['errors']:\n",
|
|
" etype = err['type']\n",
|
|
" error_types[etype] = error_types.get(etype, 0) + 1\n",
|
|
"print(\"\\nError types:\")\n",
|
|
"for etype, count in error_types.items():\n",
|
|
" print(f\" {etype}: {count} channels\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"quiz(tracker, \"q2_native_gates\",\n",
|
|
" question=\"The hardware has native gates like CX, SX, RZ. What happens to non-native gates like H?\",\n",
|
|
" options=[\n",
|
|
" \"They are executed directly\",\n",
|
|
" \"The transpiler decomposes them into native gate sequences\",\n",
|
|
" \"They cause an error\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"2. Backend\", bloom=\"understand\",\n",
|
|
" explanation=\"The transpiler converts all gates to the hardware's native set. H becomes SX + RZ. This decomposition adds gates and thus noise.\")\n",
|
|
"checkpoint_summary(tracker, \"2. Backend\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 3. Transpilation: Logical to Physical\n",
|
|
"\n",
|
|
"The logical circuit uses abstract gates (H, CX, P). The physical hardware only supports specific native gates. **Transpilation** maps one to the other, adding SWAP gates for connectivity and decomposing gates into the native set.\n",
|
|
"\n",
|
|
"Qiskit offers optimization levels 1-3, trading transpile time for circuit quality."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Transpile at different optimization levels\n",
|
|
"prep = build_preparation_circuit(\"h_p\", \"cx_chain\")\n",
|
|
"\n",
|
|
"fig, axes = plt.subplots(1, 3, figsize=(18, 4))\n",
|
|
"stats = {}\n",
|
|
"for i, opt in enumerate([1, 2, 3]):\n",
|
|
" opt_spec = spec.with_updates(optimization_level=opt)\n",
|
|
" t_circ = transpile_circuits([prep], opt_spec, backend)[0]\n",
|
|
" twoq = count_two_qubit_gates(t_circ)\n",
|
|
" d = t_circ.depth()\n",
|
|
" stats[opt] = {\"2q_gates\": twoq, \"depth\": d, \"size\": t_circ.size()}\n",
|
|
" print(f\"opt_level={opt}: 2Q gates={twoq}, depth={d}, total gates={t_circ.size()}\")\n",
|
|
" t_circ.draw(\"mpl\", ax=axes[i], style=\"iqp\")\n",
|
|
" axes[i].set_title(f\"Optimization Level {opt}\")\n",
|
|
"\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"predict_choice(tracker, \"q3_opt_levels\",\n",
|
|
" question=\"Higher transpilation optimization levels reduce gate count. Is this always better?\",\n",
|
|
" options=[\n",
|
|
" \"Yes \\u2014 fewer gates always means less noise\",\n",
|
|
" \"Not necessarily \\u2014 aggressive optimization may reroute qubits in ways that increase cross-talk\",\n",
|
|
" \"No \\u2014 lower optimization is always more reliable\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"3. Transpilation\", bloom=\"analyze\",\n",
|
|
" explanation=\"Optimization involves trade-offs. Reducing gates helps, but qubit routing decisions can place operations on noisier connections.\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Numerical Exercise: Cost Calculation\n",
|
|
"\n",
|
|
"Using the transpilation stats printed above, compute the two-qubit gate contribution to cost.\n",
|
|
"\n",
|
|
"The cost weight for two-qubit gates is \\\\(w_{2q} = 0.08\\\\). If opt_level=1 has, say, \\\\(n\\\\) two-qubit gates, the contribution is \\\\(0.08 \\\\times n\\\\)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Key Insight:** Higher optimization levels generally reduce gate count and depth, but the effect is non-monotonic \u2014 it depends on the specific circuit and backend topology. Each two-qubit gate is ~10x noisier than a single-qubit gate, so fewer = better.\n",
|
|
"\n",
|
|
"---\n",
|
|
"## 4. The Cost Model\n",
|
|
"\n",
|
|
"The scoring formula penalizes circuit cost:\n",
|
|
"\n",
|
|
"$$\\text{cost} = \\text{base} + w_{2q} \\cdot n_{2q} + w_d \\cdot d + w_s \\cdot s + w_r \\cdot r + w_q \\cdot q$$\n",
|
|
"\n",
|
|
"| Symbol | Meaning | Typical weight |\n",
|
|
"|---|---|---|\n",
|
|
"| $n_{2q}$ | Two-qubit gate count | 0.08 |\n",
|
|
"| $d$ | Circuit depth | 0.01 |\n",
|
|
"| $s$ | Total shot count | 0.0002 |\n",
|
|
"| $r$ | Runtime estimate | 0.015 |\n",
|
|
"| $q$ | Queue cost proxy | 0.30 |"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"quiz(tracker, \"q4_cost_driver\",\n",
|
|
" question=\"What is the dominant cost driver for most quantum circuits?\",\n",
|
|
" options=[\n",
|
|
" \"Single-qubit gate count\",\n",
|
|
" \"Two-qubit (CX/CZ) gate count \\u2014 these are 10-100x noisier than single-qubit gates\",\n",
|
|
" \"Classical post-processing time\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"4. Cost model\", bloom=\"apply\",\n",
|
|
" explanation=\"Two-qubit gates have error rates 10-100x higher than single-qubit gates on current hardware. Minimizing 2Q count is the primary optimization target.\")\n",
|
|
"checkpoint_summary(tracker, \"4. Cost model\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Compute cost for each optimization level\n",
|
|
"rung_config = load_rung_config(\"../../configs/rungs/rung1.yaml\")\n",
|
|
"cw = rung_config.score.cost_weights\n",
|
|
"\n",
|
|
"for opt, s in stats.items():\n",
|
|
" cost = (rung_config.score.base_cost\n",
|
|
" + cw.two_qubit_count * s[\"2q_gates\"]\n",
|
|
" + cw.depth * s[\"depth\"]\n",
|
|
" + cw.shot_count * 512\n",
|
|
" + cw.runtime_estimate * (s[\"depth\"] + 3 * s[\"2q_gates\"]))\n",
|
|
" print(f\"opt_level={opt}: cost = {cost:.3f} (2q contrib = {cw.two_qubit_count * s['2q_gates']:.3f}, depth contrib = {cw.depth * s['depth']:.3f})\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 5. Acceptance Rate Under Noise\n",
|
|
"\n",
|
|
"Postselection keeps only shots where stabilizer syndrome = 0. Under noise, many shots fail."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"quiz(tracker, \"q5_acceptance_meaning\",\n",
|
|
" question=\"Acceptance rate of 60% means:\",\n",
|
|
" options=[\n",
|
|
" \"60% of the circuit gates succeeded\",\n",
|
|
" \"60% of shots passed the stabilizer check \\u2014 40% had detectable errors\",\n",
|
|
" \"The state has 60% fidelity\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"5. Acceptance\", bloom=\"apply\",\n",
|
|
" explanation=\"40% of shots triggered a syndrome flag and were discarded. You need ~1.7x the shots to get the same number of clean data points.\")\n",
|
|
"checkpoint_summary(tracker, \"5. Acceptance\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Run full evaluation at different noise levels (via optimization levels as proxy)\n",
|
|
"rung_config = load_rung_config(\"../../configs/rungs/rung1.yaml\")\n",
|
|
"executor = LocalCheapExecutor()\n",
|
|
"\n",
|
|
"opt_results = {}\n",
|
|
"for opt in [1, 2, 3]:\n",
|
|
" s = ExperimentSpec(\n",
|
|
" rung=1, seed_style=\"h_p\", encoder_style=\"cx_chain\",\n",
|
|
" verification=\"both\", postselection=\"all_measured\",\n",
|
|
" target_backend=\"fake_brisbane\", noise_backend=\"fake_brisbane\",\n",
|
|
" optimization_level=opt, shots=256, repeats=1,\n",
|
|
" )\n",
|
|
" result = executor.evaluate(s, rung_config)\n",
|
|
" opt_results[opt] = result\n",
|
|
" m = result.metrics\n",
|
|
" print(f\"opt={opt}: acceptance={m.acceptance_rate:.3f} witness={m.logical_magic_witness:.3f} \"\n",
|
|
" f\"fidelity_noisy={m.noisy_encoded_fidelity:.3f} score={result.score:.4f}\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n",
|
|
"\n",
|
|
"labels = [f\"Level {o}\" for o in [1, 2, 3]]\n",
|
|
"\n",
|
|
"# Acceptance rate\n",
|
|
"axes[0].bar(labels, [opt_results[o].metrics.acceptance_rate for o in [1, 2, 3]],\n",
|
|
" color=[\"#e74c3c\", \"#2ecc71\", \"#3498db\"])\n",
|
|
"axes[0].set_title(\"Acceptance Rate\")\n",
|
|
"axes[0].set_ylim(0, 1)\n",
|
|
"\n",
|
|
"# Quality metrics\n",
|
|
"x = np.arange(3)\n",
|
|
"w = 0.25\n",
|
|
"axes[1].bar(x-w, [opt_results[o].metrics.logical_magic_witness for o in [1,2,3]], w, label=\"Witness\")\n",
|
|
"axes[1].bar(x, [opt_results[o].metrics.noisy_encoded_fidelity for o in [1,2,3]], w, label=\"Noisy Fid.\")\n",
|
|
"axes[1].bar(x+w, [opt_results[o].metrics.acceptance_rate for o in [1,2,3]], w, label=\"Accept.\")\n",
|
|
"axes[1].set_xticks(x)\n",
|
|
"axes[1].set_xticklabels(labels)\n",
|
|
"axes[1].set_title(\"Quality Metrics\")\n",
|
|
"axes[1].legend(fontsize=8)\n",
|
|
"\n",
|
|
"# Score\n",
|
|
"axes[2].bar(labels, [opt_results[o].score for o in [1, 2, 3]],\n",
|
|
" color=[\"#e74c3c\", \"#2ecc71\", \"#3498db\"])\n",
|
|
"axes[2].set_title(\"Final Score\")\n",
|
|
"\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Key Insight:** The \"best\" optimization level is not always the highest \u2014 it depends on how the backend's noise profile interacts with the transpiled circuit layout.\n",
|
|
"\n",
|
|
"---\n",
|
|
"## 6. Noisy Fidelity via Density Matrix\n",
|
|
"\n",
|
|
"State fidelity measures overlap between the noisy output and the ideal encoded T-state."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Noisy fidelity via density matrix on the LOGICAL (untranspiled) 4-qubit circuit.\n",
|
|
"# The transpiled circuit uses 127 qubits (full backend), making density matrix\n",
|
|
"# simulation infeasible (2^127 x 2^127 matrix). Instead we use the 4-qubit circuit\n",
|
|
"# with a simplified noise model.\n",
|
|
"\n",
|
|
"target = encoded_magic_statevector()\n",
|
|
"prep = build_preparation_circuit(\"h_p\", \"cx_chain\")\n",
|
|
"\n",
|
|
"from qiskit_aer.noise import NoiseModel as NM2, depolarizing_error\n",
|
|
"simple_noise = NM2()\n",
|
|
"simple_noise.add_all_qubit_quantum_error(depolarizing_error(0.001, 1), ['h', 'p', 'rz', 'ry', 'sx', 'x', 'u'])\n",
|
|
"simple_noise.add_all_qubit_quantum_error(depolarizing_error(0.01, 2), ['cx'])\n",
|
|
"\n",
|
|
"dm_circuit = prep.copy()\n",
|
|
"dm_circuit.save_density_matrix()\n",
|
|
"density_sim = AerSimulator(method=\"density_matrix\", noise_model=simple_noise)\n",
|
|
"dm_result = density_sim.run(dm_circuit).result()\n",
|
|
"noisy_dm = dm_result.data(0)[\"density_matrix\"]\n",
|
|
"\n",
|
|
"ideal_fid = state_fidelity(Statevector.from_instruction(prep), target)\n",
|
|
"noisy_fid = state_fidelity(noisy_dm, target)\n",
|
|
"\n",
|
|
"print(f\"Ideal fidelity: {ideal_fid:.6f}\")\n",
|
|
"print(f\"Noisy fidelity: {noisy_fid:.6f}\")\n",
|
|
"print(f\"Fidelity loss: {ideal_fid - noisy_fid:.6f}\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 7. Failure Mode Classification\n",
|
|
"\n",
|
|
"The harness classifies each experiment by its **dominant failure mode**:\n",
|
|
"\n",
|
|
"| Mode | Trigger | Meaning |\n",
|
|
"|---|---|---|\n",
|
|
"| postselection collapse | acceptance < 0.45 | Too many errors detected |\n",
|
|
"| logical witness erosion | witness < 0.65 | Magic property severely degraded |\n",
|
|
"| noise sensitivity | stability < 0.75 | Results vary wildly between repeats |\n",
|
|
"| transpile cost explosion | 2q > 60 or depth > 120 | Circuit too expensive |"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"order(tracker, \"q6_failure_severity\",\n",
|
|
" instruction=\"Rank failure modes from least to most severe:\",\n",
|
|
" items=[\"high_cost\", \"poor_acceptance\", \"low_magic_witness\"],\n",
|
|
" correct_order=[\"high_cost\", \"poor_acceptance\", \"low_magic_witness\"],\n",
|
|
" section=\"7. Failure modes\", bloom=\"analyze\",\n",
|
|
" explanation=\"High cost is fixable (optimize gates). Poor acceptance wastes shots. Low witness means the T-state character is lost \\u2014 the experiment's purpose has failed.\")\n",
|
|
"checkpoint_summary(tracker, \"7. Failure modes\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"for opt in [1, 2, 3]:\n",
|
|
" m = opt_results[opt].metrics\n",
|
|
" print(f\"opt={opt}: {m.dominant_failure_mode:30s} \"\n",
|
|
" f\"(accept={m.acceptance_rate:.2f}, witness={m.logical_magic_witness:.2f}, \"\n",
|
|
" f\"stability={m.stability_score:.2f}, 2q={m.two_qubit_count}, depth={m.depth})\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 8. The Full Scoring Formula\n",
|
|
"\n",
|
|
"$$\\text{score} = \\frac{\\text{quality} \\times \\text{acceptance\\_rate}}{\\text{cost}}$$\n",
|
|
"\n",
|
|
"Quality is a weighted average of metrics. The rung1 config weights noisy fidelity highest (0.40), followed by logical witness (0.25)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"reflect(tracker, \"q7_score_manual\",\n",
|
|
" question=\"You see the score computed manually from quality, acceptance, and cost. Which component dominates and why?\",\n",
|
|
" section=\"8. Scoring\", bloom=\"evaluate\",\n",
|
|
" model_answer=\"It depends on the noise regime. At low noise: cost dominates (quality and acceptance are both near 1). At high noise: acceptance dominates (many shots rejected). The score formula surfaces whichever factor is the bottleneck.\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Manual computation for the best optimization level\n",
|
|
"best_opt = max(opt_results, key=lambda o: opt_results[o].score)\n",
|
|
"m = opt_results[best_opt].metrics\n",
|
|
"sc = rung_config.score\n",
|
|
"w = sc.cheap_quality\n",
|
|
"\n",
|
|
"components = [\n",
|
|
" (\"ideal_fidelity\", w.ideal_fidelity, m.ideal_encoded_fidelity),\n",
|
|
" (\"noisy_fidelity\", w.noisy_fidelity, m.noisy_encoded_fidelity),\n",
|
|
" (\"logical_witness\", w.logical_witness, m.logical_magic_witness),\n",
|
|
" (\"codespace_rate\", w.codespace_rate, m.codespace_rate),\n",
|
|
" (\"stability_score\", w.stability_score, m.stability_score),\n",
|
|
" (\"spectator_alignment\", w.spectator_alignment,\n",
|
|
" (1 + m.spectator_logical_z) / 2 if m.spectator_logical_z is not None else None),\n",
|
|
"]\n",
|
|
"\n",
|
|
"print(f\"Quality components (opt_level={best_opt}):\")\n",
|
|
"print(f\"{'Component':25s} {'Weight':>8s} {'Value':>8s} {'Contribution':>14s}\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"total_w = 0\n",
|
|
"total_wv = 0\n",
|
|
"for name, weight, value in components:\n",
|
|
" if weight > 0 and value is not None:\n",
|
|
" total_w += weight\n",
|
|
" total_wv += weight * value\n",
|
|
" print(f\"{name:25s} {weight:8.2f} {value:8.4f} {weight * value:14.4f}\")\n",
|
|
"\n",
|
|
"quality = total_wv / total_w if total_w else 0\n",
|
|
"print(f\"\\nQuality = {total_wv:.4f} / {total_w:.2f} = {quality:.4f}\")\n",
|
|
"print(f\"Acceptance = {m.acceptance_rate:.4f}\")\n",
|
|
"print(f\"Cost = {m.total_cost:.4f}\")\n",
|
|
"print(f\"Score = {quality:.4f} * {m.acceptance_rate:.4f} / {m.total_cost:.4f} = {quality * m.acceptance_rate / max(m.total_cost, 1e-9):.6f}\")\n",
|
|
"print(f\"Library score: {opt_results[best_opt].score:.6f}\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Key Insight:** The score creates a three-way tension: (1) Better quality requires more complex circuits. (2) Stricter postselection improves quality but wastes shots. (3) More shots improve statistics but increase cost. The optimal configuration balances all three.\n",
|
|
"\n",
|
|
"---\n",
|
|
"## 9. Factory Throughput: An Alternative Score\n",
|
|
"\n",
|
|
"The factory throughput scorer optimizes for *yield* \u2014 accepted magic states per unit cost:\n",
|
|
"\n",
|
|
"$$\\text{throughput} = \\frac{\\text{acceptance} \\times W}{\\text{cost}}$$"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"quiz(tracker, \"q8_factory_vs_wac\",\n",
|
|
" question=\"Two scorers rank experiments differently. What determines which to use?\",\n",
|
|
" options=[\n",
|
|
" \"Always use WAC \\u2014 it's the default\",\n",
|
|
" \"Your operational goal: quality per state (WAC) vs production rate (factory throughput)\",\n",
|
|
" \"Use factory throughput only on real hardware\",\n",
|
|
" ],\n",
|
|
" correct=1, section=\"9. Factory throughput\", bloom=\"evaluate\",\n",
|
|
" explanation=\"The choice of scorer encodes your priorities. WAC optimizes per-state quality. Factory throughput optimizes for a T-state production pipeline.\")\n",
|
|
"checkpoint_summary(tracker, \"9. Factory throughput\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {},
|
|
"source": [
|
|
"factory_config = ScoreConfig(\n",
|
|
" name=\"factory_throughput\",\n",
|
|
" cheap_quality=QualityWeights(\n",
|
|
" noisy_fidelity=0.3, logical_witness=0.4,\n",
|
|
" codespace_rate=0.2, stability_score=0.1,\n",
|
|
" ),\n",
|
|
")\n",
|
|
"\n",
|
|
"print(f\"{'opt':>5s} {'WAC Score':>12s} {'Factory Score':>14s} {'WAC Rank':>10s} {'Fac Rank':>10s}\")\n",
|
|
"wac_scores = {}\n",
|
|
"fac_scores = {}\n",
|
|
"for opt in [1, 2, 3]:\n",
|
|
" m = opt_results[opt].metrics\n",
|
|
" m.extra = {}\n",
|
|
" s_wac = opt_results[opt].score\n",
|
|
" s_ft, _, _ = factory_throughput_score(m, \"cheap\", factory_config)\n",
|
|
" wac_scores[opt] = s_wac\n",
|
|
" fac_scores[opt] = s_ft\n",
|
|
"\n",
|
|
"wac_rank = sorted(wac_scores, key=wac_scores.get, reverse=True)\n",
|
|
"fac_rank = sorted(fac_scores, key=fac_scores.get, reverse=True)\n",
|
|
"for opt in [1, 2, 3]:\n",
|
|
" print(f\"{opt:>5d} {wac_scores[opt]:>12.4f} {fac_scores[opt]:>14.4f} \"\n",
|
|
" f\"{'#' + str(wac_rank.index(opt)+1):>10s} {'#' + str(fac_rank.index(opt)+1):>10s}\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": null
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Observe:** The two scorers may rank configurations differently. Factory throughput penalizes circuit cost more heavily, favoring simpler circuits even if quality is slightly lower.\n",
|
|
"\n",
|
|
"---\n",
|
|
"## Summary\n",
|
|
"\n",
|
|
"| Concept | What you learned |\n",
|
|
"|---|---|\n",
|
|
"| **Noise model** | Each gate has a probability of error; readout is imperfect |\n",
|
|
"| **Transpilation** | Maps logical circuits to physical hardware; higher optimization can reduce gates |\n",
|
|
"| **Acceptance rate** | Fraction of shots surviving postselection; drops under noise |\n",
|
|
"| **Cost model** | Penalizes 2Q gates, depth, shots, runtime |\n",
|
|
"| **Failure modes** | Four categories classify the dominant weakness |\n",
|
|
"| **Score** | quality x acceptance / cost \u2014 the single optimization target |\n",
|
|
"\n",
|
|
"> **Next:** Track A covers the physics in depth. Track C shows how the ratchet automates parameter search.\n",
|
|
"\n",
|
|
"> **Dashboard Exercise:** Go to `00_dashboard.ipynb`. Try every combination of verification mode and optimization level. Can you find the configuration with the highest score?"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## Final 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": "565da346",
|
|
"source": "---\n## Navigation \u2014 Plan C\n\n**\u2192 Next: [Track C \u2014 Search](track_c_search.ipynb)**\n\n*\u2190 Previous: [Track A \u2014 Physics](track_a_physics.ipynb) \u00b7 [Dashboard](00_dashboard.ipynb) \u00b7 [Start Here](../00_START_HERE.ipynb)*",
|
|
"metadata": {}
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.14.2"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
} |