{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Autoresearch Quantum \u2014 Control Room\n", "\n", "This interactive dashboard lets you run encoded magic-state experiments with different parameter settings\n", "and instantly visualize the results. Use it alongside the three Track notebooks:\n", "\n", "- **Track A** (Physics): `track_a_physics.ipynb`\n", "- **Track B** (Engineering): `track_b_engineering.ipynb`\n", "- **Track C** (Search): `track_c_search.ipynb`\n", "\n", "Each track will suggest \"Dashboard Exercises\" that bring you back here for hands-on exploration." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "import tempfile\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", "from IPython.display import display, clear_output, HTML\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 (\n", " ExperimentSpec, RungConfig, EvaluationMetrics, TierResult,\n", " QualityWeights, CostWeights, ScoreConfig, SearchSpaceConfig,\n", " TierPolicyConfig, HardwareConfig,\n", ")\n", "from autoresearch_quantum.execution.local import LocalCheapExecutor\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, runtime_estimate, circuit_metadata,\n", ")\n", "from autoresearch_quantum.scoring.score import score_metrics\n", "from autoresearch_quantum.config import load_rung_config\n", "\n", "print(\"All imports successful.\")" ] }, { "cell_type": "code", "metadata": {}, "source": [ "from autoresearch_quantum.teaching import LearningTracker\n", "from autoresearch_quantum.teaching.assess import quiz, predict_choice, reflect, checkpoint_summary\n", "tracker = LearningTracker(\"plan_c_dashboard\")\n", "print(\"Learning tracker active.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup: Load Base Configuration\n", "\n", "We load the rung-1 configuration as a baseline. The dashboard widgets will override individual parameters." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Load rung-1 config as our baseline\n", "rung_config = load_rung_config(\"../../configs/rungs/rung1.yaml\")\n", "executor = LocalCheapExecutor()\n", "\n", "# Storage for comparison runs\n", "run_history = []\n", "\n", "print(f\"Loaded config: {rung_config.name}\")\n", "print(f\"Objective: {rung_config.objective}\")" ] }, { "cell_type": "code", "metadata": {}, "source": [ "quiz(tracker, \"q1_baseline\",\n", " question=\"Why does the dashboard start from a rung-1 config as baseline?\",\n", " options=[\n", " \"It is the only config that exists\",\n", " \"It provides sensible defaults that widgets then override one at a time\",\n", " \"Higher rungs require IBM hardware access\",\n", " ],\n", " correct=1, section=\"1. Setup\", bloom=\"understand\",\n", " explanation=\"The rung-1 config defines the full parameter space and bootstrap incumbent. Widgets let you explore variations.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive Dashboard\n", "\n", "Adjust the widgets below and click **Run Experiment** to execute a single experiment with the chosen\n", "parameters. Click **Compare** to overlay a second run on the same plots (in orange) for side-by-side\n", "comparison.\n", "\n", "**Tip**: Try changing `seed_style` among `h_p`, `ry_rz`, `u_magic` \u2014 the witness should stay roughly\n", "the same (they are equivalent preparations up to global phase)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now run three experiments using the dashboard above:\n", "1. Set seed_style to `h_p`, click **Run Experiment**\n", "2. Change to `ry_rz`, click **Compare**\n", "3. Change to `u_magic`, click **Compare**\n", "\n", "Look at the \"Quality Metrics\" panel. Record what you see, then verify your prediction below." ] }, { "cell_type": "code", "metadata": {}, "source": [ "predict_choice(tracker, \"q2_verification_effect\",\n", " question=\"What happens to acceptance rate if you set verification to 'none'?\",\n", " options=[\n", " \"Acceptance rate drops because there are no checks\",\n", " \"Acceptance rate goes to 100% because no shots are filtered\",\n", " \"No change \\u2014 verification doesn't affect acceptance\",\n", " ],\n", " correct=1, section=\"2. Exploration\", bloom=\"apply\",\n", " explanation=\"With verification='none', there are no syndrome checks, so ALL shots are accepted (100%). But quality may be lower.\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": {}, "source": [ "reflect(tracker, \"q3_tradeoff\",\n", " question=\"After trying several parameter combinations, what tension do you notice between quality and acceptance?\",\n", " section=\"2. Exploration\", bloom=\"analyze\",\n", " model_answer=\"Stricter verification improves quality by filtering errors, but reduces acceptance rate. The score balances this: score = quality \\u00d7 acceptance / cost.\")\n", "checkpoint_summary(tracker, \"2. Exploration\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# \u2500\u2500 Widget definitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", "w_seed = widgets.Dropdown(\n", " options=[\"h_p\", \"ry_rz\", \"u_magic\"],\n", " value=\"h_p\",\n", " description=\"Seed style:\",\n", ")\n", "w_encoder = widgets.Dropdown(\n", " options=[\"cx_chain\", \"cz_compiled\"],\n", " value=\"cx_chain\",\n", " description=\"Encoder:\",\n", ")\n", "w_verification = widgets.Dropdown(\n", " options=[\"both\", \"z_only\", \"x_only\", \"none\"],\n", " value=\"both\",\n", " description=\"Verification:\",\n", ")\n", "w_postselection = widgets.Dropdown(\n", " options=[\"all_measured\", \"z_only\", \"x_only\", \"none\"],\n", " value=\"all_measured\",\n", " description=\"Postselect:\",\n", ")\n", "w_opt_level = widgets.IntSlider(\n", " value=2, min=1, max=3, step=1,\n", " description=\"Opt level:\",\n", ")\n", "w_shots = widgets.IntSlider(\n", " value=256, min=64, max=1024, step=64,\n", " description=\"Shots:\",\n", ")\n", "w_backend = widgets.Dropdown(\n", " options=[\"fake_brisbane\"],\n", " value=\"fake_brisbane\",\n", " description=\"Backend:\",\n", ")\n", "\n", "btn_run = widgets.Button(description=\"Run Experiment\", button_style=\"primary\")\n", "btn_compare = widgets.Button(description=\"Compare\", button_style=\"warning\")\n", "btn_clear = widgets.Button(description=\"Clear History\", button_style=\"danger\")\n", "\n", "out = widgets.Output()\n", "out_text = widgets.Output()\n", "\n", "\n", "def _build_spec():\n", " \"\"\"Build an ExperimentSpec from the current widget values.\"\"\"\n", " return ExperimentSpec(\n", " rung=1,\n", " seed_style=w_seed.value,\n", " encoder_style=w_encoder.value,\n", " verification=w_verification.value,\n", " postselection=w_postselection.value,\n", " ancilla_strategy=\"dedicated_pair\",\n", " optimization_level=w_opt_level.value,\n", " layout_method=\"sabre\",\n", " routing_method=\"sabre\",\n", " approximation_degree=1.0,\n", " target_backend=w_backend.value,\n", " noise_backend=w_backend.value,\n", " shots=w_shots.value,\n", " repeats=1,\n", " )\n", "\n", "\n", "def _run_and_collect():\n", " \"\"\"Run experiment, return (spec, tier_result, prep_circuit, bundle).\"\"\"\n", " spec = _build_spec()\n", " result = executor.evaluate(spec, rung_config)\n", " bundle = build_circuit_bundle(spec)\n", " backend = resolve_backend(spec.target_backend, rung_config.hardware)\n", " transpiled = transpile_circuits([bundle.acceptance], spec, backend)[0]\n", " return spec, result, bundle.prep, transpiled\n", "\n", "\n", "def _label(spec):\n", " return f\"{spec.seed_style}/{spec.encoder_style}/opt{spec.optimization_level}\"\n", "\n", "\n", "def _plot_all(clear=True):\n", " \"\"\"Draw the 2x2 dashboard from run_history.\"\"\"\n", " with out:\n", " if clear:\n", " clear_output(wait=True)\n", "\n", " if not run_history:\n", " print(\"No runs yet. Click 'Run Experiment'.\")\n", " return\n", "\n", " colors = plt.cm.tab10.colors\n", " fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n", " fig.suptitle(\"Autoresearch Quantum \u2014 Control Room\", fontsize=14, fontweight=\"bold\")\n", "\n", " # \u2500\u2500 Top-left: Circuit diagram (latest run only) \u2500\u2500\n", " ax_circ = axes[0, 0]\n", " ax_circ.set_axis_off()\n", " latest_prep = run_history[-1][2]\n", " latest_label = _label(run_history[-1][0])\n", " ax_circ.set_title(f\"Preparation Circuit ({latest_label})\", fontsize=11)\n", " # Draw circuit as text\n", " circ_text = latest_prep.draw(output=\"text\").__str__()\n", " ax_circ.text(\n", " 0.02, 0.95, circ_text,\n", " transform=ax_circ.transAxes, fontsize=7, verticalalignment=\"top\",\n", " fontfamily=\"monospace\",\n", " bbox=dict(boxstyle=\"round\", facecolor=\"#f0f0f0\", alpha=0.8),\n", " )\n", "\n", " # \u2500\u2500 Top-right: Histogram of acceptance counts \u2500\u2500\n", " ax_hist = axes[0, 1]\n", " ax_hist.set_title(\"Measurement Outcome Counts (acceptance circuit)\", fontsize=11)\n", " bar_width = 0.8 / max(len(run_history), 1)\n", " for i, (spec, result, _, _) in enumerate(run_history):\n", " counts = result.counts_summary.get(\"acceptance\", {}).get(\"latest\", {})\n", " raw = counts.get(\"raw_data_counts\", {})\n", " if raw:\n", " keys = sorted(raw.keys())\n", " vals = [raw[k] for k in keys]\n", " x = np.arange(len(keys))\n", " ax_hist.bar(\n", " x + i * bar_width, vals, bar_width,\n", " label=_label(spec), color=colors[i % len(colors)], alpha=0.8,\n", " )\n", " if i == len(run_history) - 1:\n", " ax_hist.set_xticks(x + bar_width * (len(run_history) - 1) / 2)\n", " ax_hist.set_xticklabels(keys, rotation=90, fontsize=6)\n", " ax_hist.set_ylabel(\"Counts\")\n", " ax_hist.legend(fontsize=8)\n", "\n", " # \u2500\u2500 Bottom-left: Quality metrics bar chart \u2500\u2500\n", " ax_metrics = axes[1, 0]\n", " ax_metrics.set_title(\"Quality Metrics\", fontsize=11)\n", " metric_names = [\"acceptance_rate\", \"witness\", \"score\"]\n", " x = np.arange(len(metric_names))\n", " bar_w = 0.8 / max(len(run_history), 1)\n", " for i, (spec, result, _, _) in enumerate(run_history):\n", " m = result.metrics\n", " vals = [\n", " m.acceptance_rate,\n", " m.logical_magic_witness or 0.0,\n", " result.score,\n", " ]\n", " ax_metrics.barh(\n", " x + i * bar_w, vals, bar_w,\n", " label=_label(spec), color=colors[i % len(colors)], alpha=0.8,\n", " )\n", " ax_metrics.set_yticks(x + bar_w * (len(run_history) - 1) / 2)\n", " ax_metrics.set_yticklabels(metric_names)\n", " ax_metrics.set_xlim(0, 1.0)\n", " ax_metrics.legend(fontsize=8)\n", "\n", " # \u2500\u2500 Bottom-right: Transpile cost stats \u2500\u2500\n", " ax_cost = axes[1, 1]\n", " ax_cost.set_title(\"Transpile & Cost Stats\", fontsize=11)\n", " cost_names = [\"2Q gates\", \"depth\", \"total_cost\"]\n", " x = np.arange(len(cost_names))\n", " bar_w = 0.8 / max(len(run_history), 1)\n", " for i, (spec, result, _, _) in enumerate(run_history):\n", " m = result.metrics\n", " vals = [m.two_qubit_count, m.depth, m.total_cost]\n", " ax_cost.bar(\n", " x + i * bar_w, vals, bar_w,\n", " label=_label(spec), color=colors[i % len(colors)], alpha=0.8,\n", " )\n", " ax_cost.set_xticks(x + bar_w * (len(run_history) - 1) / 2)\n", " ax_cost.set_xticklabels(cost_names)\n", " ax_cost.legend(fontsize=8)\n", "\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "\n", "def _print_summary():\n", " \"\"\"Print textual summary of the latest run.\"\"\"\n", " with out_text:\n", " clear_output(wait=True)\n", " if not run_history:\n", " return\n", " spec, result, _, _ = run_history[-1]\n", " m = result.metrics\n", " print(\"=\" * 60)\n", " print(f\" Run #{len(run_history)}: {_label(spec)}\")\n", " print(\"=\" * 60)\n", " print(f\" Score: {result.score:.4f}\")\n", " print(f\" Quality estimate: {result.quality_estimate:.4f}\")\n", " print(f\" Acceptance rate: {m.acceptance_rate:.4f}\")\n", " print(f\" Magic witness: {m.logical_magic_witness:.4f}\" if m.logical_magic_witness else \" Magic witness: N/A\")\n", " print(f\" Ideal fidelity: {m.ideal_encoded_fidelity:.4f}\" if m.ideal_encoded_fidelity else \" Ideal fidelity: N/A\")\n", " print(f\" Noisy fidelity: {m.noisy_encoded_fidelity:.4f}\" if m.noisy_encoded_fidelity else \" Noisy fidelity: N/A\")\n", " print(f\" Spectator Z: {m.spectator_logical_z:.4f}\" if m.spectator_logical_z else \" Spectator Z: N/A\")\n", " print(f\" Stability score: {m.stability_score:.4f}\" if m.stability_score else \" Stability score: N/A\")\n", " print(f\" Two-qubit gates: {m.two_qubit_count}\")\n", " print(f\" Circuit depth: {m.depth}\")\n", " print(f\" Total cost: {m.total_cost:.4f}\")\n", " print(f\" Failure mode: {m.dominant_failure_mode}\")\n", " print(\"=\" * 60)\n", "\n", "\n", "def on_run(btn):\n", " \"\"\"Run a fresh experiment (replaces history).\"\"\"\n", " run_history.clear()\n", " spec, result, prep, transpiled = _run_and_collect()\n", " run_history.append((spec, result, prep, transpiled))\n", " _plot_all(clear=True)\n", " _print_summary()\n", "\n", "\n", "def on_compare(btn):\n", " \"\"\"Run experiment and overlay on existing plots.\"\"\"\n", " spec, result, prep, transpiled = _run_and_collect()\n", " run_history.append((spec, result, prep, transpiled))\n", " _plot_all(clear=True)\n", " _print_summary()\n", "\n", "\n", "def on_clear(btn):\n", " \"\"\"Clear all history.\"\"\"\n", " run_history.clear()\n", " with out:\n", " clear_output(wait=True)\n", " print(\"History cleared.\")\n", " with out_text:\n", " clear_output(wait=True)\n", "\n", "\n", "btn_run.on_click(on_run)\n", "btn_compare.on_click(on_compare)\n", "btn_clear.on_click(on_clear)\n", "\n", "# \u2500\u2500 Layout \u2500\u2500\n", "controls_left = widgets.VBox([w_seed, w_encoder, w_verification, w_postselection])\n", "controls_right = widgets.VBox([w_opt_level, w_shots, w_backend])\n", "buttons = widgets.HBox([btn_run, btn_compare, btn_clear])\n", "control_panel = widgets.HBox([controls_left, controls_right])\n", "\n", "display(widgets.VBox([\n", " widgets.HTML(\"