{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b1d74f02",
   "metadata": {
    "id": "b1d74f02"
   },
   "source": [
    "# Superfermion: full 4–24-qubit grid, five-step VQC/VQR, RAM and time\n",
    "\n",
    "The default `requested_grid` preset matches your revised scope:\n",
    "\n",
    "- **VQC/VQR:** 4/8/12 qubits, exactly **5 full-batch SPSA iterations**, depth 1.\n",
    "- **Other quantum experiments:** 4/8/12/16/20/24 qubits, including kernels,\n",
    "  QKPCA, feature selection, MaxCut, VQE, gradients, state/feature-map, batch and depth sweeps.\n",
    "- **All seven datasets:** full available rows in an **80% training / 20% testing** split.\n",
    "- Eight simulator lanes: published/source/modified Superfermion, Qiskit Aer,\n",
    "  PennyLane Lightning, qsim/Cirq f32, Cirq f64 and Qulacs; separate classical controls.\n",
    "\n",
    "The complete supported plan has **2,520 benchmark jobs**, one seed/repeat and\n",
    "one simulator thread. Wine has only 13 original features; feature selection at\n",
    "16/20/24 qubits uses those real features plus 3/7/11 ancillas. Ancillas are absent\n",
    "from the feature cost and downstream feature list. Their embedding is audited;\n",
    "they do not create new original features or dataset rows.\n",
    "\n",
    "Every exact experiment condition gets **three-panel scaling figures**:\n",
    "primary computation time, full worker elapsed time and peak resident RAM.\n",
    "Figures cover the requested qubit ticks and every applicable framework. CSVs,\n",
    "PNG/SVG figures, numerical audits, failure reasons and checkpoints are exported.\n",
    "Failed/pending measurements appear as gaps, never as zero or a claimed win.\n",
    "Small qubit bands run first, with framework order shuffled within groups.\n",
    "Time/RAM reports refresh between jobs about every 15 minutes, so partial graphs\n",
    "can be inspected/downloaded before an expensive section finishes.\n",
    "\n",
    "### Large-qubit execution\n",
    "\n",
    "A complex128 state at 24 qubits is 256 MiB. A full 569-row Breast Cancer bank\n",
    "would be **142.25 GiB**. Large kernels therefore use identical bounded re-encoding\n",
    "blocks across all simulators; this trades memory for more simulation time.\n",
    "State/gradient/readout batches are chunked. The exported-bank budget is 512 MiB,\n",
    "which is **not** a cap on total process RAM. VQE's exact open-chain Ising reference\n",
    "uses an n-by-n fermion matrix instead of an exponentially large dense spin matrix.\n",
    "\n",
    "This grid remains expensive on free Colab. Each job has a visible **600-second\n",
    "timeout**; a timed-out/OOM worker is recorded as a failure and the campaign can\n",
    "continue. Required preflight/core/numerical correctness gates still stop on error.\n",
    "Optional full project tests are off for this preset. No universal winner is assumed.\n",
    "\n",
    "### Execution status\n",
    "\n",
    "This notebook's full native-framework campaign has **not been run** here.\n",
    "The notebook structure/syntax, grid plan and small independent numerical helpers\n",
    "are checked locally. Run cells in order for measured graphs and results; a free\n",
    "Colab session may not finish the 20/24-qubit dataset kernels. Results use the new\n",
    "`studies/requested_grid_split80_20_grid24_v8` directory.\n",
    "\n",
    "\n",
    "### Live job progress\n",
    "\n",
    "Campaign cells now show one updating progress panel: finished/planned jobs,\n",
    "percentage complete, successful/failed/remaining counts, and a per-task table.\n",
    "Each job is one framework running one experiment configuration. Progress reads\n",
    "controller-confirmed worker results and section checkpoints, including accepted\n",
    "cached successes. It refreshes every `PROGRESS_REFRESH_SECONDS=5` seconds.\n",
    "Percentages count finished jobs, including failures; they are not time estimates.\n",
    "Preparation, correctness checks and report rendering have no benchmark-job percentage.\n",
    "Logs and original error details remain available. The scientific scripts, settings,\n",
    "manifest generation and cache fingerprints are unchanged by this display update.\n",
    "\n",
    "For an existing notebook, run the separately supplied progress-cell code after\n",
    "setup and before the next campaign cell. It leaves your selected profile and\n",
    "saved results intact. Apply it while the notebook kernel is idle; a cell already\n",
    "executing the old helper continues to use that helper until it stops or finishes.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e87efb3",
   "metadata": {
    "id": "8e87efb3"
   },
   "source": [
    "## Context & Methods\n",
    "\n",
    "We ask two different questions: *How much does the Rust patch reduce an\n",
    "equivalent application's runtime?* and *Does each QML method produce useful\n",
    "predictions on the same held-out data?* Simulator speed alone does not\n",
    "establish quantum ML advantage. A win is measured; it is never required by\n",
    "editing results, choosing weaker baselines, or dropping failed jobs.\n",
    "\n",
    "| Simulator lane | Actual CPU backend | Arithmetic | Repeated execution |\n",
    "|---|---|---|---|\n",
    "| SF published | Superfermion 0.1.14 PyPI wheel | complex128 | Existing bind → IR → simulate |\n",
    "| SF source | Unchanged pinned Git source | complex128 | Same existing path, same Rust toolchain as the patch |\n",
    "| SF modified | Pinned source + embedded patch | complex128 | Prepared circuit, native batch/readouts |\n",
    "| Qiskit | Aer statevector | complex128 | Runtime parameter binding batches |\n",
    "| PennyLane | lightning.qubit | complex128 | QNode broadcasting; Lightning expands tapes |\n",
    "| Cirq/qsim | QSimSimulator | complex64 internally | Parameter sweep |\n",
    "| Cirq f64 | Cirq Simulator | complex128 | Parameter sweep |\n",
    "| Qulacs | CPU parametric statevector simulator | complex128 | Reuse circuit/state; update parameters |\n",
    "\n",
    "### Key assumptions\n",
    "\n",
    "* Every compared circuit has identical logical gates and angle values.\n",
    "  Canonical vector index bit `q` represents qubit `q`. An asymmetric\n",
    "  `X(q0)` case catches endian mistakes; Qulacs rotation signs are converted.\n",
    "* All simulator lanes receive the same thread **budget**, and BLAS uses one\n",
    "  thread. A backend can choose to use less than its budget at small sizes.\n",
    "  No worker runs concurrently with another timed worker.\n",
    "* A **statevector track** returns a complex128 bank and applies a shared\n",
    "  NumPy reduction. qsim's output cast does not change its f32 arithmetic.\n",
    "  A **native-readout track** computes the equivalent scalar through each\n",
    "  backend's observable API, avoiding state export where supported.\n",
    "* Primary runtime includes parameter binding, simulation, required output\n",
    "  conversion, and the named application stage. It excludes installation,\n",
    "  imports, dataset preprocessing, circuit preparation, warmup and independent\n",
    "  reference audits. Shared exported-state norm reductions are included in\n",
    "  circuit and kernel primary timings.\n",
    "  `circuit_prepare_s` includes the first backend import in a fresh worker.\n",
    "* Kernel primary time is **encoding + fidelity matrix algebra**. Classical\n",
    "  fitting/eigendecomposition and end-to-end time are recorded separately.\n",
    "  VQC/VQR primary time includes the full matched optimizer workload; test\n",
    "  inference is separate. Optimization solution diagnostics are outside\n",
    "  native training time for every lane.\n",
    "* Circuit/gradient microbenchmarks use a within-process median, then report\n",
    "  median/IQR across fresh processes. QML/optimization runs perform one\n",
    "  matched workload per fresh process. IQR is descriptive, **not** a CI.\n",
    "* Exact statevector simulation uses \\(O(2^n)\\) amplitudes. No MPS,\n",
    "  stabilizer shortcut, GPU, noise, sampling, or hardware execution is\n",
    "  mixed into the general simulator ranking."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46884dba",
   "metadata": {
    "id": "46884dba"
   },
   "source": [
    "### What is changed in Superfermion\n",
    "\n",
    "The patch is the same verified library change used in the earlier notebook.\n",
    "It is applied to commit `35f8f7c306ac2a004e6b10dee37317d87918d5dc`.\n",
    "Both source lanes build with Rust 1.90.0 and identical release/CPU flags;\n",
    "the source baseline isolates the patch's effect from wheel build choices.\n",
    "\n",
    "| Change | Why it can help | What this notebook checks |\n",
    "|---|---|---|\n",
    "| Immutable prepared circuit | Reuse topology, fixed gates and operation order | Changing parameters still changes states correctly |\n",
    "| Native batched state export | Reduce Python/DAG work and export copies | Native batch APIs are enabled for competing backends too |\n",
    "| Mean-Z / cached diagonal readout | Avoid statevector/probability export and repeated scans | Scalar agrees with independent full states |\n",
    "| Bitmask Pauli expectations | Reduce observable traversal overhead | Mixed X/Y/Z agrees with dense matrices |\n",
    "| GIL release / optional device exports | Reduce wrapper work and allow native execution | Compiled unit tests preserve existing defaults |\n",
    "| Exact Angle fidelity kernel | Avoid simulation for one restricted map | Kept separate from general simulator rankings |\n",
    "\n",
    "Parameter-dependent matrices/fusion are **rebuilt for each parameter row**;\n",
    "a prepared circuit does not reuse stale numerical results. Measurement,\n",
    "reset and conditioned circuits are rejected by the prepared API. State\n",
    "batches are limited to 1 GiB by the patch; this notebook uses a tighter guard.\n",
    "\n",
    "Keep the Rust core while measuring these changes. A whole-library C++ or\n",
    "assembly rewrite does not remove repeated wrapper work or exponential\n",
    "memory growth. Use the measured losses against Qulacs/Aer/Lightning to choose\n",
    "the next kernel, fusion, SIMD or allocation optimization. Optional Torch/JAX\n",
    "integration changes in the patch are not benchmarked by this notebook."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "642385ce",
   "metadata": {
    "id": "642385ce"
   },
   "source": [
    "### Experiment matrix\n",
    "\n",
    "| Family | Experiments and outputs |\n",
    "|---|---|\n",
    "| Classification | QSVM on all five classification datasets; binary and three-class labels; accuracy, balanced accuracy, macro-F1 and binary AUROC |\n",
    "| Regression | Fidelity-kernel ridge regression on Diabetes/Friedman1; VQR on Diabetes/Friedman1; RMSE, MAE and R² in original target units |\n",
    "| Representation | QKPCA fit on training data only; out-of-sample centering and a logistic head; spectrum and held-out quality |\n",
    "| Variational QML | VQC binary logistic / multiclass one-vs-rest circuits, matched SPSA seeds, full training-loss traces and inference time |\n",
    "| Combinatorial optimization | QAOA feature selection, weighted ring and Erdős–Rényi MaxCut; expected energy, exact optimum gap and optimum probability |\n",
    "| Physics | VQE on the open transverse-field Ising chain; mixed Pauli expectations and exact open-chain ground energy |\n",
    "| Differentiation | Matched parameter-shift gradients checked against independent finite differences; state-export and scalar tracks |\n",
    "| Simulator scaling | GHZ, decomposed QFT on a nontrivial input, and random entangling circuits; qubits, depth, batch size and process memory |\n",
    "| Feature-map sensitivity | Angle, Phase, Pauli and ZZ maps, all with identical gate specifications across backends |\n",
    "| Classical controls | RBF SVC, logistic regression, random forest; ridge, RBF kernel ridge, random forest regression; full-feature classification control |\n",
    "\n",
    "The validation profile covers all of these families. Its short optimizer\n",
    "budget tests execution and agreement, not model convergence. All profiles use\n",
    "full 80/20 datasets; presets vary qubits, split seeds, repeats and training budgets. CSV inputs can be added through `CUSTOM_DATASETS`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "279b0789",
   "metadata": {
    "id": "279b0789"
   },
   "source": [
    "### 1. Configure the requested grids\n",
    "\n",
    "| Experiment | Qubits | Update budget |\n",
    "|---|---|---|\n",
    "| VQC / VQR | 4, 8, 12 | **5 full-batch SPSA iterations**, depth 1 |\n",
    "| QSVM / QKRR / QKPCA | 4, 8, 12, 16, 20, 24 | Kernel computation / classical fit |\n",
    "| QAOA feature selection / MaxCut / VQE | 4, 8, 12, 16, 20, 24 | 5 iterations inherited from the free preset; separately configurable |\n",
    "| Parameter-shift gradients | 4, 8, 12, 16, 20, 24 | Same shifted-circuit algorithm and independent finite-difference audit |\n",
    "| State, feature-map, batch, depth sweeps | 4, 8, 12, 16, 20, 24 | 1 warmup + 3 inner repetitions |\n",
    "| Classical controls | All six projected input sizes | Matched full-data split |\n",
    "\n",
    "All seven bundled datasets use their complete **80/20 split**. Classification is\n",
    "stratified; all preprocessing/feature selection is trained only on training rows.\n",
    "Each VQC/VQR SPSA update uses every row in the 80% training partition; the 20%\n",
    "test partition is held out for final evaluation. Five iterations means five\n",
    "parameter updates, with an initial and five updated full-training-loss points.\n",
    "Zero padding above available PCA components adds no new information. Wine feature\n",
    "selection above 13 qubits embeds its 13-variable problem with idle-cost ancillas;\n",
    "cardinality is based on real variables, and ancillary bits are not selected features.\n",
    "\n",
    "`QUANTUM_QUBITS`, `VQC_VQR_QUBITS` and `VQC_VQR_ITERATIONS` are separate settings.\n",
    "`VQC_VQR_FULL_BATCH=True` implements full-training-partition updates.\n",
    "The default plan has **2,520 jobs**; `MAX_JOBS=4000` allows this requested grid.\n",
    "`MAX_STATEBANK_MIB=512` permits two 24-qubit output states for bounded kernel tiles.\n",
    "It does not include backend workspaces, probabilities, diagonal observables or\n",
    "independent references. Kernel block caps and logical/actual bank estimates are\n",
    "visible in `statebank_budget.csv`; no full dataset is subsampled to fit RAM.\n",
    "\n",
    "Large kernels recompute states instead of keeping a 142 GiB bank or writing it\n",
    "to disk. Timings describe this bounded algorithm, not an in-memory-bank benchmark.\n",
    "All simulator lanes share the same strategy at a given qubit/dataset condition.\n",
    "Native readouts still simulate a state internally; GPU acceleration is not enabled.\n",
    "The exact VQE reference applies specifically to the open TFIM Hamiltonian used here.\n",
    "\n",
    "`timeout_s=600` is a per-worker limit, not a completion-time estimate. Increase it\n",
    "only if you intend to spend longer per job. Failures remain in coverage tables and\n",
    "figures; paired speedups require every simulator in the matched group to succeed.\n",
    "Independent smoke/reference checks use 4/8/12 qubits, and every higher-qubit result\n",
    "has its job-level norm/full-vector or observable audit. The numerical gates are not bypassed.\n",
    "Change configuration before preparing data/manifest/validation; rerun those cells\n",
    "after any change. Export/download checkpoints before the Colab runtime is deleted.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "40e94544",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "40e94544",
    "outputId": "6f54b5c8-1c61-4824-fb48-725bc8a964e2"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"profile\": \"requested_grid\",\n",
      "  \"datasets\": [\n",
      "    \"breast_cancer\",\n",
      "    \"iris\",\n",
      "    \"wine\",\n",
      "    \"digits_01\",\n",
      "    \"moons\",\n",
      "    \"diabetes\",\n",
      "    \"friedman1\"\n",
      "  ],\n",
      "  \"train_ratio\": 0.8,\n",
      "  \"test_ratio\": 0.2,\n",
      "  \"dataset_rows\": \"all available; no sample caps\",\n",
      "  \"fresh_process_repetitions\": 1,\n",
      "  \"split_seeds\": [\n",
      "    42\n",
      "  ],\n",
      "  \"qml_qubits\": [\n",
      "    4,\n",
      "    8,\n",
      "    12,\n",
      "    16,\n",
      "    20\n",
      "  ],\n",
      "  \"vqc_vqr_qubits\": [\n",
      "    4,\n",
      "    8,\n",
      "    12\n",
      "  ],\n",
      "  \"vqc_vqr_iterations\": 5,\n",
      "  \"statevector_qubits\": [\n",
      "    4,\n",
      "    8,\n",
      "    12,\n",
      "    16,\n",
      "    20\n",
      "  ],\n",
      "  \"simulator_thread_budgets\": [\n",
      "    1\n",
      "  ],\n",
      "  \"frameworks\": [\n",
      "    \"superfermion_wheel\",\n",
      "    \"superfermion_source_baseline\",\n",
      "    \"superfermion_optimized\",\n",
      "    \"qiskit\",\n",
      "    \"pennylane\",\n",
      "    \"cirq\",\n",
      "    \"cirq_f64\",\n",
      "    \"qulacs\"\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "import base64, csv, hashlib, html, json, os, platform, shutil, subprocess, sys, time, urllib.request, venv, zlib\n",
    "\n",
    "RUN_PROFILE = os.environ.get(\"SUPERFERMION_STUDY_PROFILE\", \"requested_grid\")\n",
    "TRAIN_RATIO = 0.80\n",
    "TEST_RATIO = 0.20\n",
    "THREADS = [16]                 # Desktop run: 16 simulator threads per quantum lane (multi-threaded dataset).\n",
    "MAX_JOBS = 4000                 # Requested grid: 2,520 benchmark jobs.\n",
    "ALLOW_LARGE_RUN = True         # Authorizes the requested six-qubit-size grid.\n",
    "MAX_STATEBANK_MIB = 512         # Output bank limit, not a total process-RSS limit.\n",
    "RUN_FULL_PROJECT_TESTS = RUN_PROFILE not in (\"colab_free\",\"requested_grid\")  # Optional full suites; core/unit/correctness checks always run.\n",
    "CUSTOM_DATASETS = {}            # e.g. {\"my_data\": {\"path\":\"/content/data.csv\", \"target\":\"label\", \"kind\":\"classification\"}}\n",
    "\n",
    "CLASSIFICATION = [\"breast_cancer\", \"iris\", \"wine\", \"digits_01\", \"moons\"]\n",
    "REGRESSION = [\"diabetes\", \"friedman1\"]\n",
    "if not (0 < TRAIN_RATIO < 1 and 0 < TEST_RATIO < 1\n",
    "        and abs(TRAIN_RATIO + TEST_RATIO - 1.0) < 1e-12):\n",
    "    raise ValueError(\"Train and test ratios must be positive and sum to 1.\")\n",
    "COMMON = dict(classification_datasets=CLASSIFICATION, regression_datasets=REGRESSION,\n",
    "    train_ratio=TRAIN_RATIO, test_ratio=TEST_RATIO,\n",
    "    kernel_maps=[\"angle\", \"zz\"], warmups=2, inner_repetitions=3, timeout_s=1800,\n",
    "    qaoa_depth=1, map_batch=16, batch_qubits=8, batch_sizes=[1,8,32], circuit_depths=[1,4,8])\n",
    "QUANTUM_QUBITS = [4,8,12,16,20]\n",
    "VQC_VQR_QUBITS = [4,8,12]\n",
    "VQC_VQR_ITERATIONS = 5\n",
    "VQC_VQR_FULL_BATCH = True  # Every update uses all rows in the training partition.\n",
    "OTHER_OPTIMIZER_ITERATIONS = 5  # Retains the preceding free preset's budget for QAOA/MaxCut/VQE.\n",
    "SHOW_ALL_EXPERIMENT_FIGURES = True\n",
    "PROFILES = {\n",
    "    \"requested_grid\": dict(COMMON, seeds=[42], repetitions=1,\n",
    "        qml_qubits=QUANTUM_QUBITS, variational_qubits=VQC_VQR_QUBITS,\n",
    "        variational_iterations=VQC_VQR_ITERATIONS, variational_full_batch=VQC_VQR_FULL_BATCH,\n",
    "        iterations=OTHER_OPTIMIZER_ITERATIONS,\n",
    "        optimization_iterations=OTHER_OPTIMIZER_ITERATIONS,\n",
    "        validation_qubits=[4,8,12], state_qubits=QUANTUM_QUBITS,\n",
    "        map_qubits=QUANTUM_QUBITS, sweep_qubits=QUANTUM_QUBITS,\n",
    "        qkpca_datasets=CLASSIFICATION, vqc_datasets=CLASSIFICATION, vqr_datasets=REGRESSION,\n",
    "        feature_selection_datasets=[\"breast_cancer\",\"wine\"], feature_selection_ancillas=True, variational_depths=[1],\n",
    "        training_batch=6, vqe_qubits=QUANTUM_QUBITS, gradient_qubits=QUANTUM_QUBITS,\n",
    "        warmups=1, inner_repetitions=3, qaoa_depth=1, map_batch=8,\n",
    "        batch_sizes=[1,8], circuit_depths=[1,4], kernel_block_rows=128, timeout_s=1200),\n",
    "    \"colab_free\": dict(COMMON, classification_datasets=[\"breast_cancer\",\"iris\"],\n",
    "        regression_datasets=[\"friedman1\"], seeds=[42], repetitions=1,\n",
    "        qml_qubits=[4,8], validation_qubits=[4,8], state_qubits=[4,8,12], map_qubits=[4,8],\n",
    "        qkpca_datasets=[\"iris\"], vqc_datasets=[\"iris\"], vqr_datasets=[\"friedman1\"],\n",
    "        feature_selection_datasets=[\"breast_cancer\"], variational_depths=[1],\n",
    "        iterations=5, training_batch=6, vqe_qubits=[4], gradient_qubits=[4],\n",
    "        warmups=1, inner_repetitions=3, qaoa_depth=1, map_batch=8,\n",
    "        batch_sizes=[1,8], circuit_depths=[1,4], timeout_s=600),\n",
    "    \"validation\": dict(COMMON, seeds=[42], repetitions=2,\n",
    "        qml_qubits=[4], validation_qubits=[4,8], state_qubits=[4,8,12], map_qubits=[8],\n",
    "        qkpca_datasets=[\"breast_cancer\",\"iris\"], vqc_datasets=[\"breast_cancer\",\"iris\"],\n",
    "        vqr_datasets=[\"friedman1\"], feature_selection_datasets=[\"breast_cancer\"],\n",
    "        variational_depths=[1], iterations=3, training_batch=6, vqe_qubits=[4], gradient_qubits=[4]),\n",
    "    \"study\": dict(COMMON, seeds=[42,7,123], repetitions=3,\n",
    "        qml_qubits=[4,8], validation_qubits=[4,8], state_qubits=[4,8,12,16], map_qubits=[4,8,12],\n",
    "        qkpca_datasets=CLASSIFICATION, vqc_datasets=[\"breast_cancer\",\"iris\",\"moons\"],\n",
    "        vqr_datasets=REGRESSION, feature_selection_datasets=[\"breast_cancer\",\"wine\"],\n",
    "        variational_depths=[1,2], iterations=20, training_batch=16, vqe_qubits=[4,6], gradient_qubits=[4,8],\n",
    "        warmups=3, inner_repetitions=7, qaoa_depth=2),\n",
    "    \"paper\": dict(COMMON, seeds=[42], repetitions=1,\n",
    "        qml_qubits=[4,8,12], validation_qubits=[4,8,12], state_qubits=[4,8,12,16,20], map_qubits=[4,8,12,16,20],\n",
    "        qkpca_datasets=CLASSIFICATION, vqc_datasets=CLASSIFICATION, vqr_datasets=REGRESSION,\n",
    "        feature_selection_datasets=[\"breast_cancer\",\"wine\"], variational_depths=[1,2,3],\n",
    "        iterations=80, training_batch=24, vqe_qubits=[4,6,10], gradient_qubits=[4,8,12],\n",
    "        warmups=4, inner_repetitions=9, qaoa_depth=2, timeout_s=7200, batch_sizes=[1,8,32,64]),\n",
    "}\n",
    "if RUN_PROFILE not in PROFILES: raise ValueError(\"Unknown RUN_PROFILE\")\n",
    "PROFILE = json.loads(json.dumps(PROFILES[RUN_PROFILE]))\n",
    "for name, spec in CUSTOM_DATASETS.items():\n",
    "    PROFILE[spec[\"kind\"] + \"_datasets\"].append(name)\n",
    "if sys.version_info < (3,11): raise RuntimeError(\"Use a Python 3.11+ Colab runtime for these pinned dependencies\")\n",
    "assert all(1 <= n <= (os.cpu_count() or 1) for n in THREADS)\n",
    "default_root = Path(\"/content/superfermion_extended\") if Path(\"/content\").exists() else Path.cwd()/\"superfermion_extended\"\n",
    "ROOT = Path(os.environ.get(\"SUPERFERMION_BUILD_ROOT\", str(default_root))).resolve()\n",
    "EXPERIMENT_ROOT = ROOT/\"studies\"/(RUN_PROFILE+\"_split80_20_grid24_v8\")\n",
    "ROOT.mkdir(parents=True, exist_ok=True); EXPERIMENT_ROOT.mkdir(parents=True, exist_ok=True)\n",
    "(ROOT/\"tmp\").mkdir(exist_ok=True); (ROOT/\"pip_cache\").mkdir(exist_ok=True)\n",
    "os.environ[\"TMPDIR\"] = os.environ[\"TMP\"] = os.environ[\"TEMP\"] = str(ROOT/\"tmp\")\n",
    "os.environ[\"PIP_CACHE_DIR\"] = str(ROOT/\"pip_cache\")\n",
    "os.environ[\"MPLCONFIGDIR\"] = str(ROOT/\"matplotlib-cache\")\n",
    "Path(os.environ[\"MPLCONFIGDIR\"]).mkdir(exist_ok=True)\n",
    "FRAMEWORKS = [\"superfermion_wheel\",\"superfermion_source_baseline\",\"superfermion_optimized\",\n",
    "              \"qiskit\",\"pennylane\",\"cirq\",\"cirq_f64\",\"qulacs\"]\n",
    "CONF = dict(root=str(EXPERIMENT_ROOT), build_root=str(ROOT), profile_name=RUN_PROFILE, profile=PROFILE,\n",
    "    threads=THREADS, frameworks=FRAMEWORKS, custom_datasets=CUSTOM_DATASETS,\n",
    "    max_jobs=MAX_JOBS, max_statebank_bytes=MAX_STATEBANK_MIB*2**20, fail_fast=False,\n",
    "    kernel_row_caps=PROFILE.get(\"kernel_row_caps\",{}),\n",
    "    order_qubits_first=True, report_refresh_seconds=900)\n",
    "print(json.dumps({\"profile\":RUN_PROFILE,\"datasets\":PROFILE[\"classification_datasets\"]+PROFILE[\"regression_datasets\"],\n",
    "    \"train_ratio\":PROFILE[\"train_ratio\"],\"test_ratio\":PROFILE[\"test_ratio\"],\n",
    "    \"dataset_rows\":\"all available; no sample caps\",\n",
    "    \"fresh_process_repetitions\":PROFILE[\"repetitions\"],\"split_seeds\":PROFILE[\"seeds\"],\n",
    "    \"qml_qubits\":PROFILE[\"qml_qubits\"],\"vqc_vqr_qubits\":PROFILE.get(\"variational_qubits\",PROFILE[\"qml_qubits\"]),\n",
    "    \"vqc_vqr_iterations\":PROFILE.get(\"variational_iterations\",PROFILE[\"iterations\"]),\"statevector_qubits\":PROFILE[\"state_qubits\"],\n",
    "    \"simulator_thread_budgets\":THREADS,\"frameworks\":FRAMEWORKS},indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "abfe4b0a",
   "metadata": {
    "id": "abfe4b0a"
   },
   "source": [
    "### 2. Install isolated, pinned dependencies\n",
    "\n",
    "Workers use their own Python environment. This avoids conflicts with packages\n",
    "preloaded in the Colab kernel. Timing never includes installation or imports.\n",
    "A log is retained for each setup/build/test action, and progress appears\n",
    "during long builds. Qulacs is a real installed compiled baseline, not a\n",
    "placeholder or NumPy fallback. Any required install/import failure stops\n",
    "the notebook.\n",
    "\n",
    "The entire tested dependency set is embedded in `requirements.lock.txt`, rather\n",
    "than only top-level framework pins. `venv_colab_fix_v2` is separate from the\n",
    "previous environment. The dependency resolver and `pip check` must both pass;\n",
    "individual package versions are then checked against the lock."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ff686563",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 220
    },
    "id": "ff686563",
    "outputId": "013fafd3-f428-4ccc-bf71-48f9f77aa51c"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"font-family:system-ui,sans-serif;max-width:1100px;border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\"><div style=\"font-size:18px;font-weight:650\">Dependency Integrity</div><div style=\"color:#475569;margin:5px 0 12px\">Finished · Elapsed 00:00:00</div><div>This preparation/check/report command has no benchmark-job denominator.</div><div style=\"font-size:12px;color:#475569;margin-top:8px\">Detailed log: dependency_integrity.log</div></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished dependency_integrity in 0.6 seconds\n",
      "Full dependency lock verified: 72 packages\n",
      "Workers use /content/superfermion_extended/venv_colab_fix_v2/bin/python\n"
     ]
    }
   ],
   "source": [
    "LOGS = EXPERIMENT_ROOT/\"logs\"; LOGS.mkdir(exist_ok=True)\n",
    "\n",
    "\"\"\"Paste/run this cell after notebook setup and before the next campaign cell.\n",
    "\n",
    "Displays completed job counts and task percentages from existing checkpoints.\n",
    "It does not edit the experiment scripts, manifest, configuration or results.\n",
    "\"\"\"\n",
    "from pathlib import Path as _SFPath\n",
    "import csv as _sf_csv\n",
    "import html as _sf_html\n",
    "import json as _sf_json\n",
    "import math as _sf_math\n",
    "import os as _sf_os\n",
    "import re as _sf_re\n",
    "import signal as _sf_signal\n",
    "import subprocess as _sf_subprocess\n",
    "import time as _sf_time\n",
    "\n",
    "try:\n",
    "    from IPython.display import HTML as _SFHTML, display as _sf_display, clear_output as _sf_clear_output\n",
    "except ImportError:\n",
    "    _SFHTML = None\n",
    "    _sf_display = None\n",
    "    _sf_clear_output = None\n",
    "\n",
    "PROGRESS_REFRESH_SECONDS = 5.0\n",
    "\n",
    "\n",
    "def _sf_duration(seconds):\n",
    "    seconds = max(0, int(seconds))\n",
    "    return f\"{seconds//3600:02d}:{seconds%3600//60:02d}:{seconds%60:02d}\"\n",
    "\n",
    "\n",
    "class _SFJobProgress:\n",
    "    def __init__(self, command, log_path, start_ns, cwd=None):\n",
    "        self.log_path = _SFPath(log_path)\n",
    "        self.start_ns = start_ns\n",
    "        self.root = None\n",
    "        self.manifest = None\n",
    "        self.tasks = None\n",
    "        self.task_order = []\n",
    "        self.snapshot_path = None\n",
    "        self.task_totals = {}\n",
    "        self.total = None\n",
    "        self.rows = {}\n",
    "        self.seen_files = {}\n",
    "        self.log_position = 0\n",
    "        self.log_partial = \"\"\n",
    "        self.reported_finished = 0\n",
    "        parts = [str(part) for part in command]\n",
    "        driver = next((i for i, part in enumerate(parts)\n",
    "                       if _SFPath(part).name == \"study_driver.py\"), None)\n",
    "        if driver is None or len(parts) <= driver+2 or parts[driver+2] != \"run\":\n",
    "            return\n",
    "        if len(parts) > driver+3:\n",
    "            self.task_order = parts[driver+3].split(\",\")\n",
    "            self.tasks = set(self.task_order)\n",
    "        try:\n",
    "            config_path = _SFPath(parts[driver+1])\n",
    "            if not config_path.is_absolute():\n",
    "                config_path = (_SFPath(cwd) if cwd else _SFPath.cwd())/config_path\n",
    "            config = _sf_json.loads(config_path.read_text())\n",
    "            self.root = _SFPath(config[\"root\"])\n",
    "            self.manifest = config.get(\"manifest_sha256\")\n",
    "            section = \"_\".join(self.task_order) if self.task_order else \"all\"\n",
    "            self.snapshot_path = self.root/f\"results_{section}.json\"\n",
    "            with (self.root/\"planned_jobs.csv\").open(newline=\"\") as stream:\n",
    "                for row in _sf_csv.DictReader(stream):\n",
    "                    task = row[\"task\"]\n",
    "                    if self.tasks is None or task in self.tasks:\n",
    "                        self.task_totals[task] = sum(int(float(value or 0))\n",
    "                            for field, value in row.items() if field != \"task\")\n",
    "            self.total = sum(self.task_totals.values())\n",
    "        except (OSError, ValueError, KeyError, TypeError):\n",
    "            # The driver's actual announced total remains available even if\n",
    "            # a preview CSV has not been generated in an older notebook.\n",
    "            pass\n",
    "\n",
    "    @property\n",
    "    def is_campaign(self):\n",
    "        return self.root is not None\n",
    "\n",
    "    def _read_log(self):\n",
    "        try:\n",
    "            with self.log_path.open(errors=\"replace\") as stream:\n",
    "                stream.seek(self.log_position)\n",
    "                text = self.log_partial+stream.read()\n",
    "                self.log_position = stream.tell()\n",
    "        except OSError:\n",
    "            return\n",
    "        lines = text.split(\"\\n\")\n",
    "        self.log_partial = lines.pop()\n",
    "        for line in lines:\n",
    "            announced = _sf_re.match(r\"Executing (\\d+) jobs\\b\", line)\n",
    "            if announced:\n",
    "                self.total = int(announced.group(1))\n",
    "            finished = _sf_re.match(r\"(\\d+)/(\\d+):\\s\", line)\n",
    "            if finished:\n",
    "                self.reported_finished = max(self.reported_finished, int(finished.group(1)))\n",
    "                self.total = int(finished.group(2))\n",
    "\n",
    "    def _accept(self, row, require_exit=False):\n",
    "        if not isinstance(row, dict) or row.get(\"status\") not in {\"ok\", \"error\"}:\n",
    "            return\n",
    "        if not self.manifest or row.get(\"manifest_sha256\") != self.manifest:\n",
    "            return\n",
    "        if row.get(\"task\") in {\"validation\", \"preflight\"}:\n",
    "            return\n",
    "        if self.tasks is not None and row.get(\"task\") not in self.tasks:\n",
    "            return\n",
    "        if require_exit and \"worker_returncode\" not in row:\n",
    "            return  # The controller has not yet confirmed the worker's exit.\n",
    "        job_id = row.get(\"job_id\") or row.get(\"cache_key\")\n",
    "        if not job_id:\n",
    "            return\n",
    "        self.rows[job_id] = row\n",
    "\n",
    "    def _read_json(self, path, require_current_run=True):\n",
    "        try:\n",
    "            stat = path.stat()\n",
    "            signature = (stat.st_mtime_ns, stat.st_size)\n",
    "            if require_current_run and stat.st_mtime_ns < self.start_ns:\n",
    "                return None\n",
    "            if self.seen_files.get(str(path)) == signature:\n",
    "                return None\n",
    "            value = _sf_json.loads(path.read_text())\n",
    "            self.seen_files[str(path)] = signature\n",
    "            return value\n",
    "        except (OSError, ValueError):\n",
    "            return None  # A checkpoint may be between write and completion.\n",
    "\n",
    "    def update(self):\n",
    "        self._read_log()\n",
    "        if not self.is_campaign:\n",
    "            return\n",
    "        if self.snapshot_path is not None:\n",
    "            value = self._read_json(self.snapshot_path)\n",
    "            if isinstance(value, list):\n",
    "                for row in value:\n",
    "                    self._accept(row)\n",
    "        raw = self.root/\"raw\"\n",
    "        if raw.is_dir():\n",
    "            for path in raw.glob(\"*.json\"):\n",
    "                if path.name.endswith(\".config.json\"):\n",
    "                    continue\n",
    "                value = self._read_json(path)\n",
    "                if value is not None:\n",
    "                    self._accept(value, require_exit=True)\n",
    "\n",
    "    def counts(self):\n",
    "        successful = sum(row[\"status\"] == \"ok\" for row in self.rows.values())\n",
    "        failed = sum(row[\"status\"] == \"error\" for row in self.rows.values())\n",
    "        finished = max(len(self.rows), self.reported_finished)\n",
    "        return dict(total=self.total, finished=finished, successful=successful,\n",
    "                    failed=failed, unknown_outcomes=finished-successful-failed)\n",
    "\n",
    "    def task_counts(self):\n",
    "        totals_valid = bool(self.task_totals) and sum(self.task_totals.values()) == self.total\n",
    "        names = sorted(set(self.task_totals) | {row[\"task\"] for row in self.rows.values()})\n",
    "        result = []\n",
    "        for name in names:\n",
    "            rows = [row for row in self.rows.values() if row[\"task\"] == name]\n",
    "            total = self.task_totals.get(name) if totals_valid else None\n",
    "            result.append(dict(task=name, total=total, finished=len(rows),\n",
    "                successful=sum(row[\"status\"] == \"ok\" for row in rows),\n",
    "                failed=sum(row[\"status\"] == \"error\" for row in rows)))\n",
    "        return result\n",
    "\n",
    "    @staticmethod\n",
    "    def _percent(finished, total):\n",
    "        return f\"{100*finished/total:.1f}%\" if total and finished <= total else \"—\"\n",
    "\n",
    "    def text(self, name, phase):\n",
    "        c = self.counts()\n",
    "        if not self.is_campaign:\n",
    "            return f\"{name}: {phase}; detailed output: {self.log_path.name}\"\n",
    "        total = c[\"total\"] if c[\"total\"] is not None else \"?\"\n",
    "        return (f\"{name}: {c['finished']}/{total} jobs finished \"\n",
    "                f\"({self._percent(c['finished'],c['total'])}); \"\n",
    "                f\"{c['successful']} successful, {c['failed']} failed; {phase}\")\n",
    "\n",
    "    def html(self, name, phase, elapsed):\n",
    "        escape = _sf_html.escape\n",
    "        title = escape(str(name).replace(\"_\", \" \").title())\n",
    "        parts = [f'<div style=\"font-family:system-ui,sans-serif;max-width:1100px;'\n",
    "                 f'border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\">'\n",
    "                 f'<div style=\"font-size:18px;font-weight:650\">{title}</div>'\n",
    "                 f'<div style=\"color:#475569;margin:5px 0 12px\">'\n",
    "                 f'{escape(phase)} · Elapsed {_sf_duration(elapsed)}</div>']\n",
    "        if self.is_campaign:\n",
    "            c = self.counts()\n",
    "            total = c[\"total\"] if c[\"total\"] is not None else \"?\"\n",
    "            percentage = self._percent(c[\"finished\"],c[\"total\"])\n",
    "            parts.append(f'<div style=\"font-size:20px\"><b>{c[\"finished\"]:,} / '\n",
    "                         f'{total:,} jobs finished · {percentage}</b></div>' if isinstance(total,int)\n",
    "                         else f'<div><b>{c[\"finished\"]} / ? jobs finished</b></div>')\n",
    "            if c[\"total\"] and c[\"finished\"] <= c[\"total\"]:\n",
    "                value = 100*c[\"finished\"]/c[\"total\"]\n",
    "                parts.append(f'<progress aria-label=\"Finished jobs\" value=\"{value}\" '\n",
    "                             'max=\"100\" style=\"width:100%;height:20px;margin:8px 0\"></progress>')\n",
    "            remaining = max(0,c[\"total\"]-c[\"finished\"]) if c[\"total\"] is not None else \"?\"\n",
    "            parts.append(f'<div style=\"margin:4px 0 12px\">'\n",
    "                         f'<b>Successful:</b> {c[\"successful\"]:,} '\n",
    "                         f'({self._percent(c[\"successful\"],c[\"total\"])}) · '\n",
    "                         f'<b>Failed:</b> {c[\"failed\"]:,} · <b>Remaining:</b> {remaining}</div>')\n",
    "            if c[\"unknown_outcomes\"]:\n",
    "                parts.append(f'<div>{c[\"unknown_outcomes\"]} finished-job outcomes are '\n",
    "                             'awaiting a readable checkpoint.</div>')\n",
    "            if c[\"total\"] is not None and c[\"finished\"]>c[\"total\"]:\n",
    "                parts.append('<div>Checkpoint counts exceed the announced plan; percentage withheld.</div>')\n",
    "            tasks = self.task_counts()\n",
    "            if tasks:\n",
    "                parts.append('<div style=\"overflow-x:auto\"><table style=\"border-collapse:collapse;'\n",
    "                             'width:100%;font-size:14px;text-align:left\"><thead><tr>')\n",
    "                for label in [\"Task\", \"Finished / planned\", \"Complete\", \"Successful\", \"Failed\", \"Remaining\"]:\n",
    "                    parts.append(f'<th style=\"padding:8px;border-bottom:2px solid #cbd5e1\">{label}</th>')\n",
    "                parts.append('</tr></thead><tbody>')\n",
    "                for row in tasks:\n",
    "                    total = row[\"total\"]\n",
    "                    remaining = max(0,total-row[\"finished\"]) if total is not None else \"?\"\n",
    "                    cells = [escape(row[\"task\"].upper()),\n",
    "                             f'{row[\"finished\"]} / {total if total is not None else \"?\"}',\n",
    "                             self._percent(row[\"finished\"],total),\n",
    "                             row[\"successful\"],row[\"failed\"],remaining]\n",
    "                    parts.append('<tr>'+''.join(f'<td style=\"padding:8px;border-bottom:1px solid #e2e8f0\">'\n",
    "                                               f'{value}</td>' for value in cells)+'</tr>')\n",
    "                parts.append('</tbody></table></div>')\n",
    "            parts.append('<div style=\"font-size:12px;color:#475569;margin-top:10px\">'\n",
    "                         'Percentages count finished jobs, including failures. They are not time estimates. '\n",
    "                         'Setup, correctness checks and report rendering are outside this campaign’s job total.</div>')\n",
    "        else:\n",
    "            parts.append('<div>This preparation/check/report command has no benchmark-job denominator.</div>')\n",
    "        parts.append(f'<div style=\"font-size:12px;color:#475569;margin-top:8px\">'\n",
    "                     f'Detailed log: {escape(self.log_path.name)}</div></div>')\n",
    "        return ''.join(parts)\n",
    "\n",
    "\n",
    "def _sf_stop_process(process):\n",
    "    if process.poll() is not None:\n",
    "        return\n",
    "    try:\n",
    "        if _sf_os.name == \"posix\":\n",
    "            _sf_os.killpg(process.pid, _sf_signal.SIGTERM)\n",
    "        else:\n",
    "            process.terminate()\n",
    "    except ProcessLookupError:\n",
    "        return\n",
    "    try:\n",
    "        process.wait(timeout=5)\n",
    "    except _sf_subprocess.TimeoutExpired:\n",
    "        if _sf_os.name == \"posix\":\n",
    "            try:\n",
    "                _sf_os.killpg(process.pid, _sf_signal.SIGKILL)\n",
    "            except ProcessLookupError:\n",
    "                pass\n",
    "        else:\n",
    "            process.kill()\n",
    "        process.wait()\n",
    "\n",
    "\n",
    "def run_logged(command, name, cwd=None, env=None, timeout=3600):\n",
    "    path = _SFPath(LOGS)/f\"{name}.log\"\n",
    "    path.parent.mkdir(parents=True, exist_ok=True)\n",
    "    print(f\"Starting {name}; detailed output: {path.name}\", flush=True)\n",
    "    start = _sf_time.monotonic()\n",
    "    tracker = _SFJobProgress(command, path, _sf_time.time_ns(), cwd)\n",
    "    worker_env = _sf_os.environ.copy() if env is None else dict(env)\n",
    "    worker_env[\"MPLBACKEND\"] = \"Agg\"\n",
    "    refresh = float(PROGRESS_REFRESH_SECONDS)\n",
    "    refresh = min(30., max(.2, refresh)) if _sf_math.isfinite(refresh) else 5.\n",
    "    last_text = None\n",
    "\n",
    "    def render(phase):\n",
    "        nonlocal last_text\n",
    "        tracker.update()\n",
    "        elapsed = _sf_time.monotonic()-start\n",
    "        counts = tracker.counts()\n",
    "        if phase==\"Running\" and tracker.is_campaign and counts[\"total\"] and counts[\"finished\"]==counts[\"total\"]:\n",
    "            phase = \"Jobs finished; waiting for the controller to exit\"\n",
    "        if _sf_display is not None:\n",
    "            markup = tracker.html(name, phase, elapsed)\n",
    "            item = _SFHTML(markup) if _SFHTML is not None else markup\n",
    "            try:\n",
    "                # clear_output works in Colab as well as classic Jupyter;\n",
    "                # it avoids depending on frontend display-id update support.\n",
    "                if _sf_clear_output is not None:\n",
    "                    _sf_clear_output(wait=True)\n",
    "                _sf_display(item)\n",
    "                return\n",
    "            except Exception:\n",
    "                pass  # Presentation cannot stop an otherwise valid benchmark.\n",
    "        text = tracker.text(name, phase)\n",
    "        if text != last_text:\n",
    "            print(text, flush=True)\n",
    "            last_text = text\n",
    "\n",
    "    with path.open(\"w\") as log:\n",
    "        process = _sf_subprocess.Popen([str(part) for part in command], cwd=cwd, env=worker_env,\n",
    "            stdout=log, stderr=_sf_subprocess.STDOUT, start_new_session=(_sf_os.name==\"posix\"))\n",
    "        try:\n",
    "            render(\"Running\")\n",
    "            while True:\n",
    "                remaining = float(timeout)-(_sf_time.monotonic()-start)\n",
    "                if remaining <= 0:\n",
    "                    _sf_stop_process(process)\n",
    "                    render(\"Stopped: command timeout\")\n",
    "                    raise RuntimeError(f\"{name} timed out; inspect {path}\")\n",
    "                try:\n",
    "                    status = process.wait(timeout=min(refresh,remaining))\n",
    "                    break\n",
    "                except _sf_subprocess.TimeoutExpired:\n",
    "                    render(\"Running\")\n",
    "        except BaseException:\n",
    "            _sf_stop_process(process)\n",
    "            render(\"Stopped; completed checkpoints retained\")\n",
    "            raise\n",
    "    render(\"Campaign finished\" if status==0 and tracker.is_campaign else\n",
    "           \"Finished\" if status==0 else \"Stopped with an error\")\n",
    "    if status:\n",
    "        print(path.read_text(errors=\"replace\")[-6000:])\n",
    "        if name in {\"backend_preflight\",\"independent_framework_checks\"}:\n",
    "            filename = \"backend_preflight_errors.json\" if name==\"backend_preflight\" else \"validation_errors.json\"\n",
    "            error_path = _SFPath(EXPERIMENT_ROOT)/filename\n",
    "            if error_path.exists():\n",
    "                errors = _sf_json.loads(error_path.read_text())\n",
    "                seen = set()\n",
    "                for error in errors:\n",
    "                    key = (error.get(\"framework\"),error.get(\"error\"))\n",
    "                    if key in seen:\n",
    "                        continue\n",
    "                    seen.add(key)\n",
    "                    print(\"\\nROOT ERROR:\",error.get(\"framework\"),error.get(\"n_qubits\"),\"qubits\")\n",
    "                    print(error.get(\"traceback\",error.get(\"log_tail\",error.get(\"error\",\"unknown\")))[-5000:])\n",
    "                    print(\"Worker log:\",error.get(\"worker_log\",\"unavailable\"))\n",
    "        raise RuntimeError(f\"{name} failed ({status}); full log: {path}\")\n",
    "    print(f\"Finished {name} in {_sf_time.monotonic()-start:.1f} seconds\", flush=True)\n",
    "    return path\n",
    "\n",
    "\n",
    "# Keep the existing Agg wrapper compatible when setup or this cell is rerun.\n",
    "_sf_run_logged_original = run_logged\n",
    "\n",
    "ENV_DIR = ROOT/\"venv\"  # Prebuilt environment on D:; reused, never rebuilt.\n",
    "PYTHON = str(ENV_DIR/(\"Scripts/python.exe\" if os.name==\"nt\" else \"bin/python\"))\n",
    "if not Path(PYTHON).exists():\n",
    "    venv.EnvBuilder(with_pip=False).create(ENV_DIR)\n",
    "# Full tested dependency lock, including SymPy/Autoray and native BLAS support.\n",
    "DEPENDENCIES = ['absl-py==2.5.0', 'appdirs==1.4.4', 'attrs==26.1.0', 'autograd==1.9.1', 'autoray==0.8.4', 'cachetools==7.2.0', 'certifi==2026.7.22', 'charset-normalizer==3.5.2', 'cirq-core==1.6.1', 'cloudpickle==3.1.2', 'contourpy==1.4.0', 'cycler==0.12.1', 'diastatic-malt==2.15.3', 'dill==0.4.1', 'duet==0.2.9', 'fastjsonschema==2.22.2', 'fonttools==4.66.1', 'gast==0.7.0', 'idna==3.20', 'iniconfig==2.3.0', 'joblib==1.6.0', 'jsonschema==4.26.0', 'jsonschema-specifications==2025.9.1', 'jupyter_core==5.9.1', 'kiwisolver==1.5.1', 'matplotlib==3.10.8', 'maturin==1.9.4', 'mpmath==1.3.0', 'nbformat==5.10.4', 'networkx==3.7', 'numpy==2.3.5', 'packaging==26.3', 'pandas==2.3.2', 'pennylane==0.45.0', 'pennylane_lightning==0.45.0', 'pillow==12.3.0', 'pip==25.2', 'platformdirs==4.12.2', 'pluggy==1.6.0', 'psutil==7.2.2', 'pybind11==3.1.0', 'pybind11-global==3.1.0', 'Pygments==2.21.0', 'pyparsing==3.3.3', 'pytest==8.4.2', 'pytest-timeout==2.4.0', 'python-dateutil==2.9.0.post0', 'pytz==2026.4', 'qiskit==2.1.2', 'qiskit-aer==0.17.2', 'qsimcirq==0.22.0', 'qulacs==0.6.14', 'referencing==0.37.0', 'requests==2.34.2', 'rpds-py==2026.6.3', 'rustworkx==0.18.1', 'scikit-learn==1.7.1', 'scipy==1.17.1', 'scipy-openblas32==0.3.34.237.0', 'setuptools==84.0.0', 'six==1.17.0', 'sortedcontainers==2.4.0', 'stevedore==5.9.1', 'sympy==1.14.0', 'termcolor==3.3.0', 'threadpoolctl==3.7.0', 'tomlkit==0.15.1', 'tqdm==4.67.1', 'traitlets==5.16.1', 'typing_extensions==4.16.0', 'tzdata==2026.4', 'urllib3==2.8.0']\n",
    "LOCK_PATH = EXPERIMENT_ROOT/\"requirements.lock.txt\"\n",
    "LOCK_PATH.write_text(\"\\n\".join(DEPENDENCIES)+\"\\n\")\n",
    "(EXPERIMENT_ROOT/\"requirements.txt\").write_text(LOCK_PATH.read_text())\n",
    "install_env = os.environ.copy()\n",
    "for key in [\"PYTHONPATH\",\"PYTHONHOME\",\"PYTHONSTARTUP\",\"PYTHONWARNINGS\"]:\n",
    "    install_env.pop(key,None)\n",
    "install_env[\"PYTHONNOUSERSITE\"] = \"1\"\n",
    "run_logged([sys.executable,\"-I\",\"-m\",\"pip\",\"--python\",PYTHON,\"install\",\n",
    "            \"--upgrade\",\"--requirement\",LOCK_PATH],\"dependencies\",env=install_env,timeout=2400)\n",
    "run_logged([PYTHON,\"-I\",\"-m\",\"pip\",\"check\"],\"dependency_integrity\",env=install_env,timeout=600)\n",
    "observed = json.loads(subprocess.check_output([PYTHON,\"-I\",\"-m\",\"pip\",\"list\",\"--format=json\"],env=install_env,text=True))\n",
    "normalized = lambda name:name.lower().replace(\"_\",\"-\").replace(\".\",\"-\")\n",
    "observed = {normalized(item[\"name\"]):item[\"version\"] for item in observed}\n",
    "for pin in DEPENDENCIES:\n",
    "    name,version=pin.split(\"==\",1)\n",
    "    if observed.get(normalized(name)) != version:\n",
    "        raise RuntimeError(f\"Dependency lock mismatch: {pin}\")\n",
    "print(\"Full dependency lock verified:\",len(DEPENDENCIES),\"packages\")\n",
    "CONF[\"python\"] = PYTHON\n",
    "print(\"Workers use\", PYTHON)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "baf90d21",
   "metadata": {
    "id": "baf90d21"
   },
   "source": [
    "### 3. Build with the same Rust toolchain and CPU flags\n",
    "\n",
    "Official Rust 1.90.0 component archives are checksum-verified. Standalone\n",
    "installation works in environments without `/proc/self/exe`; in that case\n",
    "both source lanes use the same system-linker override. Otherwise repository\n",
    "portable CPU flags apply. Separate Cargo target directories prevent one\n",
    "build from silently reusing the other build's native extension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "aa51d8c9",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "aa51d8c9",
    "outputId": "46012be0-e53c-4b31-9321-25d4cd3ae17d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cargo 1.90.0 (840b83a10 2025-07-30)\n"
     ]
    }
   ],
   "source": [
    "TOOLCHAIN = ROOT/\"toolchain\"; TOOLCHAIN.mkdir(exist_ok=True)\n",
    "BUILD_ENV = os.environ.copy()\n",
    "RUST_VERSION = \"1.90.0\"; RUST_HOST = \"x86_64-pc-windows-gnu\"\n",
    "RUSTUP_HOME = TOOLCHAIN/\"rustup\"; CARGO_HOME = TOOLCHAIN/\"cargo\"\n",
    "BUILD_ENV.update(RUSTUP_HOME=str(RUSTUP_HOME), CARGO_HOME=str(CARGO_HOME),\n",
    "                 CARGO_TARGET_DIR=str(ROOT/\"cargo_target\"/\"source_optimized\"), CARGO_BUILD_JOBS=\"2\",\n",
    "                 TMPDIR=str(ROOT/\"tmp\"), TMP=str(ROOT/\"tmp\"), TEMP=str(ROOT/\"tmp\"))\n",
    "MSYS_BIN = Path(\"C:/msys64/mingw64/bin\")\n",
    "if not (MSYS_BIN/\"gcc.exe\").exists():\n",
    "    raise RuntimeError(\"mingw-w64 gcc is required for the pinned x86_64-pc-windows-gnu Rust target; install MSYS2 mingw64 or adjust MSYS_BIN\")\n",
    "BUILD_ENV[\"PATH\"] = os.pathsep.join([str(CARGO_HOME/\"bin\"), str(MSYS_BIN), BUILD_ENV.get(\"PATH\", \"\")])\n",
    "for variable in [\"RUSTFLAGS\", \"CARGO_ENCODED_RUSTFLAGS\", \"CARGO_PROFILE_RELEASE_OPT_LEVEL\",\n",
    "                 \"CARGO_PROFILE_RELEASE_LTO\", \"CARGO_PROFILE_RELEASE_CODEGEN_UNITS\"]:\n",
    "    BUILD_ENV.pop(variable, None)\n",
    "machine = platform.machine()\n",
    "machine = {\"AMD64\": \"x86_64\", \"ARM64\": \"aarch64\"}.get(machine, machine.lower())\n",
    "if machine != \"x86_64\": raise RuntimeError(f\"unsupported architecture for the pinned Rust target: {machine}\")\n",
    "# Provision rustup and the pinned 1.90.0 GNU toolchain entirely inside the study\n",
    "# root on D:; nothing is written to the system drive. The repository .cargo\n",
    "# config declares flags only for linux/darwin/msvc hosts, so the documented\n",
    "# portable CPU baseline is applied explicitly for this host via RUSTFLAGS.\n",
    "rustup_exe = CARGO_HOME/\"bin\"/\"rustup.exe\"\n",
    "if not rustup_exe.exists():\n",
    "    source_rustup = shutil.which(\"rustup\")\n",
    "    if source_rustup:\n",
    "        bootstrap = TOOLCHAIN/\"rustup.exe\"\n",
    "        if not bootstrap.exists(): shutil.copy2(source_rustup, bootstrap)\n",
    "        # rustup refuses to finish \"toolchain install\" unless the rustup binary\n",
    "        # itself is present in CARGO_HOME/bin; the shims are rustup copies.\n",
    "        (CARGO_HOME/\"bin\").mkdir(parents=True, exist_ok=True)\n",
    "        for shim in [\"rustup.exe\", \"cargo.exe\", \"rustc.exe\"]:\n",
    "            target = CARGO_HOME/\"bin\"/shim\n",
    "            if not target.exists(): shutil.copy2(bootstrap, target)\n",
    "        run_logged([str(bootstrap), \"toolchain\", \"install\", f\"{RUST_VERSION}-{RUST_HOST}\", \"--profile\", \"minimal\"],\n",
    "                   \"rust_toolchain_install\", env=BUILD_ENV, timeout=2400)\n",
    "    else:\n",
    "        initializer = TOOLCHAIN/\"rustup-init.exe\"\n",
    "        if not initializer.exists():\n",
    "            run_logged([\"powershell\", \"-NoProfile\", \"-Command\",\n",
    "                        \"Invoke-WebRequest -UseBasicParsing -Uri 'https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-gnu/rustup-init.exe'\"\n",
    "                        f\" -OutFile '{initializer}'\"],\n",
    "                       \"download_rustup\", timeout=1200)\n",
    "        run_logged([str(initializer), \"-y\", \"--no-modify-path\", \"--default-host\", RUST_HOST,\n",
    "                    \"--default-toolchain\", f\"{RUST_VERSION}-{RUST_HOST}\", \"--profile\", \"minimal\"],\n",
    "                   \"rust_toolchain_install\", env=BUILD_ENV, timeout=2400)\n",
    "if not rustup_exe.exists(): raise RuntimeError(\"rustup provisioning failed; inspect rust_toolchain_install.log\")\n",
    "# pin the runner: a surprise rustup self-update mid-experiment can lock shims\n",
    "# (seen on Windows as a transient 'Access is denied' on first proxy use).\n",
    "run_logged([str(rustup_exe), \"set\", \"auto-self-update\", \"disable\"],\n",
    "           \"rustup_disable_self_update\", env=BUILD_ENV, timeout=120)\n",
    "BUILD_ENV[\"RUSTUP_TOOLCHAIN\"] = f\"{RUST_VERSION}-{RUST_HOST}\"\n",
    "BUILD_ENV[\"RUSTFLAGS\"] = \"-C target-cpu=x86-64-v2\"\n",
    "CARGO = str(CARGO_HOME/\"bin\"/\"cargo.exe\")\n",
    "print(subprocess.check_output([CARGO, \"--version\"], env=BUILD_ENV, text=True).strip())\n",
    "print(subprocess.check_output([str(CARGO_HOME/\"bin\"/\"rustc.exe\"), \"--version\"], env=BUILD_ENV, text=True).strip())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b60e107",
   "metadata": {
    "id": "5b60e107"
   },
   "source": [
    "### 4. Materialize and verify the library patch\n",
    "\n",
    "The source SHA and every changed-file hash are pinned. The readable patch,\n",
    "changed source files, and manifests are exported with the results. No GitHub\n",
    "push or commit is made. The unchanged source checkout must be clean, and\n",
    "the modified checkout must match the embedded patch exactly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2a67b583",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "2a67b583",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "afbc1cca-9c9d-4111-a4f7-253307574360"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pinned source: 35f8f7c306ac2a004e6b10dee37317d87918d5dc\n",
      "Patch SHA256: 4887015d82d22f34f82f988c0f3e0a0158698439b6f908b2c19a3a4f0cb1a325\n",
      "Changed files: 12\n"
     ]
    }
   ],
   "source": [
    "BASE_COMMIT = '1ef0826a740b972f306680350983df4a91d05ead'\n",
    "PATCH_SHA256 = '4887015d82d22f34f82f988c0f3e0a0158698439b6f908b2c19a3a4f0cb1a325'\n",
    "PATCH_PAYLOAD = 'c-rlKYggOIw%~VuMTK5NOIQ}z5Rx{5)9G}&J2QE3L;B3^!{R8ymO;Umgd_tF;djmV`DL>oRZ^86#t_a~cg?zF1#GFb>$TsHQn%X`{>Cu%^B~*E#@&-J8imm*d`^cOlkmh%vz1P#BTnvU^YhQ5+k5Wphz|UIE`I)bMf~vO$e&E&D{D9jlVm;^L_si`1X<>#esmgmlQ>T7;}x+YW?3Mzd^8wj^Jq92e29j@+jw}syV6<dOyiMA(jf8EV6>|mN3$scyg8V^OjCdUF38W~QRaw)`JYifPlAzt`F58dO6Kv_U;wZtvr#Y@tnc!mcXnXBo!-uK=NSz<oF)?hbeO|*#m$PqpK&CD>m(S$wJ?sXwJey79RN6hhR{d!;zw`a5%EbDq?i85Bp8Ul2g4T@{+d09JL8>g`epCiqPq_deGIbMB!2;y_EjJFGYN8$2kA5ud*TrKfZ_US7I-COYpwij@2+&!lQ<$bjG`bdui=ktjGJKFD;;$=nY*+_UVfGa{wTA)ebXQ{J!`KB1N_uaydX`jZ^1V)rS-<IacU)VM+9yjds&_WvRJly^cFS|7rx)$M0Dx*drto;t$f2=%+8Wo8s>BByT;JrF?9ID#>R$tIm~DNL|npD<5Wa(Iu+T)jPOm&qDgoTs6!n)B0mc=F+2-~=NUEhC*fCG9+$xZp5SFqKHrQejVRF3Q6MAS+bi%M2m`P12rUKE{@ZT(*oSkgaWnBbcjV{38^Q)!HZGR+?dv!3)s-WKi?*B1rY)=UF7P7}kHtSk3`B4lq;qjGI|*|~4C84s%Y%`)3SnxqT=?SsY<e(9Qi;>NT#_k(@V-7|G0FvyFp9ZXMhd-*LjN?5{E4SyZ3&8d*HPaf-tvY{#cSmN4(7kg4n7nO<WtMeL5)z(qU?xgR8WUvIpc5?Oc3GQ_)UHmq%cUytQv<wl(xN1oVmZfqj)p^OkIC8@`e*X%LaoN2lL+n#$j+V3xNIZTZmna&E6dxQg;iQX!kqy`}&$5$j`6BbT|w1rJkwpgB%JE25=VoKM8>}gH%|rCgFG-rz4St)7gZuLUhD|KbwRizY5cd-8u&e;}dq_&$yE=$jgmUaJdo9CX>aIQH@!N$4zGw<c!nXCT`c+*mxp7BzZTC3KS8q4*uMLjROh_hBM+T;uk+3o{1q)b|#<=Fvm0mZsiZtI0Ih9>z3^@JU|F|Hq3GugwS|~I1kb&00_f4%F}p4BpXIu`MCJ#&tX|$4A2drTsC!)unMs}jN$SS#{+Bgho7Cj^OIfGLds%O6z}rAy2xdqV=qjB9{f{yPR{+X9Ie@krZE_3_vvHNKdnCK0y^hMP2fLfew5FqzrOt4QR4iT9{S-ZnbSU7kv~N?yIRMnRS?%{{56O`LFpv36Ih3IHq1p6_9<eAW>z*!g47mQL3nzWXRHPwB?70oReke7GXN}AjdqYf97Vy^aVcAZE2{?DBzx2v4E7U_)o9!>^MYxD0#tx#c%m*(f(YaS+)U!DAob$0mtVz}rX}DHJWzmPLE=Yq>)R#3xx{D3VFcGLTYK!rgpdaLERDqL6y-9aMQ}X~5{Xm?^S}F(S@0S+4;95L66huX{8?2zRE<VVXIU;z0>J|iel!wi{v~_>NgM(7#)78RjmKS>7KqpAG(TH)OwhKiiPBp`s^Wr*o1(khs^t0M=rqV-MUFK=G!3Gx&=YBYW*Kl207I&cvG54#wizue%&{FOD-G4klL`eQqfTK9(Xj<u11=%~qxdOF?G9u_<%UKD(`y(O?Yy-HU|IdE;9#NXEr~x>1xaot4`7Lnj6BkGvbKF>C0Vsv1PM7StTRv-?yU|GsrZnz(|r?c<q>x{iKBqgr2s2MTF|B-T;iGltB@>Pc0`s)g>5LAUEM6y98nQnY$ufC;2!Nq-Z(irMvq_OYyMD`2z(Vs>@@9<BUXpWY}Ia7b3Zb7^2G>fHxOxj)t&lZKytD!e&R>xu6XT(DAx1{GzQ`%1i>AH&IE{+$0bCR#rPOn4M8MTV}BGUfGYW!pVQ4<;8KD{?~)va4W^Ao&}c4$_E7FNHp{#dR0v-Dn9TQ=)NY}rc1Pg^B3=_->^Ca4zr?d>grJ;?yzjq&?;e^0lK}SR6@NfDHC%!<MZ1;<z|3#Af^Fdx8uXaRUc6}9#mW=GBmiccBU}XUl5G}@JlG-&pxJJG?!~DGs!xD8TM<c3==d&}#_7Bwh*oLQOU^E0FoecH5UU!d-x_F(qdS?yhQZL(D2?Iub{=_j*qflGyL)t?74YEpwdLO0yr;}=98H7J)-e|`dlF7VG#v9-^u+JsFS{a3z|bL*2_rBniIhY(MRhb4^jwfFE41(6TY%OQsgVR)u-6d<Q#LzA;L};r0e~0`P?`3Ie&P?&SW}y=kB%r9m`TCZGnk=}+!FXc8R)@v9z-LniLaK=*?+Tl^~p*Oi2#hv{w|hll6Y@00KH@C0jnjC3iaitL3ZXRfpvs*=OAeuHyGt?w*MF7Sv}I5_p54hlT6>+6Pu5q$gc7_z@rzl5LQkA`v;p6G*{&H)Ys}FbWUkT*-{uiUIu+jfDIU|bLe|uah>pWUskiUz6;qGO7h)$k8)maGRw{^c793Ek!`pMO|RhJs-WrwCILSljRDNXWTtvt<m&o2(N)bYwzM<szBE|&Qn8Yr+@Tjd29XxFWhv)Jae$s)AR2bVNK5R$Y4u-2tBpR~wK`J#e?ZJc&zj3fDfqnXFMiDSc};-Ye$12uYq9qn8&<cjz$#u~-W)&k(0gOMqxdQsf*A7BU_2PSs6A{gP*H1<memOM>k@1y!1b8$RtY=96-kg+UDWUjcM%%n4GW^2{&F3bS_IwwuH&>3K~Z3eO>B>yDDh$6GtAU5oznkbozUIP_1`+@rO8mEpnES*w-R{{Q}UXl^QR%^Y~Dq8`tyF@>1~P*{@p2p8fbZAAOjh88V&<?nkQ+{Ey7h~tDgkG9RspBG=m;P(qNU8p!~}?90}OK?kNKO^&LXJ7PxLhegqwkaP5>`^e#V&-np88rttT)*c`Bf-3Dv85O}2t+^vcTwc)VWPmY?wGY{W%Hyr`Lz=%MNT@N55h@;J8fU*ccuK=*pHRIOSc$Nht2gFPUn1R@bgFcyslaU7t;UyEFEPhcw1`GUwm@LR#ye)<xc4rw0u6!0@5W_nB%{zGe^1b)#pYIO#dJYC8ko&rf13x`?c6I;<e%hANdz10&AIqs?x1e@w;SMnhh9L=j*lOCz0igyCDgu;I;gj4y2MaY9er7=POEF8+2WrBQDInd&EJ)`#4}>P8EO9)cZm=afa4CFjY$+_H2M}Qm5eN2FF2KRdk1yZ8ef`$^^vB27hktx{`>R-66DdL+42H8b1+&w`%~J$zqj`@Tr4RP4|8*`hq%2TqaHWA)qjwzU3UmPj1B7DK&aQ$W$%KX1y3-&%#R%2=51$Nh=_~?qEIy&PYc?L^yfT_&Ky)K`EJeJE;#gS>Ym)?ka3cd&Nr_}35pkj~ob<j3gU`68lK27<(^vBGLsJ7%Z|DF1pY4A}UGj;H0t|=|++Cpl$($gM!xZc<91!;9i&KzY5qFjNb8~~SJ@(VZAcNaLf4rQ7h2$;uH>4ul*c99ZL<Z8(h<tQbK(dxSC)lQP2Y(L3=^MB;7!c#T5#i`s+={*Zrnc0cu*px7$=pM>=7kY$zO`2H643vVnvd22)-jU&n*JTgP@<?^@8NdA08y~@V1yTr7y-~xZ{aw3geZ)9jYC`qFzX0see_);>f?w2!bKm3wB(5TEhFmTFNE{Z0UezAS@3Zd!I+38-aVWIpYVVVjiDGK!y#A?9nx>O^=)Ig$eiXIvzF^1i)jVhZpWaGw%n(+;7JoY%Got;1&j-ZQ1+$)E|$Srv=77xm)!|;A2AOo?N#L6EzJ$yfw8dHAK!V0uRgx~^y&{64Ls}H@Egb8r@?eEK)J)STOYb7F{o8n9(+SpYPY=y9F!c+i@QccD!}(?5cS<ct3e;d{xYM$j4UznLE5BBqD+D@I@3|krom+xgNk58VeSN&286=6vI3n290eA`i9b!?`iVb0M`!eB7~bc>ozO@wUHJ(pk)S?v1o|9ACEp-bEV%ZE`DA`4sQy2rGKMjUqf_^eEpkC+h*0`bcw^D(x8G92A5^p!0JjVI4NwNN8%b(wnh30NnwAbq)W(H02v>*J^mt`#+Sl8PrXyo|xGNSRRF>Pt<Rxn5q&p}r1@#tf2b#&Ug1-eFPvRVw)TGbK_>mT%SwWO0&uAcwbqTeJ6|}68z96QaK?_`3Y@B2ic$$^SN_s_ftVzY5Rg-F-8s!Lvqau~a8qFhr8V=P3TO-v0SyI^<Oes(OFVy86Rl$irXN7+IdGDFCB|6*Bo^Ct6XFWrwKldnp_QV4Dy5)#%M?7`Jjw7Bq;<+P!azqc!5;Z(Bz$tOJWtzMaYMuj*?Mp8vO&M(QBWq12H+)DO0d~r1aFY6<Hn1Vsrt8_qj!MDE5cJxSlq-0B2|KXU77?w4LBHSr>paZ%>pYqr)p<M{s?%yel?f^jx1x$<fyc0*I*(*MbsoiX>O7v+)M>VuI^St6sn~~RDJes#(`Y1hmNbxRUTGaw9?3*n<c+@DH0nH(S+w*h8qJ~3<CsEA4Wh*a>fFctX|;To8iBHSI!)G2r@_+cv|Bly1r|={Uu)fT?q}I_mbYp;|5A&lv!pfCd0b1Tb3ZGl^OzP)=h3W}&f{1vo%>lWouw_7=2dRKY*;FtB_4W^h0=Mrb<)O7Zfhxq54J`+i!71Ol2%A(Sqr3df9s<*=~7-xi-VQ{D-<@wn<*+snBuN#9hBjaMSeo2!I-oYR&YwC5HyUDRu{q0KE+8qiBCh&M?j|;1sGqVh|CZap&SIcIIYEkhCWykBNr1gp*=jwpvpGzIPhOmVgXV3p)|li1}HpZ)K6uZhl8q^ADvEu?g+*kjes5)Se)eHRF;Nih5p6$6h6#dM(xG>Sb(B|>KKRigvz<b%u>t)#q>`-)w`ZEtyLei*fMyhl1)6&^NwY+7^sE^%y$dBM>QCS*O<B}*NGc(_~ymZhS7de3Bk$ci|1pcnOBm`wG{Kl3<^MW3>FsoAz%g2q6`MVy!mtpmWRsaZp|B6)uYz+)K3YZh-9~Cgdn+;t6SA<t1ZoCZfiZJQpFMGOVT{^k`g?kggP~22XO)bDZ&0U^^>zB1W}cIn1++MapGYmE!K9NU=oj?%DR#A9%jdVNIt<QSX4hv!ys)Ei&%3MMzdgXS_bzDZAT#yIP{yv)1cZXUY`bjHcLtTRLfLksmhcyMxR*agHAD2z#LeKZ^idlAO+*8<vGHuCa&K!Wv!G5BI~wbjM*%~nn%D1Fn3_7io&d-I8qyQM)@EC{)Jtnnh)Y&#pJUlq-t0*DyP8O8^9RYS8bKbyc{g;p@N<IR51K+eM`QH#J%*>5V^9fPq4LGp;}gvfuEec1DjWj<3=3fzG;KWV{U#8z?4391H3N^SXSuJOFCi5h!b4-a94?r38!R*Iv1#@#5JynZL75!RXw^Kp|faV96h<Hq75{r2bAR+YpwMf4@_JpW`XVi3^0;+uQJK%>ai&;rPOJVQ%REDL=Lpq)X+u}rcZi37+Ds#PRoNH-PcHJj78P?6Cka^8T8`~c7FR~rP6EFwi}=lQni4bhCpYaAJjqDVcj<38cYyLj)u-FQj{~C2XiDF7~9DDhWEaSCrvAj94`06h^xG8dx88Z20n|<qxdRn9(cRhA+}wW<ti^jqcgoQJO`pjl>F9~j7S1RwNj*6qv29Qlx-C^K;_A!sbn&HvHrY~m?x`GYr-=1uXuJI&WdKM=JGX6n5bNnDCI1Ht2j)qc5R~NJvBRb7F~g`)YITvn47)SxXHMO5#wL4cj0BS=Gt0=8C3$e)o0o11+y*EYBUdMW+_*FD-7V44|MxiG8cb18jeq`9F3S`c}NGSMToI56HgU1d)T1hE~NirHXK(1t7189qm{}vfdTa!um&`OGy1Aaw<aS9*tjsAzNkKJfwix%1u}cA`HmB-Pz~nRfr334{9Ot~5LQTT1F?Fo1hXSTAgxW<W>}!3&Eq@ZqR*EaI--A9+mBx#GzJqcu0&B)en+jPLhzb?d5!YoXcK*z-A(ryjNRQvk4f*ii95*D;yqPu$QiKKk)@CL+CHvQJ3j045gg@-7xj|Dra=}}V3ejvGsOi(Tq&O`AT^~&TfQSsY@8<#L1!Qes=U@H{y=pLQsB|nx-Yt7{lunIHOR8=1>Ii%ZWn<LrD68PVv+&CdRdy9+R!qOH|)h29bxZZzK1QT!@a#HePS@LqM0vGnSfxuJE-CvL#|Vsn*1Fo-Y~z`6jV-vZBIfi?(_LU&z$X_@BpD_&X$>jc)Mce9>VI$BveeS1^iTspOOB1L}ycc3exE@>3rxTY0L~Ieod8QdM)L{Iw=#09l=L9P_}#Ra3b8pJkE($TivO8W+<g{LN`cav3|ZmV+@@~ycl+sghK?q>AEecB?>f!3F?r0Es%`~qqi>iFlw|XLL;PZ@RAF_&IH#L5SMrgPTZv{g_adW=yoD@)RqXdu>k}EGFV)QNqEV{V)!+QGqMihx-|*&d=hj6Fc^KKaKLU!AR&b?%sl`ClelO}%V51<&0$fdPH#anl={)u?VmD{Sq|Z0c`N;YRi9F~w?eVMubSIp4JXO<e+!=^i;l2sy%}-4y=MGs2s3<dSIhMDptav>U!Y}Bp%^r-#qI+~K&E7S18-4-+oe(-CI9JY%=IWdMw{&m(CfOIhIY5ax8wFa970Uunw>pn3d1-U103#e*GOS99&l5c*Ie=ZG(uy#Wtbl9($vq+r5VJhBCKf)$*5m4{VA&FrgIVwXH)M&y!eNAvA;n<6tt+(=uYBf2qsug{_`jXO)fs66O{6K*T<45t!TnE+#ve#V0Q_lTD>m1L6)o4)gUcZkE>j83oPtNNnvdieufg;G`UJiU6%sVA`Kn!wQh{+hqS>4TM;OkeRmT+hAyqP2jfK}h<mlghKLLsl+Sf*c0V;&`LME3oHDd_1aOb<vn{o{&5E9~>=qT(m@?c+?jP7MxKc(d3%C4T+tsuSsO0Mfg|H1@Ve0m`>bhUm7m^d;D2O4oSyDXT;DxcOa??ub7M~>fP~EIsonA%t)6R<2d=q!HtRF;|`6y}BU@=HngqQ#rCd$na`O2|Y9hlU1zczf*pEtLkW5!=^b8E+WW-8E1w`Ya>VjNDbwW{sVN2}fuiwq?rBM_MwpZ=!p11W2mU4}R|jML!9Ok8a4y*>N|o${Ap&d^zGn5KnHm12Sn3YRgQsH!qb*@BI8K$?eB%AS&WYnb?ms~G09QNRP}ay^{5@+apq%tuEBH863+TEvV(<R3fSkSKKa+(49~Q8SrRU<`@CJPoWQ&_zdqK})I67P%1Rb9w3mzmHBmO#G5uiFUr}dHoczHH<+3tS#A-#v$6cLm0vOgrh1OpinC9E-!A4E!>u=Xck4=CSl@m<UBl$_|u%q*Q`y6;pN}0!k#bneNyxn>G(QtOjuvSRlrY}X@vt2-}D^Mi`|OPS+-SAZQ(&tFxcgux`FASqR`vbk`iPS>boj73t!HFOwT>>5W&UD;u?+9HbqsbR-0_L2n==2%XN9STSE_Ee-&+*X26zR!`3TfknJ5<p#LGZ^(kzkD%oZ!YN3K&L%UMt*BbU48g`o?dTkIjfVY+GUz+Peqq)Rc+Aa<nH|}Z`6F`j{VdlXeY*tMTX8l<FlMqP{BlCy=>z2a<)k%p0#T9e!V4peGw3HWG7NUQz6Pg$@v3-y5#T$XjILtld+ihMhWY-v)FcMl}M_fGhi3lgG(M)CgVBJ`&6CK#aXXwa`&}~;<Uk9Yv!d1<zB|{H%xUosmt>*y`22@uLP2gHya}Ix{U}A9;(v4XEDmM102ZIw~+o4QUfcf{I?lk6I5UxpyCXdaQE4D4ic=1hG7C{0V)atKa*oZ@0EM=ZI&$;4TQcmJK2&Kup)Z1x0Gy`FOVaHJC;m)T{n@8y$0;a)}vnWlGnAexWO>*J1H)YR@-gvh(=?lleh2b;lEb<4m^33+f3g*zp9f4Vh+Xa)@Y8ojmg4&)geOLg(YYk_&<Rdm*D)6wgCt4j0bmPnM-RU1?<fPH~mv+B2`P*VBMHE9q>lTAt6wkPAKD2z%v5ead$HCyUwL@(SZb{6dWSQ1BSifWguQyx38_=Mc7Zj7M91Eq^1i&sj{h}}wReR7~PqOBfG3}OSct?P@#|z>T)kCI7@h~fnl=d_M<xWTX@zOh+bh`8pMa&NqEz877lz3>y#Pa0n5{`Iz@CM^=Xa@#a<tXVgR~cKOiwERrw$hOqD82r3>PF9)^V2Xtn+AC}bj6!8y%Udvk;zdG=VE4*)O<>rqRmO1MNSP}=3LBCCL)!=Y36Gp=cI$`!KNxQCbA%>VH5{CQP*WkMVY~=0-3VrrdYX*&cy!w`Ex?4nv}s9r#YW%h3FS0#Whke#$X822_c!t#`r9T4>Fk%f{{32b}IRmZph?Mt8csM+`2}?)*W73$ljo-7S2T=GWASV*{yWs@tQ|B0C~WZxTUpVWehgkqEIeHa(iwcHKvsgAI)e)UbVv-Ed&a%kywmI`ni6p5$GXuBK7lYtRuyyF^Wu5?<t-a7(_vO8kz$zPdBspd_e?m7XxmL6!XMkj+k%7Bq)$XnF@{fG9a;&$dJTK`%2rZ&;GMCFET#5RQd?0uF8zR5Z2;88$^@(S1TRzDClGX^y6?U|Ah?l$neeu`WM1X!_YH)O^P^4!_jHb&471=<8Y|aNa>o$)H(6xX|<fU+;-9?S0@0z;%S>1dp7ulT6|W-R}oXC%u7eIoBDIiz5*p1hM~RnfrcsF92%BN#B{}H<9OT8MLKAPgOc`}j~<wk0*7%jXKK^&>@yAHvxy#`xqd;SF>DbnI5y<BP;lj1228?Fk%C{Pm{-mxjTWisg{x7EP@+F)m)1ZX{Y}Z^>bPG3>gR~_S^=VQR(~3xLz#P$$=$!dc`HXo88~H*D4*#+nS%_d9L%rRRwBnWF^r2LWl<$9*vknp!!!u=bKg|n9PxJPpywRAT>zD*zTTLV-M?_+!%C+RA_W_iceA#H*2KR6ZZo8uT0QF-dWGd`$aQ7upz>!`RRFHAqay_@csv$|zj?oH^=YcV0Wp0BW`lJeuIoy_<ld$ukxEZ++WXB1-O>I`XEB#33?df9ilXwBPT>M%GHQOW39X-$K)88YpaT$zFu_OJLpTzSDaHWCC6*i@m5qWiC}X%GXZ~dvQ^DsfVp@kLRVf+;vlL4dCjOkZXM!aMbSTv<iUN>{8D<-kgI0-69%d$G<utwwR8dKM<zM+QG)<h#bFdI+m8;SpeTl;e&ufMaj{;Y`low#tfEggik=3nvi0X;dA$T<~PZ7Rd`6<?JWZABIXAbeQg12!o1obw{<I~h1sizc&M-5_<QweN2q$wRZERuK<4w*yzjuHg$Nnf*?dpA>VT5?oukn@cFxQ5r(CDjNE(lJ9*NZm$YbPX79NYzfPm!#+b5Pz|{j&&S-@*Q%k?mwhzqyl2QC3`W31Uv~CpK=KU-zTpE;7oybGG2z;ij1{HGoGg_4(PQ+a=g6$1#iHyz~5bdUzR5PaG^my)?Rv4yvs<w;D{NpuF1HH(@@Qer(RFv@n!2j9q||NcZ`Y1(lBOL(3SG=09B0D%au^11A4K(ru;o0{}Mq2Mn2A99OLP9Sm1_rbDUf*)9Z<6VAUKhA*}2?C#C`%AkBeIIfP^IjGrL}ok|?J;Lw56W^n}xjF8Ucl@1OCEfq~0g#R>MAU;xRK~$$masVO^yF`|NO9?O6`xpyWK*k2aXqF&o)<bX-OlZKZB1LG(^d`uMUd0pt1X=(anEL6tD-)CSwcqeOWZ9nQCUa>KwBAN*V2j@Pv!z~YhUs61R_aQMNWrv<e5_QIs;j)-^oV|zC^x1nO-<FArLx_}S;WB!SmHWZC1Ygc%KIlArRuGSJe?0@P^t#S%f=o?ZWI)bx`9sSAxEcgD}qn;6mO^rMG~+@FrX!S*25)x)|X3GKIamD+7m2MJpAVIDXd5+MoWxQl`Zj`(eh9#uiBV8cTc6RPGfBD2XXl4LAT!@5W~k8;V9wS&CdK$d?kQ=1AU@)4MfddTgfa9l(vKtYM0bD0H)bzX&@thBVOl{jCC%{Qj^J3DtGc!zFuz!*09s-DeUt+;ANhN)(LOl4}kKxp>#TY`FfL8pbq?_RC@d@@ew}~wynxTn^p^)!drZ(D16X@MC!cwWm-19Y(<s#;K!yn1gWX~N?OFmK^k9%Xa@i<%j01@$>jX_{%ca8xG%o)%1@Y~hjg|*H&#%v+5e1B@XyQ1X-u}X@kPz3iC3^*lWn9kEDEPDEo`HuB^|}G^9)~%h<|#0BP`2FoD@Y?DWD!)D{WC>oH!%1a@D4KbP^~UY<hv+s!Uq<&OiqMJpjYdWqA7s@e&oE(}0h*m;|T(P-2~dlgPiZ9GcV*#2nDk%VYLJv>McqqQvzxN=#7(BIB?lMwr*X7bR}#+|b;T<X9mei9Qsm)j6OT=5zuG9&W-z>yjeK3{lB;9UN8}phQ6FJ)TV_h2EhK1i@D!kOHbzS(|gIymR59Q<H(ay86tXSFEim8{7Ipo|uh8yklQ%4pu7Fe=~kR2M<N25>RVS9<UkPo)OR3e!hu^x>ir}EP&kH>fOSs3y(OHSE@%LxdXfVz&3~Z5m;vqXnnDtA6E|c!Y49`2q&4Pt*9;5*G0clDkfVuyxw9t04n6FZCuE@Fx4#43fDHSGONm7Ro;UsZRwj8(GW|R`Z>n_#;cn*s>I{=WYr$<+E|I*_>_Q0611wzhyyKz+_UFTY0rLAB6G!9u43SW+E&m)nx6H>ZLFQ1Rh09-03rJN<?pXQdIujr{Br2Md-<Q<fBcE1z02S;<)|$I%5>c07U9`HI2)^Jz}g}b`)Y9G8r)au(~{##4{rY_^5CwnuD&c)TXk|0IXACCZ5)PZD@eP!^tZ@Lagg$v3lQiGER^A%H=f~Dkit@{@FPGzwnbz;cFmiK|B%L-_5Eu{%=Zv^9kC9K4~&&_4;^I#WLdDoG9?I*8mor^spZ)eFs#?4O(=kJa;=6yGMQyH3qXZ#KhdE?+8wZE!Kj-Q{yMDJp7@D_34WJFI*#ln9y1h-p<35o*qwW!z0tSV*Za~Pr)&yEt(<mJHxwAoGS<R4@Np-U)gYIIKU|xV=~`piL^-gg+;9#JuMxZFIIu<*GH-nt9=nE30af)0rij2u=jPXImtO92)H}vY^WvL!x=8AW&|P^jKBnZLFR^ep;oJ6#Dt2;s7T!~}0>su=%R%A#!eGNpR*zoWRHAGPGEvQYb9wJRLsFHaMu%Y*QkY>FSS1dl>nW#x%WLQ?Uf7$~RQ2e~to=)RJ6HgAmg-&NJZ(4UVOf|(b!{V}Mle0Qb^FHrTC$Xm!J>C*V~jvOU5-Lu8^THwVAn_V?0_M3gg$Ae=E1S(iusZJg5NPTx#>RD-Vl^f+5tm#@Bp+u{%jj<*wkO#j2EJHP{+JPNU#MQ|2oX}`Vxi|dkm&Y8;+t4Y599ZfGw(UQ#0hsPtl6$!0%pp8X+kjs<j^0<GNOl2+-Cvp~OSiARR~tvI7%OsU_D0J37@G5ZpYTgjrs`JR5(g(iP8mksfv`cjFH1%3+TjjwvD}^rR!*o_qYqBeBc}_V4i@+sGs1YZxmx^mUS<B?!8Yq20;>MA|UWQM=>_N@woEG=f$~uUkFp5-zq6?EdRh)w#al2GaJiI>p+Xju>QMq2^>4iZdb6_-a%|8bmrYx<DCt)^mDWnrcOloKzlh#OWiWTKC_GY89(e^#n#@nCc23dR<C00>2e&imxQYBhciy9uIj{pInbfE@-dPbFI?`R9m=;kB5|vL%(~uj7PjEks1hL$Ps~|6ClnxQ;CGnIj1BQSan>d2&*Is2^VF^siXAbI**2Z8J^w6p(~9fsQ`aQf-z5vO?WPh<nAcQ{o$EqyRgmhTUx}6s7CEp>GgC7=700#|KdEED@Yfx;2N?LR=If)WuV5v<4W^VxPxC1amh=(!*8A0RGhguID%U{m^(hqL4)=$=>P--nmr;~0_bH>v(Ce{2Oo-_2%}*O@NyeJ*Lq!sr(^pi_<Gr6GZB~ry*Gb1M{zG6-?qy4MD!(A`YwLIU@0HU^P7?HxC)Sw9uI#Z!lE~!F={JW0JvZo)P=$U?}3Q`CR>d{HL%J`ss6s(-BP3snf{iYzVf%I7=WYYhExOcWg-OGw8|Gl3E5i8+r4}*)Jo<oQc8q>GE`09zzXvlz~1>u5=N)8IjkCajk(pQzYbn|ul{)b>VLg?|2w&J#^yDNt_^WOb>biclHm{b{ZK@y8jmZzIEU)QM!$OO8OPO^JjhY`al%YxCE}V>p5f%mpJ$x-QhKZ@YAZ7bPdQbfOd3?~oLc7K)fvYBW$qw1HV$rVIsj6ZOO{!MK2^uJ<`mMo-y9c+)9@5sy@f`=u-=tPGcspJWjb;;OzFt0rQ$FEPBAKx5It0Meo!7lXX>2r0tBUiP$E)R$wZO^`rqyOMjU_7#K)I^eR%J^|MMN4nEvwDLste9i!?J?j<PV<Oy$939MF*Obav&jsPLGPCdLqnA!VFrLYXB#rG{}%gOR6bW3QYSL+@7Sye65jBh$$WM;m`6TS`XFEv{^ot1wVhK>kbQEgG}GJ6v0#7j&j_en{np8c0!+>B$!;?lrf!Dst3T0DewVOti}9<;0Y8+bW8xVbuq<x+%Te;^?OZV5?{270~k;5GQ;1UDrLX_e2dWqrVC;Ti=*MDw-$bNfu~?628ep-{_C-@`AmVXYTr()pclObrm^N>`{lEQ&BjL-MfWnwr$mlk&=ccbBFO5(_7n|k&dqBtQ3nsYM9<}^Nh5-YZ=V<IZM@1Zto%yNS3o=Eh{m~C8neg^@!#Lpji!o57+|_{n(hHkrVvgGo(bl0F!GG8;Dn5g+OHgFtex%wycQb&e<8mTz+<ytmJ#lPcQFoo@;Z0m_pPNIaS_9YR1=Gos+y$8L2Ia*s46gFcnBvqZ}(TUG?HE6ai(uz0`p)E%TbO2?cAA21PP+JRHsvOgZ6{W@EOC_ocGH3wOp?(lSm}Ns2f5c&i#CZ%`6)?R09D7PE`7>MD#9+2n*;IJVuWn^IZg25L_9(Q7R3FjduF@2S#Ni{q<F$b)bMMf@yG1Q$Efu}iIG9!fiv0t>6k@)#3VIt!~Bk~sp`8a0(U)a9cJT^71;Lol)2L(s)CS#)X1vL(4y+L6dd7&Ms&R^N6s!v&Am>j7>YVU+{$6{k5?UpDUczEJZovOV5LG_(*xw|8tGtKFsK4Kk9b+=x#sQ*HvujJ4>DDtJt>4kZglm6=pwo~P)ZpbJhh%_9VIYz8?}nM9`+i}9xEL^gQ>GN0Y-DTUAjT=5i27qPR3x)f5Pn`%?GYPBg?t@0JGz=t!dCm+76T7@QMR;<Ws730vs=U6V%<3k7KW;C1?*if-zRNB!ZL#yGrbz~Ul$X=8>r5zNga~z66Nr32Kp||3kx}4XEd2Pc<oCUIS&MEqIgby5ckE%;R(=R@oYwKPY3$_6Ef{8YFXzMG5h)%C|>TPb`qbs!-*bN@JS0)ju9^q<Jr(Af`Jmw>SL$PG^$RP4Ow-+EY3kFrj&B%+1g!p=dfR$Bd6j_1FX>`iFokHVy>dL$<53XC!)bSEhitS-*ms6iDEHm7DZi|lSeG%&ocZ^3jsE-L6c-+pCr>|+RJz&gdt48yHa6_j!>w=OVXcF{NBgKkcnW12De0SS+q$$0(rE?Jz#V<!d)vALAMk;<5>XbNG)QJ`yRy0-jnjTrCCrAjggbTew$7ZPaA%r0zr~(_^31w|znI|1|gxgG+0;sHPh^?|No7d)fF%)w(a4}?VmYntadcQc@NIs%f{Om2OG2KZ;W`*g(x!(z;v3gX~e!dU7SrrGnTLIEan?%nhY0}%?OHy1=+Gq%yN}1!sgva%*abhhO7$UMhQ(}WrAX`RmG~r{<MUecz+jE;Su0*vAaSh1L(5RQ;yY<4#hi>rVddekHeR1#nIyTOT!iB%Nbp-DRhrw4PKU%emizL)n$u$Gt`nS59fSjqUV7io9lUZeIjXkI)V^*b<9EIAzWr00pjgAln5CiVpSqnJCtUmnTDv;_v5EXG~G}c2s3}{Lg=)uQDgv{zVYvF~~sGkik^XHZlvHhNg8FZ=^YSLSdc&hL9b%W@&fLbFx!FAr$Xsgmlt4IM>P_UKp>h(={yJ}Y@MWht^R{j*(=E)_P|Ej%~QqO}ex~^iU((TfD*~k%L6|y$0Zm$gn@I@Fx*y-7Iq+P@vmDhrDC_xBU;Y)j>MN6yOO*e8$6=lmeKFB31D$L8}LCyMB*Q0$CsIEO^U_4~F-*U8=#U?+_?KWM9D!Z@M$r(Qb0QVCz-Q|>$)`V6)e{Qee&i-2IDV;^$5O}yA2lu2ahgCq29XcgJDN9hs<4ti%q^!ha5gw#y=3Nna88fVuS+oY|4gH-5<r-d}Oe+CsXr|}0-zlB+2Q^KJM0cA_kp;PW&P=;TYvN{ga}x_>dcD=#MeI(7c@?MQlu%EVwhn{u(_hdOF7JNDyNYz1^PB2Q=n;7z(2qeUHPHEB!aBmY7aWsK+?V>d)N9nS`%1=c!9&pVfXwHfJfsEVr&z$+6znd0R}M{`iObi<NKdE6g(fo)k<&1mWhy;EKI|CZ%qNZz-Z7m=7j$>Dcef%Od9z!+sS&=_!0}2g0DG|A7Dc(4M!I4lL>gBsNHj<K#!wevyxIbuWfNn0RyqoH?3MoqlS9Vf'\n",
    "PATCH_TEXT = zlib.decompress(base64.b85decode(PATCH_PAYLOAD)).decode(\"utf-8\")\n",
    "assert hashlib.sha256(PATCH_TEXT.encode()).hexdigest() == PATCH_SHA256\n",
    "PATCH_PATH = ROOT/\"superfermion_performance.patch\"\n",
    "PATCH_PATH.write_bytes(PATCH_TEXT.encode(\"utf-8\"))\n",
    "EXPECTED_SOURCE_SHA256 = {\n",
    "    'crates/sf-bindings/src/lib.rs': '700864fc1a1f8e982fd4ff3707d6019a57e2bd4170652716c6b891c4c3fc6dc0',\n",
    "    'crates/sf-bindings/src/prepared.rs': 'cb11d20f7e4a81cf8a34726a644070c313d0f65b1b0c2e4bb7f6aaa9347ad4b9',\n",
    "    'crates/sf-ir/src/dag.rs': '773193ccfde4f0eacffe7a8f1727ca07ceaa30674b89115daf28c988137fc56e',\n",
    "    'crates/sf-ir/src/state.rs': '80ad4530e6fb77fc3ad8d6abfcfd39723ec5e31060e8f45148a90179c7e2a81a',\n",
    "    'docs/prepared_performance.md': 'ebcf4dfa164fce538fd0f217c4f722c5d7690a67f3683f664c837f074f67e609',\n",
    "    'superfermion/__init__.py': '18592d4c41e2e49436e94db2c4c49b87d53e3601187c42e5fb8d71db0e4f4053',\n",
    "    'superfermion/devices/rust_device.py': 'bb8b3be495c652b5421cfb034cdbb27e58d4f2a9c54d7b0eb059d8af8bdd2af7',\n",
    "    'superfermion/kernels.py': 'cb66cf2804019bc05b55ee23e491a9f39a0218dc184cdda8fd07f1f4c7b00f4a',\n",
    "    'superfermion/nn/quantum_layer.py': '8bf43cb4e89176d35e35192f5a5efb94daa8d01fbfacf1edff47016a489632c7',\n",
    "    'superfermion/nn/torch_layer.py': '199b4bd415a78fd1c75e0cef4809514b17ba2ff6f35d146b94096d564084feb7',\n",
    "    'superfermion/prepared.py': '68f348cbe7b213d11d82f2be5a077528baa29bf00e50377575d59bf8cb00740c',\n",
    "    'tests/unit/test_prepared_performance.py': '513c03d28f8306ac2257f82331bad6bea88bd7248e251008262dea74188169a0',\n",
    "}\n",
    "print(\"Pinned source:\", BASE_COMMIT)\n",
    "print(\"Patch SHA256:\", PATCH_SHA256)\n",
    "print(\"Changed files:\", len(EXPECTED_SOURCE_SHA256))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f40f7566",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 203
    },
    "id": "f40f7566",
    "outputId": "1b7a4528-899b-4e1a-c2f2-db4f59406840"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"font-family:system-ui,sans-serif;max-width:1100px;border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\"><div style=\"font-size:18px;font-weight:650\">Verify Native Superfermion Optimized</div><div style=\"color:#475569;margin:5px 0 12px\">Finished · Elapsed 00:00:00</div><div>This preparation/check/report command has no benchmark-job denominator.</div><div style=\"font-size:12px;color:#475569;margin-top:8px\">Detailed log: verify_native_superfermion_optimized.log</div></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished verify_native_superfermion_optimized in 0.8 seconds\n",
      "Installed three independent Superfermion packages. Workers import only their selected site.\n"
     ]
    }
   ],
   "source": [
    "SOURCES = ROOT/\"sources\"; SOURCES.mkdir(exist_ok=True)\n",
    "BASE = SOURCES/\"source_baseline\"; OPT = SOURCES/\"source_optimized\"\n",
    "if not BASE.exists():\n",
    "    run_logged([\"git\", \"clone\", \"https://github.com/Catstate101/superfermion.git\", BASE], \"clone_baseline\", timeout=600)\n",
    "    run_logged([\"git\", \"checkout\", \"--detach\", BASE_COMMIT], \"pin_baseline\", cwd=BASE)\n",
    "actual_commit = subprocess.check_output([\"git\", \"rev-parse\", \"HEAD\"], cwd=BASE, text=True).strip()\n",
    "if actual_commit != BASE_COMMIT: raise RuntimeError(\"baseline checkout has the wrong commit; use a fresh ROOT directory\")\n",
    "dirty = subprocess.check_output([\"git\", \"status\", \"--porcelain\"], cwd=BASE, text=True)\n",
    "if dirty.strip(): raise RuntimeError(\"baseline source has edits; use a fresh ROOT directory\")\n",
    "if os.name==\"nt\" and b\"\\r\\n\" not in (BASE/\"Cargo.toml\").read_bytes():\n",
    "    raise RuntimeError(\"baseline checkout has LF endings but the embedded hashes expect the native Windows CRLF checkout; run: git config --global core.autocrlf true, then delete the sources folder under the study ROOT and rerun\")\n",
    "if not OPT.exists():\n",
    "    shutil.copytree(BASE, OPT)\n",
    "    run_logged([\"git\", \"apply\", \"--check\", PATCH_PATH], \"check_patch\", cwd=OPT)\n",
    "    run_logged([\"git\", \"apply\", PATCH_PATH], \"apply_patch\", cwd=OPT)\n",
    "for relative, expected in EXPECTED_SOURCE_SHA256.items():\n",
    "    actual = hashlib.sha256((OPT/relative).read_bytes()).hexdigest()\n",
    "    if actual != expected: raise RuntimeError(f\"modified source differs from embedded patch: {relative}; choose a fresh ROOT\")\n",
    "\n",
    "WHEELS = ROOT/\"wheels\"; WHEELS.mkdir(exist_ok=True)\n",
    "BUILT_WHEELS = {}\n",
    "for label, source in [(\"source_baseline\", BASE), (\"source_optimized\", OPT)]:\n",
    "    destination = WHEELS/label; destination.mkdir(exist_ok=True)\n",
    "    lane_build_env = BUILD_ENV.copy()\n",
    "    lane_build_env[\"CARGO_TARGET_DIR\"] = str(ROOT/\"cargo_target\"/label)\n",
    "    identity = dict(base_commit=BASE_COMMIT, lane=label, patch_sha256=PATCH_SHA256 if label==\"source_optimized\" else None,\n",
    "        python=subprocess.check_output([PYTHON,\"--version\"],text=True).strip(),\n",
    "        cargo=subprocess.check_output([CARGO,\"--version\"],env=BUILD_ENV,text=True).strip(),\n",
    "        rustc=subprocess.check_output([str(TOOLCHAIN/\"cargo/bin\"/(\"rustc.exe\" if os.name==\"nt\" else \"rustc\")),\"--version\"],env=BUILD_ENV,text=True).strip(),\n",
    "        rustflags=BUILD_ENV.get(\"RUSTFLAGS\",\"repository .cargo/config.toml\"),maturin=\"1.9.4\",\n",
    "        source_sha256={str(p.relative_to(source)):hashlib.sha256(p.read_bytes()).hexdigest()\n",
    "                      for p in source.rglob(\"*\") if p.is_file() and\n",
    "                      not any(part in {\".git\",\"target\",\"__pycache__\",\".pytest_cache\"} for part in p.relative_to(source).parts)\n",
    "                      and p.suffix not in {\".pyc\",\".pyo\"}})\n",
    "    identity_sha = hashlib.sha256(json.dumps(identity,sort_keys=True).encode()).hexdigest()\n",
    "    receipt_path=destination/\"build_receipt.json\"\n",
    "    receipt=json.loads(receipt_path.read_text()) if receipt_path.exists() else {}\n",
    "    wheels=list(destination.glob(\"*.whl\"))\n",
    "    verified_cache=(len(wheels)==1 and receipt.get(\"build_identity_sha256\")==identity_sha and\n",
    "                    hashlib.sha256(wheels[0].read_bytes()).hexdigest()==receipt.get(\"wheel_sha256\"))\n",
    "    if verified_cache:\n",
    "        print(f\"Reusing hash-verified {label} wheel; source/compiler/flags match its build receipt\")\n",
    "    else:\n",
    "        run_logged([PYTHON,\"-m\",\"maturin\",\"build\",\"--release\",\"--locked\",\"--interpreter\",PYTHON,\n",
    "            \"--manifest-path\",source/\"crates/sf-bindings/Cargo.toml\",\"--out\",destination],\n",
    "            f\"build_{label}\",cwd=source,env=lane_build_env,timeout=3600)\n",
    "        wheels=list(destination.glob(\"*.whl\"))\n",
    "        if len(wheels)!=1: raise RuntimeError(f\"expected exactly one wheel in {destination}\")\n",
    "        receipt_path.write_text(json.dumps(dict(build_identity_sha256=identity_sha,\n",
    "            wheel_sha256=hashlib.sha256(wheels[0].read_bytes()).hexdigest(),identity=identity),indent=2))\n",
    "    BUILT_WHEELS[label] = str(wheels[0])\n",
    "release_dir = WHEELS/\"release\"; release_dir.mkdir(exist_ok=True)\n",
    "run_logged([PYTHON, \"-m\", \"pip\", \"download\", \"--no-deps\", \"--only-binary=:all:\",\n",
    "            \"--dest\", release_dir, \"superfermion==0.1.14\"], \"download_release\")\n",
    "release_wheels = list(release_dir.glob(\"*.whl\"))\n",
    "if len(release_wheels) != 1: raise RuntimeError(\"expected exactly one release wheel\")\n",
    "SITE_WHEELS = {\"superfermion_wheel\": str(release_wheels[0]),\n",
    "               \"superfermion_source_baseline\": BUILT_WHEELS[\"source_baseline\"],\n",
    "               \"superfermion_optimized\": BUILT_WHEELS[\"source_optimized\"]}\n",
    "SITES = {}\n",
    "for framework, wheel in SITE_WHEELS.items():\n",
    "    site = ROOT/\"sites\"/framework; site.mkdir(parents=True, exist_ok=True)\n",
    "    run_logged([PYTHON, \"-m\", \"pip\", \"install\", \"--no-deps\", \"--upgrade\", \"--target\", site, wheel],\n",
    "               f\"install_{framework}\")\n",
    "    SITES[framework] = str(site)\n",
    "    import_env = os.environ.copy(); import_env[\"PYTHONPATH\"] = str(site)\n",
    "    native_probe = \"import superfermion._sf_core as c; import superfermion as sf; print(sf.__file__); assert hasattr(c, 'PreparedCircuit') == \"+str(framework == \"superfermion_optimized\")\n",
    "    run_logged([PYTHON, \"-c\", native_probe], f\"verify_native_{framework}\", cwd=ROOT, env=import_env)\n",
    "CONF[\"sites\"] = SITES\n",
    "print(\"Installed three independent Superfermion packages. Workers import only their selected site.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "169541f2",
   "metadata": {
    "id": "169541f2"
   },
   "source": [
    "### 5. Run compiled Rust and Python checks\n",
    "\n",
    "Core Rust tests, prepared-API numerics/ownership and Python unit tests remain\n",
    "mandatory. Independent backend smoke checks and numerical gates also remain\n",
    "mandatory. Optional full repository suites are off for the requested-grid/free\n",
    "presets; enable `RUN_FULL_PROJECT_TESTS=True` for that extra coverage.\n",
    "The full-suite path retains the Agg backend, CPU JAX and optional test-plugin\n",
    "dependency fixes under the locked benchmark requirements.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c0d619d3",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 203
    },
    "id": "c0d619d3",
    "outputId": "f15b2b37-c1fa-4b38-e0ec-0432609e7031"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"font-family:system-ui,sans-serif;max-width:1100px;border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\"><div style=\"font-size:18px;font-weight:650\">Python Unit Tests</div><div style=\"color:#475569;margin:5px 0 12px\">Finished · Elapsed 00:00:00</div><div>This preparation/check/report command has no benchmark-job denominator.</div><div style=\"font-size:12px;color:#475569;margin-top:8px\">Detailed log: python_unit_tests.log</div></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished python_unit_tests in 0.9 seconds\n",
      "All requested compiled-extension and Python test commands passed.\n"
     ]
    }
   ],
   "source": [
    "TEST_ENV = BUILD_ENV.copy()\n",
    "TEST_ENV.update(\n",
    "    PYTHONPATH=str(SITES[\"superfermion_optimized\"]), PYTHONNOUSERSITE=\"1\",\n",
    "    MPLBACKEND=\"Agg\", SF_F32=\"0\", RAYON_NUM_THREADS=\"1\", OMP_NUM_THREADS=\"1\",\n",
    "    OPENBLAS_NUM_THREADS=\"1\", MKL_NUM_THREADS=\"1\",\n",
    "    JAX_PLATFORMS=\"cpu\", JAX_ENABLE_X64=\"true\",\n",
    ")\n",
    "TEST_ENV.pop(\"PYTHONHOME\", None)\n",
    "\n",
    "if RUN_FULL_PROJECT_TESTS:\n",
    "    # Install the optional test dependencies in the isolated worker environment.\n",
    "    # Retain the benchmark dependency pins; record the resolved extras for reruns.\n",
    "    PIP_ENV = TEST_ENV.copy()\n",
    "    for key in (\"PYTHONPATH\", \"PYTHONHOME\", \"PYTHONSTARTUP\"):\n",
    "        PIP_ENV.pop(key, None)\n",
    "    TEST_DEPS_LOCK = EXPERIMENT_ROOT/\"full_project_test_dependencies.lock.txt\"\n",
    "    install_command = [sys.executable, \"-I\", \"-m\", \"pip\", \"--python\", str(PYTHON),\n",
    "                       \"install\", \"--constraint\", str(LOCK_PATH)]\n",
    "    if TEST_DEPS_LOCK.exists():\n",
    "        install_command += [\"--constraint\", str(TEST_DEPS_LOCK)]\n",
    "    install_command += [\"jax>=0.4\", \"pytest-benchmark>=4.0\", \"pytest-cov>=4.0\"]\n",
    "    run_logged(install_command, \"full_test_dependencies\", cwd=ROOT, env=PIP_ENV, timeout=1800)\n",
    "    run_logged([PYTHON, \"-I\", \"-m\", \"pip\", \"check\"],\n",
    "               \"full_test_dependency_integrity\", env=PIP_ENV, timeout=600)\n",
    "    TEST_DEPS_LOCK.write_text(subprocess.check_output(\n",
    "        [PYTHON, \"-I\", \"-m\", \"pip\", \"freeze\"], env=PIP_ENV, text=True))\n",
    "    probe = r\"\"\"\n",
    "import sys\n",
    "import matplotlib\n",
    "import cirq\n",
    "import jax\n",
    "import jax.numpy as jnp\n",
    "assert matplotlib.get_backend().lower() == \"agg\"\n",
    "assert jax.config.x64_enabled\n",
    "assert all(device.platform == \"cpu\" for device in jax.devices())\n",
    "assert str(jnp.asarray(1.0).dtype) == \"float64\"\n",
    "print(\"Python:\", sys.executable)\n",
    "print(\"Matplotlib:\", matplotlib.get_backend(), \"; Cirq:\", cirq.__version__)\n",
    "print(\"JAX:\", jax.__version__, \"; devices:\", jax.devices())\n",
    "\"\"\"\n",
    "    run_logged([PYTHON, \"-c\", probe], \"full_test_import_checks\",\n",
    "               cwd=ROOT, env=TEST_ENV, timeout=600)\n",
    "\n",
    "run_logged([CARGO, \"test\", \"--locked\", \"-p\", \"sf-ir\"],\n",
    "           \"rust_core_tests\", cwd=OPT, env=TEST_ENV, timeout=1800)\n",
    "run_logged([PYTHON, \"-m\", \"pytest\", \"--import-mode=importlib\", OPT/\"tests/unit/test_prepared_performance.py\",\n",
    "            \"-q\", \"--timeout=120\"], \"focused_python_tests\", cwd=ROOT, env=TEST_ENV, timeout=1800)\n",
    "run_logged([PYTHON, \"-m\", \"pytest\", \"--import-mode=importlib\", OPT/\"tests/unit\", \"-q\", \"--timeout=120\"],\n",
    "           \"python_unit_tests\", cwd=ROOT, env=TEST_ENV, timeout=1800)\n",
    "if RUN_FULL_PROJECT_TESTS:\n",
    "    run_logged([CARGO, \"test\", \"--locked\", \"--workspace\"],\n",
    "               \"full_rust_tests\", cwd=OPT, env=TEST_ENV, timeout=3600)\n",
    "    run_logged([PYTHON, \"-m\", \"pytest\", \"--import-mode=importlib\", OPT/\"tests\", \"-q\", \"--timeout=120\"],\n",
    "               \"full_python_project_tests\", cwd=ROOT, env=TEST_ENV, timeout=3600)\n",
    "print(\"All requested compiled-extension and Python test commands passed.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a9a5e4e",
   "metadata": {
    "id": "2a9a5e4e"
   },
   "source": [
    "### 6. Write the editable experiment modules\n",
    "\n",
    "The notebook contains every script. Expanded cells below write ordinary\n",
    "Python source; the downloaded bundle also includes the same readable `.py`\n",
    "files. `legacy_adapter.py` preserves the earlier gate definitions and backend\n",
    "setup. `experiment_core.py` adds native competitor batching, Qulacs, QFT and\n",
    "independent state/observable references. No simulator result is replaced by\n",
    "a reference implementation when a backend fails."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29c89ffb",
   "metadata": {
    "id": "29c89ffb"
   },
   "source": [
    "#### Matched original gates and backend setup\n",
    "\n",
    "Open this source cell to inspect or modify `legacy_adapter.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "2e919ca1",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "2e919ca1",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "871256ea-104f-4c27-fa47-3124008f644b"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote legacy_adapter.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Fresh-process CPU benchmarks. No simulator fallbacks or fabricated results.\"\"\"\n",
    "\n",
    "import json\n",
    "import os\n",
    "from pathlib import Path\n",
    "try:\n",
    "    import resource\n",
    "except ImportError:  # Windows: no resource module; psutil fallbacks below\n",
    "    resource = None\n",
    "import sys\n",
    "import time\n",
    "import traceback\n",
    "from types import SimpleNamespace\n",
    "\n",
    "import numpy as np\n",
    "from sklearn.metrics import accuracy_score, balanced_accuracy_score, f1_score, roc_auc_score\n",
    "from sklearn.svm import SVC\n",
    "\n",
    "MEMORY_DISCOVERY_SOURCE = \"backend_default\"\n",
    "\n",
    "\n",
    "def aer_simulator_class():\n",
    "    \"\"\"Supply real OS memory metadata when a sandbox omits procfs.\n",
    "\n",
    "    This changes import-time memory discovery only. The Aer simulator and its\n",
    "    numerical kernels are unmodified; explicit thread and memory limits apply.\n",
    "    \"\"\"\n",
    "    global MEMORY_DISCOVERY_SOURCE\n",
    "    if os.name == \"nt\":\n",
    "        # Windows exposes real physical-memory metadata through psutil directly.\n",
    "        import psutil\n",
    "        from qiskit_aer import AerSimulator\n",
    "        MEMORY_DISCOVERY_SOURCE = \"psutil.virtual_memory.total (Windows)\"\n",
    "        return AerSimulator\n",
    "    if Path(\"/proc/meminfo\").exists():\n",
    "        from qiskit_aer import AerSimulator\n",
    "        return AerSimulator\n",
    "    import psutil\n",
    "    total = os.sysconf(\"SC_PHYS_PAGES\") * os.sysconf(\"SC_PAGE_SIZE\")\n",
    "    if total <= 0:\n",
    "        raise RuntimeError(\"operating system physical-memory metadata is unavailable\")\n",
    "    original = psutil.virtual_memory\n",
    "    psutil.virtual_memory = lambda: SimpleNamespace(total=total)\n",
    "    try:\n",
    "        from qiskit_aer import AerSimulator\n",
    "    finally:\n",
    "        psutil.virtual_memory = original\n",
    "    MEMORY_DISCOVERY_SOURCE = \"os.sysconf physical pages (procfs absent; import metadata only)\"\n",
    "    return AerSimulator\n",
    "\n",
    "\n",
    "def clock():\n",
    "    return time.perf_counter()\n",
    "\n",
    "\n",
    "def rss_mb():\n",
    "    # Linux lanes read current resident pages without a sampling thread;\n",
    "    # Windows reads current RSS through psutil.\n",
    "    if os.name == \"nt\":\n",
    "        import psutil\n",
    "        return psutil.Process().memory_info().rss/2**20\n",
    "    try:\n",
    "        pages = int(Path(\"/proc/self/statm\").read_text().split()[1])\n",
    "        return pages*os.sysconf(\"SC_PAGE_SIZE\")/2**20\n",
    "    except FileNotFoundError:\n",
    "        # Restricted offline test environments may omit procfs. This fallback\n",
    "        # is a high-water mark, not current RSS; the result records that fact.\n",
    "        if resource is not None:\n",
    "            return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/1024\n",
    "        import psutil\n",
    "        return psutil.Process().memory_info().rss/2**20\n",
    "\n",
    "\n",
    "def canonical(vector, n, msb=False):\n",
    "    vector = np.asarray(vector, dtype=np.complex128)\n",
    "    if msb:\n",
    "        vector = vector.reshape([2] * n).transpose(tuple(reversed(range(n)))).reshape(-1)\n",
    "    return vector\n",
    "\n",
    "\n",
    "def mean_z_weights(n):\n",
    "    indices = np.arange(1 << n, dtype=np.uint32)\n",
    "    counts = np.zeros(len(indices), dtype=np.uint8)\n",
    "    for q in range(n):\n",
    "        counts += ((indices >> q) & 1).astype(np.uint8)\n",
    "    return (n - 2.0 * counts) / n\n",
    "\n",
    "\n",
    "def fidelity_matrix(a, b=None, block_rows=4):\n",
    "    b = a if b is None else b\n",
    "    result = np.empty((len(a), len(b)))\n",
    "    for start in range(0, len(a), block_rows):\n",
    "        result[start:start + block_rows] = np.abs(a[start:start + block_rows].conj() @ b.T)**2\n",
    "    return result\n",
    "\n",
    "\n",
    "def metrics(y, prediction, score):\n",
    "    result = {\"accuracy\": float(accuracy_score(y, prediction)),\n",
    "              \"balanced_accuracy\": float(balanced_accuracy_score(y, prediction)),\n",
    "              \"f1\": float(f1_score(y, prediction, zero_division=0))}\n",
    "    result[\"roc_auc\"] = float(roc_auc_score(y, score)) if len(np.unique(y)) > 1 else None\n",
    "    return result\n",
    "\n",
    "\n",
    "def feature_spec(n, name, layers=0):\n",
    "    operations = []\n",
    "    def add(gate, wires, key=None):\n",
    "        operations.append((gate, wires, key))\n",
    "    if name == \"angle\":\n",
    "        for q in range(n): add(\"RY\", [q], f\"x{q}\")\n",
    "        for q in range(n-1): add(\"CX\", [q, q+1])\n",
    "    elif name == \"phase\":\n",
    "        for q in range(n): add(\"H\", [q])\n",
    "        for q in range(n): add(\"P\", [q], f\"x{q}\")\n",
    "        for q in range(n-1): add(\"CX\", [q, q+1])\n",
    "        for q in range(n): add(\"H\", [q])\n",
    "    elif name == \"pauli\":\n",
    "        for q in range(n):\n",
    "            add(\"RX\", [q], f\"x{q}\"); add(\"RZ\", [q], f\"x{q}\")\n",
    "        for q in range(n-1): add(\"CX\", [q, q+1])\n",
    "    elif name == \"zz\":\n",
    "        for q in range(n): add(\"H\", [q])\n",
    "        for q in range(n): add(\"RZ\", [q], f\"x{q}\")\n",
    "        for q in range(n-1):\n",
    "            add(\"CX\", [q, q+1]); add(\"RZ\", [q+1], f\"zz{q}\"); add(\"CX\", [q, q+1])\n",
    "        for q in range(n): add(\"H\", [q])\n",
    "    elif name == \"basis\":\n",
    "        add(\"X\", [0])\n",
    "    else:\n",
    "        raise ValueError(name)\n",
    "    for layer in range(layers):\n",
    "        for q in range(n):\n",
    "            add(\"RY\", [q], f\"t{layer*2*n+2*q}\")\n",
    "            add(\"RZ\", [q], f\"t{layer*2*n+2*q+1}\")\n",
    "        for q in range(n-1): add(\"CX\", [q, q+1])\n",
    "    return operations\n",
    "\n",
    "\n",
    "def feature_values(x, name=\"angle\", theta=None):\n",
    "    result = {} if name == \"basis\" else {f\"x{q}\": float(value) for q, value in enumerate(x)}\n",
    "    if name == \"zz\": result.update({f\"zz{q}\": float(x[q]*x[q+1]) for q in range(len(x)-1)})\n",
    "    if theta is not None: result.update({f\"t{q}\": float(value) for q, value in enumerate(theta)})\n",
    "    return result\n",
    "\n",
    "\n",
    "def mean_z_terms(n):\n",
    "    terms = []\n",
    "    for q in range(n):\n",
    "        pauli = [0]*n; pauli[q] = 3\n",
    "        terms.append((pauli, 1/n))\n",
    "    return terms\n",
    "\n",
    "\n",
    "def qubo_ising(a, b, constant):\n",
    "    h = -a/2 - b.sum(axis=1)/4\n",
    "    pairs = [(i, j, float(b[i, j]/4)) for i in range(len(a)) for j in range(i+1, len(a)) if abs(b[i, j]) > 1e-15]\n",
    "    offset = float(constant + a.sum()/2 + np.triu(b, 1).sum()/4)\n",
    "    return h, pairs, offset\n",
    "\n",
    "\n",
    "def qaoa_spec(n, pairs):\n",
    "    operations = [(\"H\", [q], None) for q in range(n)]\n",
    "    operations += [(\"RZ\", [q], f\"z{q}\") for q in range(n)]\n",
    "    for p, (i, j, _) in enumerate(pairs):\n",
    "        operations += [(\"CX\", [i, j], None), (\"RZ\", [j], f\"j{p}\"), (\"CX\", [i, j], None)]\n",
    "    return operations + [(\"RX\", [q], f\"b{q}\") for q in range(n)]\n",
    "\n",
    "\n",
    "def qaoa_values(n, h, pairs, gamma, beta):\n",
    "    return {**{f\"z{q}\": float(2*gamma*h[q]) for q in range(n)},\n",
    "            **{f\"j{p}\": float(2*gamma*v) for p, (_, _, v) in enumerate(pairs)},\n",
    "            **{f\"b{q}\": float(2*beta) for q in range(n)}}\n",
    "\n",
    "\n",
    "def ising_terms(n, h, pairs, offset):\n",
    "    result = [([0]*n, offset)]\n",
    "    for q in range(n):\n",
    "        pauli = [0]*n; pauli[q] = 3; result.append((pauli, float(h[q])))\n",
    "    for i, j, value in pairs:\n",
    "        pauli = [0]*n; pauli[i] = pauli[j] = 3; result.append((pauli, value))\n",
    "    return result\n",
    "\n",
    "\n",
    "class Adapter:\n",
    "    \"\"\"Matched logical gates, explicit output contracts, canonical q0=LSB states.\"\"\"\n",
    "\n",
    "    def __init__(self, framework, n, operations, output=\"state\", terms=None, weights=None):\n",
    "        self.framework, self.n, self.operations, self.output = framework, n, operations, output\n",
    "        self.optimized = framework == \"superfermion_optimized\"\n",
    "        self.kind = \"superfermion\" if framework.startswith(\"superfermion\") else (\"cirq\" if framework == \"cirq_f64\" else framework)\n",
    "        self.terms, self.weights = terms, weights\n",
    "        self.keys = list(dict.fromkeys(key for _, _, key in operations if key is not None))\n",
    "        self.calls = 0; self.execute_s = 0.\n",
    "        if self.kind == \"superfermion\":\n",
    "            import superfermion as sf\n",
    "            self.sf = sf\n",
    "            self.template = sf.Circuit(n)\n",
    "            for gate, wires, key in operations:\n",
    "                method = getattr(self.template, gate.lower())\n",
    "                method(sf.param(key), *wires) if key is not None else method(*wires)\n",
    "            if self.optimized:\n",
    "                self.prepared = sf.prepare(self.template)\n",
    "                if output == \"qubo\": self.diagonal = sf.DiagonalObservable(np.asarray(weights).tolist())\n",
    "            self.precision = \"complex128\"; self.backend = \"superfermion-rust-cpu\"\n",
    "        elif self.kind == \"qiskit\":\n",
    "            from qiskit import QuantumCircuit\n",
    "            from qiskit.circuit import Parameter\n",
    "            from qiskit.quantum_info import SparsePauliOp\n",
    "            AerSimulator = aer_simulator_class()\n",
    "            self.backend_object = AerSimulator(method=\"statevector\", precision=\"double\",\n",
    "                max_parallel_threads=int(os.environ[\"SIM_THREADS\"]), max_parallel_experiments=1,\n",
    "                max_memory_mb=512)\n",
    "            self.symbols = {key: Parameter(key) for key in self.keys}\n",
    "            self.template = QuantumCircuit(n)\n",
    "            for gate, wires, key in operations:\n",
    "                method = getattr(self.template, gate.lower())\n",
    "                method(self.symbols[key], *wires) if key is not None else method(*wires)\n",
    "            if output == \"state\": self.template.save_statevector()\n",
    "            else:\n",
    "                strings = [(\"\".join(\"IXYZ\"[p] for p in reversed(pauli)), coefficient) for pauli, coefficient in terms]\n",
    "                self.template.save_expectation_value(SparsePauliOp.from_list(strings), list(range(n)), label=\"readout\")\n",
    "            self.precision = \"complex128\"; self.backend = \"qiskit-aer-statevector\"\n",
    "        elif self.kind == \"cirq\":\n",
    "            import cirq\n",
    "            import sympy\n",
    "            self.cirq = cirq; self.qubits = cirq.LineQubit.range(n)\n",
    "            self.symbols = {key: sympy.Symbol(key) for key in self.keys}\n",
    "            gates = []\n",
    "            for gate, wires, key in operations:\n",
    "                q = [self.qubits[w] for w in wires]\n",
    "                if gate == \"CX\": operation = cirq.CNOT(*q)\n",
    "                elif gate == \"H\": operation = cirq.H(*q)\n",
    "                elif gate == \"X\": operation = cirq.X(*q)\n",
    "                elif gate == \"P\": operation = cirq.ZPowGate(exponent=self.symbols[key]/np.pi, global_shift=0).on(*q)\n",
    "                else: operation = getattr(cirq, gate.lower())(self.symbols[key]).on(*q)\n",
    "                gates.append(operation)\n",
    "            self.template = cirq.Circuit(gates)\n",
    "            if framework == \"cirq_f64\":\n",
    "                self.simulator = cirq.Simulator(dtype=np.complex128)\n",
    "            else:\n",
    "                import qsimcirq\n",
    "                self.simulator = qsimcirq.QSimSimulator(\n",
    "                    qsim_options=qsimcirq.QSimOptions(cpu_threads=int(os.environ[\"SIM_THREADS\"])))\n",
    "            if output != \"state\":\n",
    "                pauli_operators = [None, cirq.X, cirq.Y, cirq.Z]\n",
    "                strings = [cirq.PauliString({self.qubits[q]: pauli_operators[p] for q, p in enumerate(pauli) if p},\n",
    "                                            coefficient=coefficient) for pauli, coefficient in terms]\n",
    "                self.observable = cirq.PauliSum.from_pauli_strings(strings)\n",
    "            self.precision = \"complex128\" if framework == \"cirq_f64\" else \"complex64\"\n",
    "            self.backend = \"cirq-simulator-f64\" if framework == \"cirq_f64\" else \"cirq-qsim\"\n",
    "        elif self.kind == \"pennylane\":\n",
    "            import pennylane as qml\n",
    "            self.device = qml.device(\"lightning.qubit\", wires=n, c_dtype=np.complex128)\n",
    "            observable = None\n",
    "            if output != \"state\":\n",
    "                coefficients, operators = [], []\n",
    "                for pauli, coefficient in terms:\n",
    "                    factors = [getattr(qml, {1: \"PauliX\", 2: \"PauliY\", 3: \"PauliZ\"}[p])(wires=q)\n",
    "                               for q, p in enumerate(pauli) if p]\n",
    "                    operator = qml.prod(*factors) if len(factors) > 1 else (factors[0] if factors else qml.Identity(wires=0))\n",
    "                    coefficients.append(coefficient); operators.append(operator)\n",
    "                observable = qml.Hamiltonian(coefficients, operators)\n",
    "            methods = {\"H\": qml.Hadamard, \"X\": qml.PauliX, \"CX\": qml.CNOT,\n",
    "                       \"RY\": qml.RY, \"RX\": qml.RX, \"RZ\": qml.RZ, \"P\": qml.PhaseShift}\n",
    "            @qml.qnode(self.device, interface=None, diff_method=None)\n",
    "            def qnode(values):\n",
    "                for gate, wires, key in operations:\n",
    "                    methods[gate](values[key], wires=wires) if key is not None else methods[gate](wires=wires)\n",
    "                return qml.state() if output == \"state\" else qml.expval(observable)\n",
    "            self.qnode = qnode\n",
    "            self.precision = \"complex128\"; self.backend = \"pennylane-lightning.qubit\"\n",
    "        else:\n",
    "            raise ValueError(framework)\n",
    "\n",
    "    def reset(self):\n",
    "        self.calls = 0; self.execute_s = 0.\n",
    "\n",
    "    def state(self, values):\n",
    "        if self.output != \"state\": raise ValueError(\"this adapter returns native readouts\")\n",
    "        start = clock()\n",
    "        if self.kind == \"superfermion\":\n",
    "            if self.optimized: result = np.asarray(self.prepared.states_batch([values])[0])\n",
    "            else: result = np.asarray(self.template.bind(values).to_ir().simulate_to_state(\"statevector\", \"cpu\").numpy())\n",
    "        elif self.kind == \"qiskit\":\n",
    "            circuit = self.template.assign_parameters({self.symbols[k]: v for k, v in values.items()})\n",
    "            execution = self.backend_object.run(circuit).result()\n",
    "            if not execution.success: raise RuntimeError(str(execution))\n",
    "            result = canonical(execution.get_statevector(circuit), self.n)\n",
    "        elif self.kind == \"cirq\":\n",
    "            circuit = self.cirq.resolve_parameters(self.template, values)\n",
    "            result = canonical(self.simulator.simulate(circuit, qubit_order=self.qubits).final_state_vector, self.n, msb=True)\n",
    "        else: result = canonical(self.qnode(values), self.n, msb=True)\n",
    "        self.calls += 1; self.execute_s += clock()-start\n",
    "        return result\n",
    "\n",
    "    def states(self, values):\n",
    "        if self.optimized and len(values)*(1 << self.n)*16 <= (1 << 30):\n",
    "            start = clock(); result = np.asarray(self.prepared.states_batch(values))\n",
    "            self.calls += len(values); self.execute_s += clock()-start\n",
    "            return result\n",
    "        # All ordinary backends use the same preallocated bank, not list+vstack.\n",
    "        result = np.empty((len(values), 1 << self.n), dtype=np.complex128)\n",
    "        for row, parameters in enumerate(values): result[row] = self.state(parameters)\n",
    "        return result\n",
    "\n",
    "    def readouts(self, values):\n",
    "        if self.output == \"state\": raise ValueError(\"use the common readout on returned vectors\")\n",
    "        start = clock()\n",
    "        if self.optimized:\n",
    "            result = (self.prepared.mean_z_batch(values) if self.output == \"mean_z\"\n",
    "                      else self.prepared.diagonal_batch(values, self.diagonal))\n",
    "        else:\n",
    "            result = []\n",
    "            for parameters in values:\n",
    "                if self.kind == \"superfermion\":\n",
    "                    state = self.template.bind(parameters).to_ir().simulate_to_state(\"statevector\", \"cpu\")\n",
    "                    value = state.expectation([(pauli, coefficient, 0.) for pauli, coefficient in self.terms])\n",
    "                elif self.kind == \"qiskit\":\n",
    "                    circuit = self.template.assign_parameters({self.symbols[k]: v for k, v in parameters.items()})\n",
    "                    execution = self.backend_object.run(circuit).result()\n",
    "                    if not execution.success: raise RuntimeError(str(execution))\n",
    "                    value = execution.data(0)[\"readout\"]\n",
    "                elif self.kind == \"cirq\":\n",
    "                    circuit = self.cirq.resolve_parameters(self.template, parameters)\n",
    "                    value = self.simulator.simulate_expectation_values(circuit, observables=[self.observable], qubit_order=self.qubits)[0]\n",
    "                else: value = self.qnode(parameters)\n",
    "                result.append(float(np.real(value)))\n",
    "        self.calls += len(values); self.execute_s += clock()-start\n",
    "        return np.asarray(result, dtype=float)\n",
    "\n",
    "\n",
    "def report_kernel(config, analytical=False):\n",
    "    data = np.load(config[\"data_path\"])\n",
    "    task, n = config[\"task\"], config[\"n_qubits\"]\n",
    "    if task == \"qsvm\": x, y = data[\"X_train\"], data[\"X_test\"]\n",
    "    else: x, y = data[\"X_batch\"], None\n",
    "    adapter = None\n",
    "    if analytical:\n",
    "        from superfermion.kernels import angle_fidelity_kernel\n",
    "        angle_fidelity_kernel(x[:1], x[:1])\n",
    "    else:\n",
    "        adapter = Adapter(config[\"framework\"], n, feature_spec(n, \"angle\"))\n",
    "        adapter.state(feature_values(x[0])); adapter.reset()\n",
    "    baseline_rss = int(rss_mb()*2**20)\n",
    "    start = clock()\n",
    "    if analytical:\n",
    "        ktrain = angle_fidelity_kernel(x)\n",
    "        ktest = angle_fidelity_kernel(y, x) if y is not None else None\n",
    "    else:\n",
    "        sx = adapter.states([feature_values(row) for row in x])\n",
    "        sy = adapter.states([feature_values(row) for row in y]) if y is not None else None\n",
    "        ktrain = fidelity_matrix(sx, block_rows=config[\"kernel_block_rows\"])\n",
    "        ktest = fidelity_matrix(sy, sx, config[\"kernel_block_rows\"]) if y is not None else None\n",
    "    primary = clock()-start\n",
    "    result = {\"primary_runtime_s\": primary, \"kernel_probe\": ktrain[:8, :8].tolist(),\n",
    "              \"kernel_trace\": float(np.trace(ktrain)), \"rss_postwarmup_mb\": baseline_rss/2**20}\n",
    "    if task == \"qsvm\":\n",
    "        start = clock(); model = SVC(kernel=\"precomputed\", random_state=config[\"seed\"])\n",
    "        model.fit(ktrain, data[\"y_train\"])\n",
    "        predictions = model.predict(ktest); scores = model.decision_function(ktest)\n",
    "        result.update(metrics(data[\"y_test\"], predictions, scores))\n",
    "        result.update(end_to_end_s=primary+clock()-start, predictions=predictions.tolist(), scores=scores.tolist())\n",
    "    else:\n",
    "        start = clock(); count = len(x); centering = np.eye(count)-np.ones((count, count))/count\n",
    "        eigenvalues = np.sort(np.linalg.eigvalsh(centering @ ktrain @ centering))[::-1]\n",
    "        result.update(end_to_end_s=primary+clock()-start, eigenvalues=eigenvalues.tolist())\n",
    "    if adapter: result.update(backend=adapter.backend, internal_precision=adapter.precision,\n",
    "                              circuit_evaluations=adapter.calls, circuit_execution_s=adapter.execute_s)\n",
    "    else: result.update(backend=\"analytical-angle\", internal_precision=\"float64\", circuit_evaluations=0)\n",
    "    return result\n",
    "\n",
    "\n",
    "def report_feature(config):\n",
    "    n, name = config[\"n_qubits\"], config[\"feature_map\"]\n",
    "    x = np.load(config[\"data_path\"])[\"X_batch\"]\n",
    "    adapter = Adapter(config[\"framework\"], n, feature_spec(n, name))\n",
    "    adapter.state(feature_values(x[0], name)); adapter.reset()\n",
    "    baseline = rss_mb()\n",
    "    start = clock(); vectors = adapter.states([feature_values(row, name) for row in x]); total = clock()-start\n",
    "    # Identical validation on every lane, explicitly outside primary timing.\n",
    "    norms = np.sum(np.abs(vectors)**2, axis=1)\n",
    "    return {\"primary_runtime_s\": total, \"end_to_end_s\": total, \"backend\": adapter.backend,\n",
    "            \"internal_precision\": adapter.precision, \"max_norm_error\": float(np.max(np.abs(norms-1))),\n",
    "            \"circuit_evaluations\": adapter.calls, \"circuit_execution_s\": adapter.execute_s,\n",
    "            \"rss_postwarmup_mb\": baseline, \"batch_size\": len(x)}\n",
    "\n",
    "\n",
    "def report_vqc(config):\n",
    "    data = np.load(config[\"data_path\"]); n = config[\"n_qubits\"]\n",
    "    x, y, xt, yt = data[\"X_train\"], data[\"y_train\"], data[\"X_test\"], data[\"y_test\"]\n",
    "    native = config[\"track\"] == \"native_readout\"\n",
    "    weights = mean_z_weights(n)  # Cached once, for all common-readout lanes.\n",
    "    adapter = Adapter(config[\"framework\"], n, feature_spec(n, \"angle\", config[\"vqc_layers\"]),\n",
    "                      \"mean_z\" if native else \"state\", mean_z_terms(n))\n",
    "    rng = np.random.default_rng(config[\"seed\"]); theta = rng.normal(0, .05, 2*n*config[\"vqc_layers\"])\n",
    "    def predict(values, rows):\n",
    "        parameters = [feature_values(row, theta=values) for row in rows]\n",
    "        means = adapter.readouts(parameters) if native else np.abs(adapter.states(parameters))**2 @ weights\n",
    "        return np.clip((1-means)/2, 1e-8, 1-1e-8)\n",
    "    def loss(values, indices):\n",
    "        probabilities = predict(values, x[indices]); labels = y[indices]\n",
    "        return float(-np.mean(labels*np.log(probabilities)+(1-labels)*np.log(1-probabilities)))\n",
    "    predict(theta, x[:1]); adapter.reset()\n",
    "    baseline = rss_mb()\n",
    "    batch = min(config[\"vqc_batch\"], len(y)); fixed = np.arange(batch)\n",
    "    start = clock(); initial = loss(theta, fixed)\n",
    "    for iteration in range(config[\"vqc_iterations\"]):\n",
    "        indices = rng.choice(len(y), batch, replace=False); delta = rng.choice([-1., 1.], len(theta))\n",
    "        rate = .08/(iteration+1)**.602; step = .05/(iteration+1)**.101\n",
    "        plus, minus = loss(theta+step*delta, indices), loss(theta-step*delta, indices)\n",
    "        theta -= rate*(plus-minus)/(2*step)*delta\n",
    "    score = predict(theta, xt); final = loss(theta, fixed); total = clock()-start\n",
    "    return {**metrics(yt, (score >= .5).astype(int), score), \"primary_runtime_s\": total,\n",
    "            \"end_to_end_s\": total, \"initial_loss\": initial, \"final_loss\": final,\n",
    "            \"scores\": score.tolist(), \"parameters\": theta.tolist(), \"backend\": adapter.backend,\n",
    "            \"internal_precision\": adapter.precision, \"circuit_evaluations\": adapter.calls,\n",
    "            \"circuit_execution_s\": adapter.execute_s, \"rss_postwarmup_mb\": baseline}\n",
    "\n",
    "\n",
    "def report_qaoa(config):\n",
    "    data = np.load(config[\"qubo_path\"]); n = config[\"n_qubits\"]\n",
    "    h, pairs, offset = qubo_ising(data[\"a\"], data[\"B\"], float(data[\"const\"]))\n",
    "    cost, cards, k = data[\"costvec\"], data[\"cards\"].astype(np.int32), int(data[\"select_k\"])\n",
    "    native = config[\"track\"] == \"native_readout\"\n",
    "    operations = qaoa_spec(n, pairs)\n",
    "    adapter = Adapter(config[\"framework\"], n, operations, \"qubo\" if native else \"state\",\n",
    "                      ising_terms(n, h, pairs, offset), cost)\n",
    "    state_adapter = Adapter(config[\"framework\"], n, operations) if native else adapter\n",
    "    def energy(parameters):\n",
    "        values = qaoa_values(n, h, pairs, *parameters)\n",
    "        return float(adapter.readouts([values])[0] if native else np.dot(np.abs(adapter.state(values))**2, cost))\n",
    "    parameters = np.array([.4, .3]); energy(parameters)\n",
    "    state_adapter.state(qaoa_values(n, h, pairs, *parameters))\n",
    "    adapter.reset(); state_adapter.reset()\n",
    "    baseline = rss_mb()\n",
    "    rng = np.random.default_rng(config[\"seed\"])\n",
    "    start = clock(); initial = energy(parameters)\n",
    "    for iteration in range(config[\"qaoa_iterations\"]):\n",
    "        delta = rng.choice([-1., 1.], 2); rate = .12/(iteration+1)**.602; step = .08/(iteration+1)**.101\n",
    "        plus, minus = energy(parameters+step*delta), energy(parameters-step*delta)\n",
    "        parameters -= rate*(plus-minus)/(2*step)*delta\n",
    "    probabilities = np.abs(state_adapter.state(qaoa_values(n, h, pairs, *parameters)))**2\n",
    "    final = float(np.dot(probabilities, cost))\n",
    "    primary = clock()-start\n",
    "    # Feasible-mode selection and reference are application work, timed separately.\n",
    "    start = clock(); feasible = np.flatnonzero(cards == k); raw = int(np.argmax(probabilities))\n",
    "    selected = int(feasible[np.argmax(probabilities[feasible])]); optimal = float(cost[feasible].min())\n",
    "    return {\"primary_runtime_s\": primary, \"end_to_end_s\": primary+clock()-start,\n",
    "            \"initial_energy\": initial, \"final_energy\": final, \"parameters\": parameters.tolist(),\n",
    "            \"raw_cardinality_error\": int(abs(int(cards[raw])-k)), \"postselected_cost\": float(cost[selected]),\n",
    "            \"optimal_feasible_energy\": optimal, \"postselected_gap\": float(cost[selected]-optimal),\n",
    "            \"feasible_probability\": float(probabilities[feasible].sum()), \"backend\": adapter.backend,\n",
    "            \"internal_precision\": adapter.precision, \"circuit_evaluations\": adapter.calls+(state_adapter.calls if native else 0),\n",
    "            \"circuit_execution_s\": adapter.execute_s+(state_adapter.execute_s if native else 0),\n",
    "            \"rss_postwarmup_mb\": baseline}\n",
    "\n",
    "\n",
    "def report_validation(config):\n",
    "    n = config[\"n_qubits\"]; rng = np.random.default_rng(2041+n)\n",
    "    x = rng.uniform(-1.4, 1.4, n); theta = rng.normal(0, .2, 2*n)\n",
    "    probes = np.unique(np.r_[0, 1, (1 << (n-1)), (1 << n)-1,\n",
    "                             rng.integers(0, 1 << n, size=min(64, 1 << n))])\n",
    "    if n <= 8: probes = np.arange(1 << n)\n",
    "    weights = mean_z_weights(n); cases = []\n",
    "    def record(name, vector, native=None, cost=None):\n",
    "        values = vector[probes]\n",
    "        row = {\"case\": name, \"probe_indices\": probes.tolist(), \"vector_re\": values.real.tolist(),\n",
    "               \"vector_im\": values.imag.tolist(), \"norm\": float(np.vdot(vector, vector).real),\n",
    "               \"mean_z\": float(np.dot(np.abs(vector)**2, weights))}\n",
    "        if cost is not None:\n",
    "            row.update(energy=float(np.dot(np.abs(vector)**2, cost)), energy_scale=float(max(1., np.max(np.abs(cost)))))\n",
    "        if native is not None: row[\"native_value\"] = float(native)\n",
    "        cases.append(row)\n",
    "    for name in [\"angle\", \"phase\", \"pauli\", \"zz\", \"basis\"]:\n",
    "        adapter = Adapter(config[\"framework\"], n, feature_spec(n, name))\n",
    "        record(name, adapter.state(feature_values(x, name)))\n",
    "    state_adapter = Adapter(config[\"framework\"], n, feature_spec(n, \"angle\", 1))\n",
    "    native_adapter = Adapter(config[\"framework\"], n, feature_spec(n, \"angle\", 1), \"mean_z\", mean_z_terms(n))\n",
    "    values = feature_values(x, theta=theta)\n",
    "    record(\"vqc\", state_adapter.state(values), native_adapter.readouts([values])[0])\n",
    "    data = np.load(config[\"qubo_path\"])\n",
    "    h, pairs, offset = qubo_ising(data[\"a\"], data[\"B\"], float(data[\"const\"]))\n",
    "    operations = qaoa_spec(n, pairs)\n",
    "    state_adapter = Adapter(config[\"framework\"], n, operations)\n",
    "    native_adapter = Adapter(config[\"framework\"], n, operations, \"qubo\", ising_terms(n, h, pairs, offset), data[\"costvec\"])\n",
    "    for p, parameters in enumerate([(.11, .23), (.4, .3), (-.53, .17)]):\n",
    "        values = qaoa_values(n, h, pairs, *parameters)\n",
    "        record(f\"qaoa_fixed_{p}\", state_adapter.state(values), native_adapter.readouts([values])[0], data[\"costvec\"])\n",
    "    return {\"cases\": cases, \"internal_precision\": state_adapter.precision,\n",
    "            \"backend\": state_adapter.backend, \"primary_runtime_s\": None}\n",
    "\n",
    "\n",
    "def main(config_path, output_path):\n",
    "    config = json.loads(Path(config_path).read_text())\n",
    "    result = {key: config.get(key) for key in [\"job_id\", \"cache_key\", \"task\", \"track\", \"framework\", \"dataset\",\n",
    "                                             \"n_qubits\", \"feature_map\", \"repetition\", \"threads\", \"seed\", \"manifest_sha256\"]}\n",
    "    start = clock()\n",
    "    try:\n",
    "        if config[\"task\"] == \"validation\": measurement = report_validation(config)\n",
    "        elif config[\"task\"] in [\"qsvm\", \"qkpca\"]: measurement = report_kernel(config, config[\"framework\"] == \"analytical_angle\")\n",
    "        elif config[\"task\"] == \"feature_map\": measurement = report_feature(config)\n",
    "        elif config[\"task\"] == \"vqc\": measurement = report_vqc(config)\n",
    "        elif config[\"task\"] == \"qaoa_fs\": measurement = report_qaoa(config)\n",
    "        else: raise ValueError(config[\"task\"])\n",
    "        result.update(measurement); result[\"status\"] = \"ok\"\n",
    "    except Exception as error:\n",
    "        result.update(status=\"error\", error_type=type(error).__name__, error=str(error), traceback=traceback.format_exc())\n",
    "    result[\"worker_wall_s\"] = clock()-start\n",
    "    if resource is not None:\n",
    "        result[\"process_peak_rss_mb\"] = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/1024\n",
    "    else:\n",
    "        import psutil\n",
    "        result[\"process_peak_rss_mb\"] = psutil.Process().memory_info().peak_wset/2**20\n",
    "    result[\"rss_after_task_mb\"] = rss_mb()\n",
    "    result[\"current_rss_source\"] = (\"procfs\" if Path(\"/proc/self/statm\").exists()\n",
    "        else (\"psutil peak_wset (Windows)\" if os.name == \"nt\" else \"process high-water fallback\"))\n",
    "    result[\"backend_memory_discovery\"] = MEMORY_DISCOVERY_SOURCE\n",
    "    path = Path(output_path); temporary = path.with_suffix(\".tmp\")\n",
    "    temporary.write_text(json.dumps(result, indent=2, allow_nan=False)); temporary.replace(path)\n",
    "    print(json.dumps({\"job_id\": result[\"job_id\"], \"status\": result[\"status\"]}))\n",
    "    if result[\"status\"] != \"ok\": raise SystemExit(1)\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\": main(*sys.argv[1:])\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'legacy_adapter.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote legacy_adapter.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "516225c6",
   "metadata": {
    "id": "516225c6"
   },
   "source": [
    "#### Native batch adapters and independent references\n",
    "\n",
    "Open this source cell to inspect or modify `experiment_core.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "777a495c",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "777a495c",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "e886b550-9411-46ee-8b15-05ddedef2277"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote experiment_core.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Matched CPU adapters and independent numerical references for the study.\"\"\"\n",
    "import os\n",
    "import time\n",
    "import numpy as np\n",
    "\n",
    "from legacy_adapter import (Adapter as LegacyAdapter, feature_spec, feature_values,\n",
    "                            mean_z_terms, mean_z_weights, fidelity_matrix,\n",
    "                            ising_terms, canonical)\n",
    "\n",
    "\n",
    "def canonical_bank(vectors, n, msb=False):\n",
    "    bank = np.asarray(vectors, dtype=np.complex128).reshape(-1, 1 << n)\n",
    "    if msb:\n",
    "        bank = bank.reshape(len(bank), *([2] * n)).transpose(0, *range(n, 0, -1)).reshape(len(bank), -1)\n",
    "    return np.ascontiguousarray(bank)\n",
    "\n",
    "\n",
    "class Adapter(LegacyAdapter):\n",
    "    \"\"\"Native batching where supported; actual simulator precision is retained.\"\"\"\n",
    "    def __init__(self, framework, n, operations, output=\"state\", terms=None, weights=None):\n",
    "        if framework != \"qulacs\":\n",
    "            super().__init__(framework, n, operations, output, terms, weights)\n",
    "        else:\n",
    "            from qulacs import ParametricQuantumCircuit, QuantumState, Observable\n",
    "            self.framework, self.kind, self.n = framework, framework, n\n",
    "            self.operations, self.output, self.terms, self.weights = operations, output, terms, weights\n",
    "            self.optimized = False\n",
    "            self.keys = list(dict.fromkeys(k for _, _, k in operations if k is not None))\n",
    "            self.calls, self.execute_s = 0, 0.\n",
    "            self.template = ParametricQuantumCircuit(n)\n",
    "            self.parameter_slots, self.phase_keys = [], []\n",
    "            for gate, wires, key in operations:\n",
    "                if key is None:\n",
    "                    getattr(self.template, \"add_\" + {\"CX\":\"CNOT\"}.get(gate, gate) + \"_gate\")(*wires)\n",
    "                else:\n",
    "                    # Qulacs rotates with exp(+i theta P/2). The common\n",
    "                    # convention is exp(-i theta P/2); convert every angle.\n",
    "                    axis = \"RZ\" if gate == \"P\" else gate\n",
    "                    getattr(self.template, \"add_parametric_\" + axis + \"_gate\")(*wires, 0.)\n",
    "                    self.parameter_slots.append(key)\n",
    "                    if gate == \"P\": self.phase_keys.append(key)\n",
    "            self.state_object = QuantumState(n)\n",
    "            if output != \"state\":\n",
    "                self.observable = Observable(n)\n",
    "                for pauli, coefficient in terms:\n",
    "                    text = \" \".join(f'{\"IXYZ\"[p]} {q}' for q, p in enumerate(pauli) if p) or \"I 0\"\n",
    "                    self.observable.add_operator(float(coefficient), text)\n",
    "            self.precision, self.backend = \"complex128\", \"qulacs-cpu-parametric\"\n",
    "        self.batch_strategy = {\n",
    "            \"superfermion_optimized\":\"PreparedCircuit.states_batch / native reductions\",\n",
    "            \"superfermion_wheel\":\"existing bind/to_ir/simulate loop\",\n",
    "            \"superfermion_source_baseline\":\"existing bind/to_ir/simulate loop\",\n",
    "            \"qiskit\":\"Aer runtime parameter_binds; single experiment thread budget\",\n",
    "            \"pennylane\":\"QNode broadcasting; Lightning expands broadcast tapes\",\n",
    "            \"cirq\":\"qsim simulate_sweep / expectation sweep\",\n",
    "            \"cirq_f64\":\"Cirq complex128 simulate_sweep / expectation sweep\",\n",
    "            \"qulacs\":\"reused ParametricQuantumCircuit and QuantumState; parameter update loop\",\n",
    "        }[framework]\n",
    "\n",
    "    def _qulacs_run(self, values):\n",
    "        for i, key in enumerate(self.parameter_slots):\n",
    "            self.template.set_parameter(i, -float(values[key]))\n",
    "        self.state_object.set_zero_state()\n",
    "        self.template.update_quantum_state(self.state_object)\n",
    "        if self.phase_keys:\n",
    "            # P(theta) = exp(i theta/2) RZ(theta); retain the global phase\n",
    "            # for a literal, fully matched statevector output contract.\n",
    "            self.state_object.multiply_coef(np.exp(.5j*sum(values[k] for k in self.phase_keys)))\n",
    "\n",
    "    def _aer_execute(self, values):\n",
    "        if self.keys:\n",
    "            binds = [{self.symbols[k]: [float(row[k]) for row in values] for k in self.keys}]\n",
    "            result = self.backend_object.run(self.template, parameter_binds=binds,\n",
    "                runtime_parameter_bind_enable=True).result()\n",
    "        else:\n",
    "            result = self.backend_object.run([self.template for _ in values]).result()\n",
    "        if not result.success or len(result.results) != len(values):\n",
    "            raise RuntimeError(\"Aer returned an unsuccessful or incomplete batch\")\n",
    "        return result\n",
    "\n",
    "    def states(self, values):\n",
    "        values = list(values)\n",
    "        if not values: return np.empty((0, 1 << self.n), dtype=np.complex128)\n",
    "        if self.output != \"state\": raise ValueError(\"statevector output required\")\n",
    "        start = time.perf_counter()\n",
    "        if self.kind == \"superfermion\":\n",
    "            if self.optimized:\n",
    "                result = np.asarray(self.prepared.states_batch(values))\n",
    "            else:\n",
    "                result = np.empty((len(values), 1 << self.n), dtype=np.complex128)\n",
    "                for i, row in enumerate(values):\n",
    "                    result[i] = self.template.bind(row).to_ir().simulate_to_state(\"statevector\", \"cpu\").numpy()\n",
    "        elif self.kind == \"qiskit\":\n",
    "            execution = self._aer_execute(values)\n",
    "            result = canonical_bank([execution.get_statevector(i) for i in range(len(values))], self.n)\n",
    "        elif self.kind == \"cirq\":\n",
    "            execution = self.simulator.simulate_sweep(self.template, params=values, qubit_order=self.qubits)\n",
    "            result = canonical_bank([row.final_state_vector for row in execution], self.n, msb=True)\n",
    "        elif self.kind == \"pennylane\":\n",
    "            if self.keys:\n",
    "                broadcast = {k: np.asarray([row[k] for row in values]) for k in self.keys}\n",
    "                result = canonical_bank(self.qnode(broadcast), self.n, msb=True)\n",
    "            else:\n",
    "                result = canonical_bank([self.qnode(row) for row in values], self.n, msb=True)\n",
    "        else:\n",
    "            result = np.empty((len(values), 1 << self.n), dtype=np.complex128)\n",
    "            for i, row in enumerate(values):\n",
    "                self._qulacs_run(row)\n",
    "                result[i] = self.state_object.get_vector()\n",
    "        self.calls += len(values); self.execute_s += time.perf_counter()-start\n",
    "        return result\n",
    "\n",
    "    def state(self, values):\n",
    "        return self.states([values])[0]\n",
    "\n",
    "    def readouts(self, values):\n",
    "        if self.output == \"state\": raise ValueError(\"native expectation output required\")\n",
    "        values = list(values)\n",
    "        start = time.perf_counter()\n",
    "        if self.kind == \"superfermion\":\n",
    "            if self.optimized and self.output == \"mean_z\":\n",
    "                result = self.prepared.mean_z_batch(values)\n",
    "            elif self.optimized and self.output == \"qubo\":\n",
    "                result = self.prepared.diagonal_batch(values, self.diagonal)\n",
    "            else:\n",
    "                result = []\n",
    "                for row in values:\n",
    "                    state = (self.prepared.simulate(row) if self.optimized else\n",
    "                             self.template.bind(row).to_ir().simulate_to_state(\"statevector\", \"cpu\"))\n",
    "                    result.append(state.expectation([(p, c, 0.) for p, c in self.terms]).real)\n",
    "        elif self.kind == \"qiskit\":\n",
    "            execution=self._aer_execute(values)\n",
    "            result = [execution.data(i)[\"readout\"] for i in range(len(values))]\n",
    "        elif self.kind == \"cirq\":\n",
    "            result = [row[0] for row in self.simulator.simulate_expectation_values_sweep(\n",
    "                self.template, observables=[self.observable], params=values, qubit_order=self.qubits)]\n",
    "        elif self.kind == \"pennylane\":\n",
    "            if self.keys:\n",
    "                result = self.qnode({k: np.asarray([row[k] for row in values]) for k in self.keys})\n",
    "            else:\n",
    "                result = [self.qnode(row) for row in values]\n",
    "        else:\n",
    "            result = []\n",
    "            for row in values:\n",
    "                self._qulacs_run(row)\n",
    "                result.append(self.observable.get_expectation_value(self.state_object))\n",
    "        self.calls += len(values); self.execute_s += time.perf_counter()-start\n",
    "        return np.real(np.asarray(result)).astype(float).reshape(-1)\n",
    "\n",
    "\n",
    "def reference_state(n, operations, values):\n",
    "    \"\"\"Independent NumPy state propagation, canonical qubit q = bit q.\"\"\"\n",
    "    state = np.zeros(1 << n, dtype=np.complex128); state[0] = 1\n",
    "    indices = np.arange(1 << n, dtype=np.uint64)\n",
    "    for gate, wires, key in operations:\n",
    "        if gate == \"CX\":\n",
    "            c, t = wires\n",
    "            state = state[indices ^ (((indices >> c) & 1) << t)]\n",
    "            continue\n",
    "        if gate == \"H\": matrix = np.array([[1,1],[1,-1]], complex)/np.sqrt(2)\n",
    "        elif gate == \"X\": matrix = np.array([[0,1],[1,0]], complex)\n",
    "        else:\n",
    "            theta = float(values[key]); c, s = np.cos(theta/2), np.sin(theta/2)\n",
    "            if gate == \"RY\": matrix = np.array([[c,-s],[s,c]], complex)\n",
    "            elif gate == \"RX\": matrix = np.array([[c,-1j*s],[-1j*s,c]], complex)\n",
    "            elif gate == \"RZ\": matrix = np.diag([np.exp(-.5j*theta), np.exp(.5j*theta)])\n",
    "            elif gate == \"P\": matrix = np.diag([1,np.exp(1j*theta)])\n",
    "            else: raise ValueError(gate)\n",
    "        q = wires[0]; stride = 1 << q\n",
    "        bank = state.reshape(-1, 2, stride)\n",
    "        lo, hi = bank[:,0,:].copy(), bank[:,1,:].copy()\n",
    "        bank[:,0,:] = matrix[0,0]*lo+matrix[0,1]*hi\n",
    "        bank[:,1,:] = matrix[1,0]*lo+matrix[1,1]*hi\n",
    "    return state\n",
    "\n",
    "\n",
    "def align_error(actual, expected):\n",
    "    overlap = np.vdot(expected, actual)\n",
    "    phase = overlap/abs(overlap) if abs(overlap) > 1e-20 else 1.\n",
    "    maximum = 0.\n",
    "    for start in range(0, len(actual), 1 << 18):\n",
    "        stop = start + (1 << 18)\n",
    "        maximum = max(maximum, float(np.max(np.abs(actual[start:stop]/phase-expected[start:stop]))))\n",
    "    return maximum\n",
    "\n",
    "\n",
    "def pauli_expectations(bank, terms, n):\n",
    "    \"\"\"Exact Pauli contractions with bounded basis-index temporaries.\"\"\"\n",
    "    bank = np.asarray(bank, dtype=np.complex128).reshape(-1, 1 << n)\n",
    "    result = np.zeros(len(bank), dtype=np.complex128)\n",
    "    for pauli, coefficient in terms:\n",
    "        flip = sum(1 << q for q,p in enumerate(pauli) if p in [1,2])\n",
    "        ys = sum(p == 2 for p in pauli)\n",
    "        sign_qubits = [q for q,p in enumerate(pauli) if p in [2,3]]\n",
    "        for start in range(0, 1 << n, 1 << 18):\n",
    "            stop = min(start + (1 << 18), 1 << n)\n",
    "            indices = np.arange(start, stop, dtype=np.uint64)\n",
    "            parity = np.zeros(len(indices), dtype=np.uint8)\n",
    "            for q in sign_qubits: parity ^= ((indices >> q) & 1).astype(np.uint8)\n",
    "            sign = 1. - 2.*parity\n",
    "            for row, vector in enumerate(bank):\n",
    "                value = np.vdot(vector[start:stop], vector[indices ^ flip]*sign)\n",
    "                result[row] += coefficient*((-1j)**ys)*value\n",
    "    if np.max(np.abs(result.imag)) > 1e-8: raise RuntimeError(\"observable is not Hermitian\")\n",
    "    return result.real\n",
    "\n",
    "\n",
    "def state_chunk_rows(n, budget_bytes, simultaneous_banks=1, row_cap=None):\n",
    "    \"\"\"Bound exported complex128 banks; backend workspaces are additional.\"\"\"\n",
    "    required = simultaneous_banks*(1 << n)*16\n",
    "    rows = int(budget_bytes)//required\n",
    "    if rows < 1:\n",
    "        raise MemoryError(f\"{simultaneous_banks} state(s) at {n} qubits need {required/2**20:.1f} MiB; output budget is {budget_bytes/2**20:.1f} MiB\")\n",
    "    return min(rows, int(row_cap)) if row_cap else rows\n",
    "\n",
    "\n",
    "def quantum_kernel_matrices(adapter, train_rows, test_rows, budget_bytes, block_rows=128):\n",
    "    \"\"\"Dense when affordable; otherwise exact kernels by re-encoding blocks.\n",
    "\n",
    "    Every simulator uses the same mode/block size for a condition. No state\n",
    "    bank is written to disk. The bounded mode trades additional simulation for\n",
    "    memory; its timing is not interchangeable with a retained-bank experiment.\n",
    "    \"\"\"\n",
    "    train_rows, test_rows = list(train_rows), list(test_rows)\n",
    "    nt, nv = len(train_rows), len(test_rows)\n",
    "    kt, kv = np.empty((nt, nt)), np.empty((nv, nt))\n",
    "    encoding, algebra, norm_error = 0., 0., 0.\n",
    "    def states(rows):\n",
    "        nonlocal encoding, norm_error\n",
    "        before = time.perf_counter(); bank = adapter.states(rows)\n",
    "        encoding += time.perf_counter()-before\n",
    "        if bank.shape != (len(rows), 1 << adapter.n) or not np.isfinite(bank).all():\n",
    "            raise ValueError(\"Invalid kernel state block\")\n",
    "        for vector in bank:\n",
    "            norm_error = max(norm_error, abs(float(np.vdot(vector, vector).real)-1.))\n",
    "        return bank\n",
    "    retained_bytes = (nt+nv)*(1 << adapter.n)*16\n",
    "    if retained_bytes <= budget_bytes:\n",
    "        left, right = states(train_rows), states(test_rows)\n",
    "        before = time.perf_counter()\n",
    "        kt[:] = fidelity_matrix(left, block_rows=8)\n",
    "        kv[:] = fidelity_matrix(right, left, block_rows=8)\n",
    "        algebra += time.perf_counter()-before\n",
    "        strategy, rows, peak_bytes = \"retained_state_bank\", nt+nv, retained_bytes\n",
    "    else:\n",
    "        rows = state_chunk_rows(adapter.n, budget_bytes, simultaneous_banks=2, row_cap=block_rows)\n",
    "        for i in range(0, nt, rows):\n",
    "            stop_i = min(i+rows, nt); left = states(train_rows[i:stop_i])\n",
    "            for j in range(i, nt, rows):\n",
    "                stop_j = min(j+rows, nt)\n",
    "                right = left if i == j else states(train_rows[j:stop_j])\n",
    "                before = time.perf_counter(); tile = np.abs(left.conj() @ right.T)**2\n",
    "                kt[i:stop_i,j:stop_j] = tile\n",
    "                if i != j: kt[j:stop_j,i:stop_i] = tile.T\n",
    "                algebra += time.perf_counter()-before\n",
    "                del right\n",
    "            for j in range(0, nv, rows):\n",
    "                stop_j = min(j+rows, nv); right = states(test_rows[j:stop_j])\n",
    "                before = time.perf_counter()\n",
    "                kv[j:stop_j,i:stop_i] = np.abs(right.conj() @ left.T)**2\n",
    "                algebra += time.perf_counter()-before\n",
    "                del right\n",
    "            del left\n",
    "        strategy, peak_bytes = \"bounded_reencoding_blocks\", min(nt+nv, 2*rows)*(1 << adapter.n)*16\n",
    "    return kt, kv, dict(encoding_runtime_s=encoding, kernel_algebra_s=algebra,\n",
    "        kernel_strategy=strategy, kernel_block_rows=rows,\n",
    "        logical_statebank_bytes=retained_bytes, exported_bank_peak_bytes=peak_bytes,\n",
    "        all_encoded_state_norm_error=norm_error)\n",
    "\n",
    "\n",
    "def tfim_ground_energy(n, coupling=1., field=.7):\n",
    "    \"\"\"Exact open-chain TFIM reference, with no 2**n by 2**n matrix.\n",
    "\n",
    "    After a global spin rotation and Jordan-Wigner transformation, the\n",
    "    positive single-particle energies are twice the singular values of the\n",
    "    bidiagonal field/coupling matrix. E0 is minus their singular-value sum.\n",
    "    This applies only to tfim_terms(n, coupling, field), with open boundaries.\n",
    "    Independent dense checks for small n are performed in offline_checks.py.\n",
    "    \"\"\"\n",
    "    matrix = np.diag(np.full(n, float(field)))\n",
    "    if n > 1: matrix += np.diag(np.full(n-1, float(coupling)), 1)\n",
    "    return -float(np.linalg.svd(matrix, compute_uv=False).sum())\n",
    "\n",
    "\n",
    "def circuit_spec(n, family, depth, seed):\n",
    "    rng = np.random.default_rng(seed)\n",
    "    if family in [\"angle\",\"phase\",\"pauli\",\"zz\"]:\n",
    "        op = feature_spec(n,family)\n",
    "        return op, feature_values(rng.uniform(-1.5,1.5,n), family)\n",
    "    if family == \"ghz\": return [(\"H\",[0],None)]+[(\"CX\",[0,q],None) for q in range(1,n)], {}\n",
    "    op, values = [], {}\n",
    "    def rotation(gate, q, value):\n",
    "        key = \"r\"+str(len(values)); values[key] = float(value); op.append((gate,[q],key))\n",
    "    if family == \"random\":\n",
    "        for layer in range(depth):\n",
    "            for q in range(n):\n",
    "                rotation(\"RY\",q,rng.uniform(-np.pi,np.pi))\n",
    "                rotation(\"RZ\",q,rng.uniform(-np.pi,np.pi))\n",
    "            for q in range(layer%2,n-1,2): op.append((\"CX\",[q,q+1],None))\n",
    "            for q in range(1-layer%2,n-1,2): op.append((\"CX\",[q,q+1],None))\n",
    "    elif family == \"qft\":\n",
    "        # Nontrivial product input, then QFT with controlled phase gates\n",
    "        # decomposed into common P/CNOT operations and final bit swaps.\n",
    "        for q in range(n): rotation(\"RY\",q,rng.uniform(-1.5,1.5))\n",
    "        for target in reversed(range(n)):\n",
    "            op.append((\"H\",[target],None))\n",
    "            for control in reversed(range(target)):\n",
    "                phi = np.pi/2**(target-control)\n",
    "                rotation(\"P\",control,phi/2); op.append((\"CX\",[control,target],None))\n",
    "                rotation(\"P\",target,-phi/2); op.append((\"CX\",[control,target],None))\n",
    "                rotation(\"P\",target,phi/2)\n",
    "        for q in range(n//2):\n",
    "            op.extend([(\"CX\",[q,n-1-q],None),(\"CX\",[n-1-q,q],None),(\"CX\",[q,n-1-q],None)])\n",
    "    else: raise ValueError(family)\n",
    "    return op, values\n",
    "\n",
    "\n",
    "def qaoa_spec_values(n, h, pairs, p, theta):\n",
    "    op, values = [(\"H\",[q],None) for q in range(n)], {}\n",
    "    for layer in range(p):\n",
    "        gamma, beta = theta[2*layer:2*layer+2]\n",
    "        for q in range(n):\n",
    "            key = f\"z{layer}_{q}\"; values[key] = float(2*gamma*h[q]); op.append((\"RZ\",[q],key))\n",
    "        for j,(a,b,c) in enumerate(pairs):\n",
    "            key = f\"j{layer}_{j}\"; values[key] = float(2*gamma*c)\n",
    "            op.extend([(\"CX\",[a,b],None),(\"RZ\",[b],key),(\"CX\",[a,b],None)])\n",
    "        for q in range(n):\n",
    "            key = f\"b{layer}_{q}\"; values[key] = float(2*beta); op.append((\"RX\",[q],key))\n",
    "    return op, values\n",
    "\n",
    "\n",
    "def qubo_to_ising(a, b, constant):\n",
    "    \"\"\"C(z)=constant+a.z+sum_{i<j} b[i,j]z_i z_j; z=(1-Z)/2.\"\"\"\n",
    "    b=np.triu(b,1)\n",
    "    h=-np.asarray(a)/2-(b.sum(axis=0)+b.sum(axis=1))/4\n",
    "    pairs=[(i,j,float(b[i,j]/4)) for i in range(len(a)) for j in range(i+1,len(a)) if b[i,j]!=0]\n",
    "    offset=float(constant+np.asarray(a).sum()/2+b.sum()/4)\n",
    "    return h,pairs,offset\n",
    "\n",
    "\n",
    "def tfim_terms(n, coupling=1., field=.7):\n",
    "    terms = []\n",
    "    for q in range(n-1):\n",
    "        p = [0]*n; p[q]=p[q+1]=3; terms.append((p,-coupling))\n",
    "    for q in range(n):\n",
    "        p = [0]*n; p[q]=1; terms.append((p,-field))\n",
    "    return terms\n",
    "\n",
    "\n",
    "def hamiltonian_matrix(n, terms):\n",
    "    matrices = [np.eye(2),np.array([[0,1],[1,0]]),np.array([[0,-1j],[1j,0]]),np.diag([1,-1])]\n",
    "    result = np.zeros((1 << n,1 << n), complex)\n",
    "    for pauli, coefficient in terms:\n",
    "        matrix = np.array([[1.]])\n",
    "        for q in reversed(range(n)): matrix = np.kron(matrix,matrices[pauli[q]])\n",
    "        result += coefficient*matrix\n",
    "    return result\n",
    "\n",
    "\n",
    "def angle_kernel(x, y=None):\n",
    "    y = x if y is None else y\n",
    "    return np.prod(np.cos((x[:,None,:]-y[None,:,:])/2)**2, axis=-1)\n",
    "\n",
    "\n",
    "def spsa(initial, objective, iterations, seed, batch_indices=None, trace_objective=None):\n",
    "    rng = np.random.default_rng(seed)\n",
    "    theta = np.asarray(initial).copy(); trace = []\n",
    "    for k in range(iterations):\n",
    "        delta = rng.choice([-1.,1.],len(theta)); a=.12/(k+1)**.602; c=.1/(k+1)**.101\n",
    "        indices = None if batch_indices is None else batch_indices[k]\n",
    "        plus, minus = objective(theta+c*delta,indices), objective(theta-c*delta,indices)\n",
    "        theta -= a*(plus-minus)/(2*c)*delta\n",
    "        value = float(objective(theta,indices) if trace_objective is None else trace_objective(theta))\n",
    "        trace.append(value)\n",
    "    return theta, trace\n",
    "\n",
    "\n",
    "def parameter_shift_values(values, keys):\n",
    "    rows = []\n",
    "    for key in keys:\n",
    "        plus, minus = dict(values), dict(values)\n",
    "        plus[key] += np.pi/2; minus[key] -= np.pi/2\n",
    "        rows.extend([plus,minus])\n",
    "    return rows\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'experiment_core.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote experiment_core.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36cd05cd",
   "metadata": {
    "id": "36cd05cd"
   },
   "source": [
    "#### Train-only data preparation\n",
    "\n",
    "Open this source cell to inspect or modify `prepare_study_data.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "496ba852",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "496ba852",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "ffd89e3d-be41-4aeb-dca5-97dc8a2be169"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote prepare_study_data.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Shared train-only preprocessing, immutable dataset splits, and QUBO inputs.\"\"\"\n",
    "import hashlib\n",
    "import json\n",
    "from pathlib import Path\n",
    "import sys\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.datasets import (load_breast_cancer, load_iris, load_wine,\n",
    "                              load_digits, load_diabetes, make_moons, make_friedman1)\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.feature_selection import mutual_info_classif\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelEncoder, StandardScaler\n",
    "\n",
    "\n",
    "def sha(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()\n",
    "\n",
    "\n",
    "def load_dataset(name, seed, custom):\n",
    "    sources = {\n",
    "        \"breast_cancer\": \"sklearn.datasets.load_breast_cancer (Wisconsin diagnostic)\",\n",
    "        \"iris\": \"sklearn.datasets.load_iris (all three classes)\",\n",
    "        \"wine\": \"sklearn.datasets.load_wine (all three classes)\",\n",
    "        \"digits_01\": \"sklearn.datasets.load_digits, digits 0 and 1 only\",\n",
    "        \"moons\": \"sklearn.datasets.make_moons(n_samples=400, noise=0.20, random_state=seed)\",\n",
    "        \"diabetes\": \"sklearn.datasets.load_diabetes (regression)\",\n",
    "        \"friedman1\": \"sklearn.datasets.make_friedman1(n_samples=400, n_features=10, noise=1, random_state=seed)\",\n",
    "    }\n",
    "    kind = \"regression\" if name in [\"diabetes\",\"friedman1\"] else \"classification\"\n",
    "    if name in custom:\n",
    "        spec = custom[name]; frame = pd.read_csv(spec[\"path\"])\n",
    "        if spec[\"target\"] not in frame: raise ValueError(\"custom CSV target is missing\")\n",
    "        y = frame.pop(spec[\"target\"]).to_numpy()\n",
    "        x = frame.to_numpy(dtype=float); kind = spec[\"kind\"]\n",
    "        source = f'custom CSV {spec[\"path\"]}; SHA256={sha(spec[\"path\"])}'\n",
    "    elif name == \"moons\": x,y = make_moons(400,noise=.2,random_state=seed); source=sources[name]\n",
    "    elif name == \"friedman1\": x,y = make_friedman1(400,n_features=10,noise=1,random_state=seed); source=sources[name]\n",
    "    else:\n",
    "        loader = {\"breast_cancer\":load_breast_cancer,\"iris\":load_iris,\"wine\":load_wine,\n",
    "                  \"digits_01\":load_digits,\"diabetes\":load_diabetes}[name]\n",
    "        x,y = loader(return_X_y=True); source=sources[name]\n",
    "        if name == \"digits_01\": mask=y<2; x,y=x[mask],y[mask]\n",
    "    x = np.asarray(x,dtype=np.float64)\n",
    "    if not np.isfinite(x).all() or pd.isna(y).any(): raise ValueError(f\"non-finite/missing data in {name}\")\n",
    "    classes = []\n",
    "    if kind == \"classification\":\n",
    "        encoder = LabelEncoder(); y = encoder.fit_transform(y); classes = encoder.classes_.astype(str).tolist()\n",
    "    else: y = np.asarray(y,dtype=float)\n",
    "    return x,np.asarray(y),kind,source,classes\n",
    "\n",
    "\n",
    "def preprocess(x, train, test, n):\n",
    "    scaler = StandardScaler().fit(x[train])\n",
    "    xt, xv = scaler.transform(x[train]), scaler.transform(x[test])\n",
    "    components = min(n,x.shape[1],len(train)-1)\n",
    "    pca = PCA(n_components=components,svd_solver=\"full\").fit(xt)\n",
    "    a,b = pca.transform(xt),pca.transform(xv)\n",
    "    limits = np.maximum(np.quantile(np.abs(a),.95,axis=0),1e-10)\n",
    "    a,b = np.clip(a/limits,-1,1)*np.pi,np.clip(b/limits,-1,1)*np.pi\n",
    "    if components < n:\n",
    "        a,b = np.pad(a,((0,0),(0,n-components))),np.pad(b,((0,0),(0,n-components)))\n",
    "    arrays = dict(X_train=a,X_test=b,raw_train=x[train],raw_test=x[test],train_ids=train,test_ids=test,\n",
    "                  scaler_mean=scaler.mean_,scaler_scale=scaler.scale_,pca_mean=pca.mean_,\n",
    "                  pca_components=pca.components_,angle_limits=limits)\n",
    "    audit = dict(active_components=components,padded_qubits=n-components,\n",
    "                 pca_explained_variance=float(pca.explained_variance_ratio_.sum()),\n",
    "                 train_clipped_fraction=float(np.mean(np.abs(a[:,:components])>=np.pi)),\n",
    "                 test_clipped_fraction=float(np.mean(np.abs(b[:,:components])>=np.pi)))\n",
    "    return arrays,audit\n",
    "\n",
    "\n",
    "def qubo_inputs(xtrain, ytrain, n, seed, allow_ancillas=False):\n",
    "    mi = mutual_info_classif(xtrain,ytrain,random_state=seed)\n",
    "    features = np.argsort(-mi,kind=\"stable\")[:min(n,xtrain.shape[1])]\n",
    "    active=len(features)\n",
    "    if active < n and not allow_ancillas: raise ValueError(\"feature-selection qubits exceed available original features\")\n",
    "    relevance = mi[features]; relevance /= max(float(relevance.max()),1e-12)\n",
    "    correlation = np.nan_to_num(np.abs(np.corrcoef(xtrain[:,features],rowvar=False)))\n",
    "    k = max(1,active//2); penalty = 1.5\n",
    "    a = np.zeros(n);a[:active]=-relevance+penalty*(1-2*k)\n",
    "    b = np.zeros((n,n));b[:active,:active]=np.triu(.25*correlation+2*penalty,1)\n",
    "    constant = penalty*k*k\n",
    "    # Retain the 2**n diagonal but avoid a 2**n by n bit matrix at 24 qubits.\n",
    "    logical = np.empty(1 << active, dtype=np.float64)\n",
    "    for start in range(0, 1 << active, 1 << 14):\n",
    "        stop = min(start+(1 << 14), 1 << active)\n",
    "        indices = np.arange(start, stop, dtype=np.uint64)\n",
    "        bits = ((indices[:,None] >> np.arange(active,dtype=np.uint64)) & 1).astype(float)\n",
    "        logical[start:stop] = constant+bits@a[:active]+np.einsum(\"bi,ij,bj->b\",bits,b[:active,:active],bits,optimize=True)\n",
    "    weights=np.tile(logical,1 << (n-active)) if active<n else logical\n",
    "    return dict(qubo_a=a,qubo_b=b,qubo_constant=np.array(constant),qubo_cost=weights,\n",
    "                selected_original_features=features,cardinality=np.array(k),feature_relevance=relevance,\n",
    "                feature_correlation=correlation,active_feature_variables=np.array(active),\n",
    "                feature_selection_ancillas=np.array(n-active))\n",
    "\n",
    "\n",
    "def prepare(config):\n",
    "    root = Path(config[\"root\"]); directory=root/\"data\"; directory.mkdir(parents=True,exist_ok=True)\n",
    "    profile=config[\"profile\"]; manifest=dict(paths={},sha256={},datasets=[]); unsupported=[]\n",
    "    train_ratio=float(profile[\"train_ratio\"]); test_ratio=float(profile[\"test_ratio\"])\n",
    "    if not (0 < train_ratio < 1 and 0 < test_ratio < 1\n",
    "            and np.isclose(train_ratio+test_ratio,1.0,rtol=0,atol=1e-12)):\n",
    "        raise ValueError(\"Train and test ratios must be positive and sum to 1.\")\n",
    "    for seed in profile[\"seeds\"]:\n",
    "        for name in profile[\"classification_datasets\"]+profile[\"regression_datasets\"]:\n",
    "            x,y,kind,source,classes=load_dataset(name,seed,config.get(\"custom_datasets\",{}))\n",
    "            train,test=train_test_split(np.arange(len(x)),test_size=test_ratio,random_state=seed,\n",
    "                stratify=y if kind==\"classification\" else None)\n",
    "            if set(train)&set(test): raise AssertionError(\"split leakage\")\n",
    "            if len(train)+len(test)!=len(x): raise AssertionError(\"split omitted dataset rows\")\n",
    "            for n in sorted(set(profile[\"qml_qubits\"]+profile.get(\"variational_qubits\",profile[\"qml_qubits\"]))):\n",
    "                arrays,audit=preprocess(x,train,test,n)\n",
    "                ym,ys=(0.,1.) if kind==\"classification\" else (float(y[train].mean()),float(max(y[train].std(),1e-12)))\n",
    "                arrays.update(y_train=y[train],y_test=y[test],y_train_scaled=(y[train]-ym)/ys,\n",
    "                    y_test_scaled=(y[test]-ym)/ys,target_mean=np.array(ym),target_scale=np.array(ys))\n",
    "                requested=name in profile[\"feature_selection_datasets\"]\n",
    "                allow_ancillas=bool(profile.get(\"feature_selection_ancillas\",False))\n",
    "                available=requested and (n<=x.shape[1] or allow_ancillas)\n",
    "                audit.update(feature_selection_requested=requested,feature_selection_available=available,\n",
    "                             feature_selection_max_qubits=x.shape[1],\n",
    "                             feature_selection_active_features=min(n,x.shape[1]) if requested else 0,\n",
    "                             feature_selection_ancilla_qubits=max(0,n-x.shape[1]) if requested and allow_ancillas else 0)\n",
    "                if available:\n",
    "                    arrays.update(qubo_inputs(x[train],y[train],n,seed,allow_ancillas=allow_ancillas))\n",
    "                elif requested:\n",
    "                    unsupported.append(dict(dataset=name,n_qubits=n,seed=seed,\n",
    "                        original_features=x.shape[1],reason=\"Feature-selection qubits exceed the number of original features\"))\n",
    "                key=f\"{name}:{n}:{seed}\"; path=directory/(key.replace(\":\",\"_\")+\".npz\")\n",
    "                np.savez_compressed(path,**arrays)\n",
    "                manifest[\"paths\"][key]=str(path); manifest[\"sha256\"][key]=sha(path)\n",
    "                manifest[\"datasets\"].append(dict(dataset=name,kind=kind,source=source,classes=classes,\n",
    "                    seed=seed,n_qubits=n,original_samples=len(x),original_features=x.shape[1],\n",
    "                    train_samples=len(train),test_samples=len(test),\n",
    "                    requested_train_ratio=train_ratio,requested_test_ratio=test_ratio,\n",
    "                    actual_train_ratio=len(train)/len(x),actual_test_ratio=len(test)/len(x),\n",
    "                    class_counts_train={str(v):int((y[train]==v).sum()) for v in np.unique(y[train])} if kind==\"classification\" else {},\n",
    "                    raw_values_sha256=hashlib.sha256(x.tobytes()+y.tobytes()).hexdigest(),**audit))\n",
    "    (root/\"data_manifest.json\").write_text(json.dumps(manifest,indent=2))\n",
    "    pd.DataFrame(manifest[\"datasets\"]).to_csv(root/\"dataset_audit.csv\",index=False)\n",
    "    pd.DataFrame(unsupported,columns=[\"dataset\",\"n_qubits\",\"seed\",\"original_features\",\"reason\"]).to_csv(\n",
    "        root/\"unsupported_feature_selection.csv\",index=False)\n",
    "    print(f'Prepared {len(manifest[\"paths\"])} dataset/qubit/seed inputs; '\n",
    "          f'{train_ratio:.0%}/{test_ratio:.0%} split using all rows; train-only scaling, PCA and angle limits.')\n",
    "    print(\"Bundled datasets require no external dataset downloads. Padded components are explicitly recorded.\")\n",
    "    if unsupported:\n",
    "        print(f\"Recorded {len(unsupported)} unsupported feature-selection dataset/qubit/seed cases in unsupported_feature_selection.csv; other QML tasks retain these qubit settings.\")\n",
    "\n",
    "\n",
    "if __name__==\"__main__\": prepare(json.loads(Path(sys.argv[1]).read_text()))\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'prepare_study_data.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote prepare_study_data.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0acb0649",
   "metadata": {
    "id": "0acb0649"
   },
   "source": [
    "#### QML, optimization, gradients and circuit workloads\n",
    "\n",
    "Open this source cell to inspect or modify `study_worker.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4f97f66e",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "4f97f66e",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "0ce05ce8-f76e-41a8-91f1-1b796a07ff47"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote study_worker.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"A single real benchmark job; errors are retained and never replaced by fallbacks.\"\"\"\n",
    "import json\n",
    "import importlib\n",
    "import importlib.metadata\n",
    "import os\n",
    "from pathlib import Path\n",
    "try:\n",
    "    import resource\n",
    "except ImportError:  # Windows: no resource module; psutil fallbacks below\n",
    "    resource = None\n",
    "import sys\n",
    "import time\n",
    "import traceback\n",
    "\n",
    "import numpy as np\n",
    "from scipy.special import expit, softmax\n",
    "from sklearn.dummy import DummyClassifier\n",
    "from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor\n",
    "from sklearn.kernel_ridge import KernelRidge\n",
    "from sklearn.linear_model import LogisticRegression, Ridge\n",
    "from sklearn.metrics import (accuracy_score, balanced_accuracy_score, f1_score,\n",
    "                             roc_auc_score, mean_squared_error, mean_absolute_error, r2_score)\n",
    "from sklearn.pipeline import make_pipeline\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.svm import SVC\n",
    "\n",
    "from experiment_core import (Adapter, feature_spec, feature_values, mean_z_terms,\n",
    "    mean_z_weights, fidelity_matrix, reference_state, align_error, pauli_expectations,\n",
    "    circuit_spec, qaoa_spec_values, qubo_to_ising, ising_terms, tfim_terms,\n",
    "    hamiltonian_matrix, angle_kernel, spsa, parameter_shift_values,\n",
    "    quantum_kernel_matrices, state_chunk_rows, tfim_ground_energy)\n",
    "import legacy_adapter\n",
    "\n",
    "\n",
    "def peak_mb():\n",
    "    if resource is not None:\n",
    "        return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/1024\n",
    "    import psutil\n",
    "    return psutil.Process().memory_info().peak_wset/2**20\n",
    "\n",
    "\n",
    "def current_rss_mib():\n",
    "    \"\"\"Resident RAM, including Python and native allocations; no sampler.\"\"\"\n",
    "    if os.name == \"nt\":\n",
    "        import psutil\n",
    "        return psutil.Process().memory_info().rss/2**20, \"Windows psutil current RSS\"\n",
    "    try:\n",
    "        pages=int(Path(\"/proc/self/statm\").read_text().split()[1])\n",
    "        return pages*os.sysconf(\"SC_PAGE_SIZE\")/2**20, \"Linux /proc/self/statm\"\n",
    "    except (OSError, ValueError, IndexError):\n",
    "        # A high-water mark is not a current-RSS measurement.\n",
    "        return None, \"unavailable: procfs resident-page counter could not be read\"\n",
    "\n",
    "\n",
    "def classification_metrics(y, prediction, scores=None):\n",
    "    result = dict(accuracy=float(accuracy_score(y,prediction)),\n",
    "                  balanced_accuracy=float(balanced_accuracy_score(y,prediction)),\n",
    "                  f1_macro=float(f1_score(y,prediction,average=\"macro\",zero_division=0)))\n",
    "    if len(np.unique(y))==2 and scores is not None:\n",
    "        scores=np.asarray(scores)\n",
    "        result[\"roc_auc\"] = float(roc_auc_score(y,scores[:,1] if scores.ndim==2 else scores))\n",
    "    return result\n",
    "\n",
    "\n",
    "def regression_metrics(y,prediction):\n",
    "    return dict(rmse=float(np.sqrt(mean_squared_error(y,prediction))),\n",
    "                mae=float(mean_absolute_error(y,prediction)),r2=float(r2_score(y,prediction)))\n",
    "\n",
    "\n",
    "def tolerance(job): return 3e-5 if job[\"framework\"]==\"cirq\" else 3e-9\n",
    "\n",
    "\n",
    "def bank_audit(job, bank, operations, values):\n",
    "    \"\"\"All norms, plus full amplitude vectors for first and last batch rows.\"\"\"\n",
    "    n=job[\"n_qubits\"]; tol=tolerance(job)\n",
    "    if bank.shape!=(len(values),1 << n) or not np.isfinite(bank).all(): raise ValueError(\"invalid state bank\")\n",
    "    norm_error=max(abs(float(np.vdot(vector,vector).real)-1) for vector in bank)\n",
    "    selected=sorted(set([0,len(values)-1])); error=0.\n",
    "    for i in selected:\n",
    "        error=max(error,align_error(bank[i],reference_state(n,operations,values[i])))\n",
    "    if norm_error>tol or error>tol: raise RuntimeError(f\"state audit failed: amplitude={error}, norm={norm_error}\")\n",
    "    return dict(max_amplitude_error=error,max_norm_error=norm_error,tolerance=tol,\n",
    "                vector_audit=\"full amplitude vectors for first/last rows; all batch norms\")\n",
    "\n",
    "\n",
    "def adapter_metadata(adapter):\n",
    "    return dict(internal_precision=adapter.precision,backend=adapter.backend,\n",
    "                batch_strategy=adapter.batch_strategy,circuit_calls=adapter.calls,\n",
    "                backend_execute_total_s=adapter.execute_s)\n",
    "\n",
    "\n",
    "def timed_repeat(function, job):\n",
    "    for _ in range(job[\"warmups\"]): function()\n",
    "    times=[]\n",
    "    for _ in range(job[\"inner_repetitions\"]):\n",
    "        start=time.perf_counter(); result=function(); times.append(time.perf_counter()-start)\n",
    "    return result,dict(primary_runtime_s=float(np.median(times)),inner_runtime_s=times,\n",
    "                       peak_measured_stage_mb=peak_mb())\n",
    "\n",
    "\n",
    "def kernel_job(job):\n",
    "    data=np.load(job[\"data_path\"]); n=job[\"n_qubits\"]; name=job[\"feature_map\"]\n",
    "    x,y=data[\"X_train\"],data[\"X_test\"]\n",
    "    row_cap=job.get(\"kernel_row_cap\")\n",
    "    if row_cap: x=x[:int(row_cap)]; y=y[:int(row_cap)]\n",
    "    rows_x=[feature_values(row,name) for row in x]; rows_y=[feature_values(row,name) for row in y]\n",
    "    analytical=job[\"framework\"]==\"analytical_angle\"\n",
    "    prep=time.perf_counter()\n",
    "    adapter=None if analytical else Adapter(job[\"framework\"],n,feature_spec(n,name))\n",
    "    prepare_s=time.perf_counter()-prep\n",
    "    if adapter:\n",
    "        adapter.states(rows_x[:1]); adapter.reset()\n",
    "    else: angle_kernel(x[:1])\n",
    "    start=time.perf_counter()\n",
    "    if analytical:\n",
    "        kt,kv=angle_kernel(x),angle_kernel(y,x); encode_s=0.; kernel_s=time.perf_counter()-start\n",
    "    else:\n",
    "        kt,kv,kernel_info=quantum_kernel_matrices(adapter,rows_x,rows_y,\n",
    "            job[\"max_statebank_bytes\"],job.get(\"kernel_block_rows\",128))\n",
    "        encode_s=kernel_info[\"encoding_runtime_s\"];kernel_s=kernel_info[\"kernel_algebra_s\"]\n",
    "    primary=time.perf_counter()-start; peak=peak_mb()\n",
    "    result=dict(primary_runtime_s=primary,encoding_runtime_s=encode_s,kernel_algebra_s=kernel_s,\n",
    "                train_samples=len(x),test_samples=len(y),kernel_row_cap=(int(row_cap) if row_cap else None),\n",
    "                circuit_prepare_s=prepare_s,peak_measured_stage_mb=peak,\n",
    "                kernel_probe=kt[:6,:6].tolist(),test_kernel_probe=kv[:3,:6].tolist(),\n",
    "                kernel_diagonal_error=float(np.max(np.abs(np.diag(kt)-1))),\n",
    "                kernel_min_eigenvalue=float(np.linalg.eigvalsh((kt+kt.T)/2).min()))\n",
    "    if result[\"kernel_diagonal_error\"]>5*tolerance(job) or result[\"kernel_min_eigenvalue\"] < -5*tolerance(job):\n",
    "        raise RuntimeError(\"kernel normalization or PSD check failed\")\n",
    "    if adapter:\n",
    "        result.update(adapter_metadata(adapter));result.update(kernel_info)\n",
    "        if kernel_info[\"all_encoded_state_norm_error\"]>tolerance(job):\n",
    "            raise RuntimeError(\"Kernel state-block normalization failed\")\n",
    "        error=0.;norm=kernel_info[\"all_encoded_state_norm_error\"]\n",
    "        for rows in [rows_x,rows_y]:\n",
    "            for index in sorted(set([0,len(rows)-1])):\n",
    "                probe=adapter.states([rows[index]])\n",
    "                audit=bank_audit(job,probe,adapter.operations,[rows[index]])\n",
    "                error=max(error,audit[\"max_amplitude_error\"]);norm=max(norm,audit[\"max_norm_error\"])\n",
    "                del probe\n",
    "        result.update(max_amplitude_error=error,max_norm_error=norm,tolerance=tolerance(job),\n",
    "            vector_audit=\"All encoded-state norms; independently replayed full first/last train/test vectors after timing\")\n",
    "    else:\n",
    "        # Every analytical value is audited against an independent product\n",
    "        # RY/CNOT state construction, not against this closed-form function.\n",
    "        class IndependentKernel:\n",
    "            def __init__(self): self.n=n\n",
    "            def states(self,rows):\n",
    "                return np.stack([reference_state(n,feature_spec(n,\"angle\"),row) for row in rows]) if rows else np.empty((0,1 << n),complex)\n",
    "        reference,_,_=quantum_kernel_matrices(IndependentKernel(),rows_x[:6],[],\n",
    "            job[\"max_statebank_bytes\"],job.get(\"kernel_block_rows\",128))\n",
    "        error=float(np.max(np.abs(kt[:6,:6]-reference)))\n",
    "        if error>3e-9: raise RuntimeError(\"analytical Angle kernel mismatch\")\n",
    "        result.update(internal_precision=\"float64 analytical\",backend=\"exact product-cosine Angle kernel\",\n",
    "                      batch_strategy=\"separate classical algorithm\",circuit_calls=0,max_kernel_error=error,\n",
    "                      kernel_strategy=\"analytical_with_blocked_reference_audit\")\n",
    "    before=time.perf_counter()\n",
    "    if job[\"task\"]==\"qsvm\":\n",
    "        model=SVC(C=1,kernel=\"precomputed\",decision_function_shape=\"ovr\",random_state=job[\"seed\"])\n",
    "        model.fit(kt,data[\"y_train\"]); prediction=model.predict(kv); scores=model.decision_function(kv)\n",
    "        result.update(classification_metrics(data[\"y_test\"],prediction,scores))\n",
    "    elif job[\"task\"]==\"qkrr\":\n",
    "        model=KernelRidge(alpha=.1,kernel=\"precomputed\").fit(kt,data[\"y_train_scaled\"])\n",
    "        prediction=model.predict(kv)*float(data[\"target_scale\"])+float(data[\"target_mean\"])\n",
    "        result.update(regression_metrics(data[\"y_test\"],prediction))\n",
    "    else:\n",
    "        mean=kt.mean(axis=0); grand=float(kt.mean())\n",
    "        centered=kt-mean[None,:]-mean[:,None]+grand\n",
    "        centered_test=kv-mean[None,:]-kv.mean(axis=1)[:,None]+grand\n",
    "        eigenvalues,eigenvectors=np.linalg.eigh((centered+centered.T)/2)\n",
    "        order=np.argsort(eigenvalues)[::-1]; order=order[eigenvalues[order]>1e-8][:3]\n",
    "        if not len(order): raise RuntimeError(\"QKPCA has no positive components\")\n",
    "        vectors=eigenvectors[:,order]; roots=np.sqrt(eigenvalues[order])\n",
    "        train_embedding=vectors*roots; test_embedding=centered_test@vectors/roots\n",
    "        model=LogisticRegression(C=1,max_iter=1000).fit(train_embedding,data[\"y_train\"])\n",
    "        prediction=model.predict(test_embedding); scores=model.predict_proba(test_embedding)\n",
    "        result.update(classification_metrics(data[\"y_test\"],prediction,scores),\n",
    "                      qkpca_components=len(order),qkpca_top_eigenvalues=eigenvalues[order].tolist(),\n",
    "                      qkpca_variance_fraction=float(eigenvalues[order].sum()/np.maximum(eigenvalues,0).sum()))\n",
    "    fit_s=time.perf_counter()-before\n",
    "    result.update(classical_stage_s=fit_s,end_to_end_s=primary+fit_s,predictions=prediction.tolist())\n",
    "    return result\n",
    "\n",
    "\n",
    "def classical_job(job):\n",
    "    data=np.load(job[\"data_path\"]); x,y=data[\"X_train\"],data[\"y_train\"]\n",
    "    kind=job[\"kind\"]; name=job[\"model\"]\n",
    "    constructors={\"rbf_svc\":lambda:SVC(C=1,kernel=\"rbf\",gamma=\"scale\",random_state=job[\"seed\"]),\n",
    "                  \"logistic\":lambda:LogisticRegression(C=1,max_iter=1000),\n",
    "                  \"rf_classifier\":lambda:RandomForestClassifier(n_estimators=100,n_jobs=1,random_state=job[\"seed\"]),\n",
    "                  \"ridge\":lambda:Ridge(alpha=1.),\n",
    "                  \"rbf_krr\":lambda:KernelRidge(alpha=.1,kernel=\"rbf\",gamma=1/x.shape[1]),\n",
    "                  \"rf_regressor\":lambda:RandomForestRegressor(n_estimators=100,n_jobs=1,random_state=job[\"seed\"])}\n",
    "    start=time.perf_counter(); model=constructors[name]().fit(x,y); prediction=model.predict(data[\"X_test\"])\n",
    "    result=dict(predictions=prediction.tolist(),internal_precision=\"classical estimator\",\n",
    "                train_samples=len(x),test_samples=len(data[\"X_test\"]))\n",
    "    if kind==\"classification\":\n",
    "        score=model.decision_function(data[\"X_test\"]) if hasattr(model,\"decision_function\") else model.predict_proba(data[\"X_test\"])\n",
    "        result.update(classification_metrics(data[\"y_test\"],prediction,score))\n",
    "    else: result.update(regression_metrics(data[\"y_test\"],prediction))\n",
    "    elapsed=time.perf_counter()-start\n",
    "    result.update(primary_runtime_s=elapsed,end_to_end_s=elapsed,peak_measured_stage_mb=peak_mb())\n",
    "    if kind==\"classification\":\n",
    "        pca=data[\"pca_components\"]; raw=StandardScaler().fit(data[\"raw_train\"])\n",
    "        # A second classical control retains every original feature. It is\n",
    "        # an information-content comparison, not the matched-input ranking.\n",
    "        full_model=constructors[name](); before=time.perf_counter()\n",
    "        full_model.fit(raw.transform(data[\"raw_train\"]),y)\n",
    "        full_prediction=full_model.predict(raw.transform(data[\"raw_test\"]))\n",
    "        result.update(full_feature_runtime_s=time.perf_counter()-before,\n",
    "                      full_feature_accuracy=float(accuracy_score(data[\"y_test\"],full_prediction)))\n",
    "    return result\n",
    "\n",
    "\n",
    "def evaluator(job, operations, output, terms, weights=None):\n",
    "    native=job[\"track\"]==\"native_readout\"\n",
    "    before=time.perf_counter()\n",
    "    adapter=Adapter(job[\"framework\"],job[\"n_qubits\"],operations,\n",
    "                    output=output if native else \"state\",terms=terms,weights=weights)\n",
    "    prepare_s=time.perf_counter()-before\n",
    "    if not native and weights is None and output==\"mean_z\": weights=mean_z_weights(job[\"n_qubits\"])\n",
    "    chunk=state_chunk_rows(job[\"n_qubits\"],job[\"max_statebank_bytes\"],simultaneous_banks=2)\n",
    "    def evaluate(rows):\n",
    "        rows=list(rows);outputs=[]\n",
    "        for start in range(0,len(rows),chunk):\n",
    "            block=rows[start:start+chunk]\n",
    "            if native: values=adapter.readouts(block)\n",
    "            else:\n",
    "                bank=adapter.states(block)\n",
    "                values=np.abs(bank)**2@weights if weights is not None else pauli_expectations(bank,terms,job[\"n_qubits\"])\n",
    "                del bank\n",
    "            outputs.extend(np.asarray(values,dtype=float))\n",
    "        return np.asarray(outputs,dtype=float)\n",
    "    return adapter,evaluate,prepare_s\n",
    "\n",
    "\n",
    "def variational_ml(job):\n",
    "    data=np.load(job[\"data_path\"]); n=job[\"n_qubits\"]; layers=job[\"depth\"]\n",
    "    x,xt=data[\"X_train\"],data[\"X_test\"]; regression=job[\"task\"]==\"vqr\"\n",
    "    y=data[\"y_train_scaled\"] if regression else data[\"y_train\"]\n",
    "    classes=len(np.unique(y)) if not regression else 1\n",
    "    units=1 if classes<=2 else classes; width=2*n*layers\n",
    "    rng=np.random.default_rng(job[\"seed\"])\n",
    "    initial=rng.normal(0,.15,units*(width+1)+(1 if regression else 0))\n",
    "    if regression: initial[-1]=.5\n",
    "    adapter,evaluate,prep=evaluator(job,feature_spec(n,job[\"feature_map\"],layers),\"mean_z\",mean_z_terms(n))\n",
    "    def scores(theta,inputs):\n",
    "        result=[]\n",
    "        for unit in range(units):\n",
    "            offset=unit*(width+1); angles=theta[offset:offset+width]\n",
    "            rows=[feature_values(row,job[\"feature_map\"],angles) for row in inputs]\n",
    "            z=evaluate(rows)\n",
    "            result.append((theta[-1] if regression else 2.)*z+theta[offset+width])\n",
    "        values=np.column_stack(result)\n",
    "        if regression: return values[:,0]\n",
    "        return np.column_stack([1-expit(values[:,0]),expit(values[:,0])]) if units==1 else softmax(values,axis=1)\n",
    "    def objective(theta,indices):\n",
    "        indices=np.arange(len(x)) if indices is None else indices\n",
    "        predicted=scores(theta,x[indices])\n",
    "        if regression: return float(np.mean((predicted-y[indices])**2))\n",
    "        return float(-np.mean(np.log(np.clip(predicted[np.arange(len(indices)),y[indices].astype(int)],1e-9,1))))\n",
    "    scores(initial,x[:1]); adapter.reset()\n",
    "    batches=[rng.choice(len(x),min(job[\"batch_size\"],len(x)),replace=False) for _ in range(job[\"iterations\"])]\n",
    "    start=time.perf_counter(); initial_loss=objective(initial,None)\n",
    "    final,trace=spsa(initial,objective,job[\"iterations\"],job[\"seed\"]+501,batches,\n",
    "                     trace_objective=lambda theta:objective(theta,None))\n",
    "    final_loss=trace[-1] if trace else initial_loss; training=time.perf_counter()-start; peak=peak_mb()\n",
    "    before=time.perf_counter(); predicted=scores(final,xt); inference=time.perf_counter()-before\n",
    "    if regression:\n",
    "        prediction=predicted*float(data[\"target_scale\"])+float(data[\"target_mean\"])\n",
    "        quality=regression_metrics(data[\"y_test\"],prediction)\n",
    "    else:\n",
    "        prediction=predicted.argmax(axis=1); quality=classification_metrics(data[\"y_test\"],prediction,predicted)\n",
    "    # Native reductions are checked against independently propagated states\n",
    "    # at the final parameters, outside the measured training and inference.\n",
    "    rows=[feature_values(x[0],job[\"feature_map\"],final[:width])]\n",
    "    expected=pauli_expectations([reference_state(n,adapter.operations,rows[0])],mean_z_terms(n),n)[0]\n",
    "    actual=evaluate(rows)[0]; error=float(abs(actual-expected))\n",
    "    if error>tolerance(job): raise RuntimeError(\"variational final expectation mismatch\")\n",
    "    return dict(primary_runtime_s=training,inference_runtime_s=inference,end_to_end_s=training+inference,\n",
    "        circuit_prepare_s=prep,peak_measured_stage_mb=peak,initial_loss=initial_loss,final_loss=final_loss,\n",
    "        optimization_trace=[initial_loss]+trace,trace_kind=\"full training loss at each iterate; \"+\n",
    "            (\"full-training-partition\" if job.get(\"training_batch_mode\")==\"full_train_partition\" else \"mini-batch\")+\" SPSA perturbations\",\n",
    "        predictions=prediction.tolist(),learned_parameters=final.tolist(),native_readout_error=error,\n",
    "        **quality,**adapter_metadata(adapter))\n",
    "\n",
    "\n",
    "def optimization(job):\n",
    "    n=job[\"n_qubits\"]; rng=np.random.default_rng(job[\"seed\"])\n",
    "    if job[\"task\"]==\"vqe\":\n",
    "        terms=tfim_terms(n); op=feature_spec(n,\"angle\",job[\"depth\"]); width=2*n*job[\"depth\"]\n",
    "        initial=rng.normal(0,.2,width)\n",
    "        reference_start=time.perf_counter();ground=tfim_ground_energy(n)\n",
    "        ground_reference_s=time.perf_counter()-reference_start\n",
    "        adapter,evaluate,prep=evaluator(job,op,\"pauli\",terms)\n",
    "        values=lambda theta:feature_values(np.zeros(n),\"angle\",theta)\n",
    "        weights=None\n",
    "    else:\n",
    "        if job[\"task\"]==\"qaoa_fs\":\n",
    "            data=np.load(job[\"data_path\"]); a,b,constant=data[\"qubo_a\"],data[\"qubo_b\"],float(data[\"qubo_constant\"])\n",
    "            h,pairs,offset=qubo_to_ising(a,b,constant); weights=data[\"qubo_cost\"]\n",
    "        else:\n",
    "            edges=[(q,(q+1)%n,float(rng.uniform(.5,1.5))) for q in range(n)]\n",
    "            if job[\"dataset\"]==\"erdos_renyi\":\n",
    "                edges=[(i,j,float(rng.uniform(.5,1.5))) for i in range(n) for j in range(i+1,n) if rng.random()<.6]\n",
    "                if not edges: edges=[(0,1,1.)]\n",
    "            h=np.zeros(n); pairs=[(i,j,w/2) for i,j,w in edges]; offset=-sum(w for _,_,w in edges)/2\n",
    "            weights=np.empty(1 << n,dtype=float)\n",
    "            for start in range(0,1 << n,1 << 18):\n",
    "                stop=min(start+(1 << 18),1 << n);indices=np.arange(start,stop,dtype=np.uint64)\n",
    "                cost=np.zeros(len(indices))\n",
    "                for i,j,w in edges: cost-=w*(((indices >> i)^(indices >> j))&1)\n",
    "                weights[start:stop]=cost\n",
    "        terms=ising_terms(n,h,pairs,offset); initial=rng.uniform(.2,.7,2*job[\"depth\"])\n",
    "        op,_=qaoa_spec_values(n,h,pairs,job[\"depth\"],initial)\n",
    "        values=lambda theta:qaoa_spec_values(n,h,pairs,job[\"depth\"],theta)[1]\n",
    "        adapter,evaluate,prep=evaluator(job,op,\"qubo\",terms,weights)\n",
    "        ground=float(weights.min())\n",
    "    def objective(theta,unused=None): return float(evaluate([values(theta)])[0])\n",
    "    objective(initial); adapter.reset()\n",
    "    start=time.perf_counter(); first=objective(initial)\n",
    "    final,trace=spsa(initial,objective,job[\"iterations\"],job[\"seed\"]+700)\n",
    "    energy=trace[-1] if trace else first; elapsed=time.perf_counter()-start; peak=peak_mb()\n",
    "    # The same final state export is outside primary native-readout training\n",
    "    # for every backend, so solution diagnostics do not change that contract.\n",
    "    before=time.perf_counter(); export=Adapter(job[\"framework\"],n,op)\n",
    "    bank=export.states([values(final)]); diagnostics_s=time.perf_counter()-before\n",
    "    audit=bank_audit(job,bank,op,[values(final)])\n",
    "    expected=float(pauli_expectations(bank,terms,n)[0]); native_error=abs(expected-energy)\n",
    "    scale=max(1.,sum(abs(c) for _,c in terms))\n",
    "    if native_error>tolerance(job)*scale or energy<ground-tolerance(job)*scale: raise RuntimeError(\"optimization energy audit failed\")\n",
    "    result=dict(primary_runtime_s=elapsed,end_to_end_s=elapsed+diagnostics_s,circuit_prepare_s=prep,\n",
    "        solution_diagnostics_s=diagnostics_s,peak_measured_stage_mb=peak,initial_energy=first,\n",
    "        final_energy=energy,ground_energy=ground,energy_gap=energy-ground,\n",
    "        optimization_trace=[first]+trace,learned_parameters=final.tolist(),\n",
    "        native_readout_error=float(native_error),energy_scale=scale,**audit,**adapter_metadata(adapter))\n",
    "    if job[\"task\"]==\"vqe\":\n",
    "        result.update(ground_reference_method=\"exact open-chain Jordan-Wigner singular values (n by n)\",\n",
    "                      ground_reference_s=ground_reference_s)\n",
    "    if weights is not None:\n",
    "        probabilities=np.abs(bank[0])**2; modal=int(probabilities.argmax())\n",
    "        result.update(modal_bitstring=modal,modal_cost=float(weights[modal]),\n",
    "            optimum_probability=float(probabilities[np.isclose(weights,ground,atol=1e-10)].sum()))\n",
    "        if job[\"task\"]==\"maxcut\": result[\"approximation_ratio\"]=float(energy/ground) if ground<0 else None\n",
    "        else:\n",
    "            features=data[\"selected_original_features\"]\n",
    "            selected=[int(features[q]) for q in range(len(features)) if (modal>>q)&1]\n",
    "            result.update(selected_features=selected,selected_feature_count=len(selected),\n",
    "                target_cardinality=int(data[\"cardinality\"]),active_feature_variables=len(features),\n",
    "                feature_selection_ancillas=n-len(features))\n",
    "            before=time.perf_counter()\n",
    "            if selected:\n",
    "                model=make_pipeline(StandardScaler(),LogisticRegression(C=1,max_iter=1000))\n",
    "                model.fit(data[\"raw_train\"][:,selected],data[\"y_train\"])\n",
    "                prediction=model.predict(data[\"raw_test\"][:,selected])\n",
    "            else:\n",
    "                model=DummyClassifier(strategy=\"most_frequent\").fit(data[\"raw_train\"],data[\"y_train\"])\n",
    "                prediction=model.predict(data[\"raw_test\"])\n",
    "            result.update(fs_downstream_accuracy=float(accuracy_score(data[\"y_test\"],prediction)),\n",
    "                          fs_downstream_runtime_s=time.perf_counter()-before)\n",
    "    return result\n",
    "\n",
    "\n",
    "def gradient_job(job):\n",
    "    n=job[\"n_qubits\"]; rng=np.random.default_rng(job[\"seed\"])\n",
    "    x=rng.uniform(-1,1,n); theta=rng.normal(0,.2,2*n*job[\"depth\"])\n",
    "    op=feature_spec(n,\"angle\",job[\"depth\"]); values=feature_values(x,\"angle\",theta)\n",
    "    keys=[\"t\"+str(i) for i in range(len(theta))]\n",
    "    shifted=parameter_shift_values(values,keys)\n",
    "    adapter,evaluate,prep=evaluator(job,op,\"mean_z\",mean_z_terms(n))\n",
    "    def execute():\n",
    "        outcomes=evaluate(shifted); return (outcomes[::2]-outcomes[1::2])/2\n",
    "    gradient,timing=timed_repeat(execute,job)\n",
    "    finite=[]; epsilon=1e-6\n",
    "    for key in keys:\n",
    "        plus,minus=dict(values),dict(values); plus[key]+=epsilon; minus[key]-=epsilon\n",
    "        a=pauli_expectations([reference_state(n,op,plus)],mean_z_terms(n),n)[0]\n",
    "        b=pauli_expectations([reference_state(n,op,minus)],mean_z_terms(n),n)[0]\n",
    "        finite.append((a-b)/(2*epsilon))\n",
    "    error=float(np.max(np.abs(gradient-np.array(finite))))\n",
    "    if error>tolerance(job)*3: raise RuntimeError(f\"parameter-shift gradient mismatch: {error}\")\n",
    "    return dict(**timing,circuit_prepare_s=prep,gradient=gradient.tolist(),max_gradient_error=error,\n",
    "                shifted_circuits=2*len(keys),**adapter_metadata(adapter))\n",
    "\n",
    "\n",
    "def circuit_job(job):\n",
    "    n=job[\"n_qubits\"]; op,base=circuit_spec(n,job[\"family\"],job[\"depth\"],job[\"seed\"])\n",
    "    rng=np.random.default_rng(job[\"seed\"]+111)\n",
    "    rows=[{k:(float(v+rng.normal(0,.05)) if job[\"family\"] not in [\"qft\",\"ghz\"] else v)\n",
    "           for k,v in base.items()} for _ in range(job[\"batch_size\"])]\n",
    "    before=time.perf_counter(); adapter=Adapter(job[\"framework\"],n,op); prep=time.perf_counter()-before\n",
    "    chunk=state_chunk_rows(n,job[\"max_statebank_bytes\"])\n",
    "    def execute():\n",
    "        norm=0.\n",
    "        for start in range(0,len(rows),chunk):\n",
    "            bank=adapter.states(rows[start:start+chunk])\n",
    "            if not np.isfinite(bank).all():raise RuntimeError(\"Nonfinite circuit state block\")\n",
    "            for vector in bank:norm=max(norm,abs(float(np.vdot(vector,vector).real)-1.))\n",
    "            del bank\n",
    "        return norm\n",
    "    norm,timing=timed_repeat(execute,job);metadata=adapter_metadata(adapter)\n",
    "    error=0.\n",
    "    for index in sorted(set([0,len(rows)-1])):\n",
    "        bank=adapter.states([rows[index]])\n",
    "        audit=bank_audit(job,bank,op,[rows[index]])\n",
    "        error=max(error,audit[\"max_amplitude_error\"]);norm=max(norm,audit[\"max_norm_error\"])\n",
    "        del bank\n",
    "    if norm>tolerance(job):raise RuntimeError(\"Circuit stream normalization failed\")\n",
    "    return dict(**timing,circuit_prepare_s=prep,gate_count=len(op),\n",
    "                statebank_bytes=min(chunk,len(rows))*(1 << n)*16,\n",
    "                logical_statebank_bytes=len(rows)*(1 << n)*16,state_chunk_rows=min(chunk,len(rows)),\n",
    "                output_contract=\"complex128 state exports in bounded chunks; all-state norm reduction inside timing\",\n",
    "                throughput_circuits_s=len(rows)/timing[\"primary_runtime_s\"],\n",
    "                max_amplitude_error=error,max_norm_error=norm,tolerance=tolerance(job),\n",
    "                vector_audit=\"Every measured state norm; first/last full vectors independently replayed after timing\",**metadata)\n",
    "\n",
    "\n",
    "def validation_job(job):\n",
    "    n=job[\"n_qubits\"]; rng=np.random.default_rng(12345); checks=[]\n",
    "    for family in [\"angle\",\"phase\",\"pauli\",\"zz\",\"ghz\",\"random\",\"qft\"]:\n",
    "        op,base=circuit_spec(n,family,2,12345)\n",
    "        rows=[base,{k:float(v+.17) for k,v in base.items()}]\n",
    "        adapter=Adapter(job[\"framework\"],n,op); bank=adapter.states(rows)\n",
    "        checks.append(dict(case=family,passed=True,**bank_audit(job,bank,op,rows)))\n",
    "    op=[(\"X\",[0],None)]; bank=Adapter(job[\"framework\"],n,op).states([{}])\n",
    "    if np.argmax(np.abs(bank[0]))!=1: raise RuntimeError(\"q0=LSB convention failed\")\n",
    "    checks.append(dict(case=\"asymmetric_q0_basis\",passed=True,**bank_audit(job,bank,op,[{}])))\n",
    "    terms=tfim_terms(n)+[([2]+[0]*(n-1),.13)]\n",
    "    op,base=circuit_spec(n,\"pauli\",1,555)\n",
    "    reference=reference_state(n,op,base); expected=float(pauli_expectations([reference],terms,n)[0])\n",
    "    native=Adapter(job[\"framework\"],n,op,output=\"pauli\",terms=terms)\n",
    "    actual=float(native.readouts([base])[0]); error=abs(actual-expected)\n",
    "    if error>tolerance(job)*sum(abs(c) for _,c in terms): raise RuntimeError(\"mixed X/Y/Z native observable mismatch\")\n",
    "    checks.append(dict(case=\"mixed_XYZ_observable\",passed=True,native_readout_error=error,tolerance=tolerance(job)))\n",
    "    mz=Adapter(job[\"framework\"],n,op,output=\"mean_z\",terms=mean_z_terms(n))\n",
    "    rows=[base,{k:float(v+.13) for k,v in base.items()}]\n",
    "    expected=pauli_expectations([reference_state(n,op,row) for row in rows],mean_z_terms(n),n)\n",
    "    error=float(np.max(np.abs(mz.readouts(rows)-expected)))\n",
    "    if error>tolerance(job): raise RuntimeError(\"native mean-Z batch mismatch\")\n",
    "    checks.append(dict(case=\"native_mean_z_batch\",passed=True,native_readout_error=error,tolerance=tolerance(job)))\n",
    "    diagonal=mean_z_weights(n); native=Adapter(job[\"framework\"],n,op,output=\"qubo\",terms=mean_z_terms(n),weights=diagonal)\n",
    "    error=float(np.max(np.abs(native.readouts(rows)-expected)))\n",
    "    if error>tolerance(job): raise RuntimeError(\"native diagonal batch mismatch\")\n",
    "    checks.append(dict(case=\"native_diagonal_batch\",passed=True,native_readout_error=error,tolerance=tolerance(job)))\n",
    "    gradients=gradient_job({**job,\"track\":\"native_readout\",\"depth\":1})\n",
    "    checks.append(dict(case=\"parameter_shift_vs_finite_difference\",passed=True,max_gradient_error=gradients[\"max_gradient_error\"]))\n",
    "    return dict(checks=checks,internal_precision=\"complex64\" if job[\"framework\"]==\"cirq\" else \"complex128\")\n",
    "\n",
    "\n",
    "def preflight_job(job):\n",
    "    \"\"\"Exercise real native extensions before launching the larger campaign.\"\"\"\n",
    "    n=job[\"n_qubits\"]\n",
    "    operations=[(\"RY\",[0],\"input\"),(\"H\",[0],None),(\"CX\",[0,1],None),(\"RY\",[1],\"a\"),(\"RZ\",[0],\"b\")]\n",
    "    rows=[dict(input=.61,a=.31,b=-.27),dict(input=-.33,a=-.46,b=.19)]\n",
    "    state_adapter=Adapter(job[\"framework\"],n,operations)\n",
    "    bank=state_adapter.states(rows)\n",
    "    audit=bank_audit(job,bank,operations,rows)\n",
    "    reference=np.asarray([reference_state(n,operations,row) for row in rows])\n",
    "    native=Adapter(job[\"framework\"],n,operations,output=\"mean_z\",terms=mean_z_terms(n),weights=mean_z_weights(n))\n",
    "    error=float(np.max(np.abs(native.readouts(rows)-pauli_expectations(reference,mean_z_terms(n),n))))\n",
    "    if error>tolerance(job): raise RuntimeError(f\"native readout smoke mismatch: {error}\")\n",
    "    modules={\n",
    "        \"qiskit\":[\"qiskit\",\"qiskit_aer\"],\"pennylane\":[\"pennylane\",\"pennylane_lightning\"],\n",
    "        \"cirq\":[\"cirq\",\"qsimcirq\"],\"cirq_f64\":[\"cirq\"],\"qulacs\":[\"qulacs\"],\n",
    "    }.get(job[\"framework\"],[\"superfermion\",\"superfermion._sf_core\"])\n",
    "    return dict(**audit,native_readout_error=error,**adapter_metadata(state_adapter),\n",
    "        python_executable=sys.executable,python_version=sys.version,\n",
    "        isolated_python=bool(sys.flags.isolated),user_site_disabled=bool(sys.flags.no_user_site),\n",
    "        imported_module_files={name:str(getattr(importlib.import_module(name),\"__file__\",None)) for name in modules},\n",
    "        package_versions={package:importlib.metadata.version(package) for package in\n",
    "            [\"numpy\",\"scipy\",\"sympy\",\"autoray\",\"cirq-core\",\"qsimcirq\",\"pennylane\",\"pennylane-lightning\"]})\n",
    "\n",
    "\n",
    "def run(job):\n",
    "    task=job[\"task\"]\n",
    "    if task==\"preflight\": return preflight_job(job)\n",
    "    if task==\"validation\": return validation_job(job)\n",
    "    if task in [\"qsvm\",\"qkrr\",\"qkpca\"]: return kernel_job(job)\n",
    "    if task==\"classical\": return classical_job(job)\n",
    "    if task in [\"vqc\",\"vqr\"]: return variational_ml(job)\n",
    "    if task in [\"qaoa_fs\",\"maxcut\",\"vqe\"]: return optimization(job)\n",
    "    if task==\"gradient\": return gradient_job(job)\n",
    "    if task==\"circuit\": return circuit_job(job)\n",
    "    raise ValueError(task)\n",
    "\n",
    "\n",
    "if __name__==\"__main__\":\n",
    "    job=json.loads(Path(sys.argv[1]).read_text()); result=dict(job)\n",
    "    entry_rss,entry_source=current_rss_mib()\n",
    "    try:\n",
    "        result.update(run(job),status=\"ok\",memory_metric=(\"Windows psutil peak_wset at measured-stage end\" if os.name==\"nt\" else \"Linux process HWM at measured-stage end\")+\"; includes imports/preparation/warmup; not statevector-only memory\",\n",
    "                      memory_discovery_source=legacy_adapter.MEMORY_DISCOVERY_SOURCE)\n",
    "    except Exception as error:\n",
    "        result.update(status=\"error\",error=str(error),traceback=traceback.format_exc())\n",
    "    exit_rss,exit_source=current_rss_mib()\n",
    "    result.update(\n",
    "        worker_entry_rss_mib=entry_rss,\n",
    "        worker_exit_rss_mib=exit_rss,\n",
    "        worker_peak_rss_mib=peak_mb(),\n",
    "        primary_stage_peak_rss_mib=result.get(\"peak_measured_stage_mb\"),\n",
    "        worker_rss_change_mib=(exit_rss-entry_rss if entry_rss is not None and exit_rss is not None else None),\n",
    "        worker_entry_rss_source=entry_source,\n",
    "        worker_exit_rss_source=exit_source,\n",
    "        worker_memory_metric=(\"Windows psutil peak_wset at job end\" if os.name==\"nt\" else \"Linux process high-water RSS at job end\")+\", before JSON serialization; includes imports, preparation, warmup, fitting, inference, diagnostics and audits that the job performs\",\n",
    "        ram_units=\"MiB (2**20 bytes)\",\n",
    "    )\n",
    "    path=Path(sys.argv[2]); temporary=path.with_suffix(\".tmp\"); temporary.write_text(json.dumps(result,indent=2,allow_nan=False)); temporary.replace(path)\n",
    "    print(json.dumps({\"task\":job[\"task\"],\"framework\":job[\"framework\"],\"status\":result[\"status\"]}))\n",
    "    if result[\"status\"]!=\"ok\": raise SystemExit(1)\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'study_worker.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote study_worker.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74bce1c2",
   "metadata": {
    "id": "74bce1c2"
   },
   "source": [
    "#### Fresh-process pairing, fingerprints and checkpoints\n",
    "\n",
    "Open this source cell to inspect or modify `study_driver.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "f796bdbf",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "f796bdbf",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "00b279ac-6007-48f3-e796-5b750f192e88"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote study_driver.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Paired fresh-process campaigns, resumable fingerprints, and strict validity gates.\"\"\"\n",
    "import hashlib\n",
    "import itertools\n",
    "import json\n",
    "import os\n",
    "from pathlib import Path\n",
    "import random\n",
    "import subprocess\n",
    "import sys\n",
    "import time\n",
    "\n",
    "import pandas as pd\n",
    "from experiment_core import state_chunk_rows\n",
    "\n",
    "\n",
    "SCRIPT_NAMES=[\"legacy_adapter.py\",\"experiment_core.py\",\"prepare_study_data.py\",\n",
    "              \"study_worker.py\",\"study_driver.py\",\"analyze_study.py\",\"offline_checks.py\"]\n",
    "\n",
    "# -I ignores the notebook's PYTHONPATH/PYTHONHOME/user site and warning overrides.\n",
    "# Only the explicitly selected library site and the benchmark scripts are added.\n",
    "WORKER_BOOTSTRAP = \"\"\"\n",
    "import pathlib, runpy, sys\n",
    "worker, job, output, site = sys.argv[1:]\n",
    "sys.path.insert(0, str(pathlib.Path(worker).resolve().parent))\n",
    "if site:\n",
    "    sys.path.insert(0, site)\n",
    "sys.argv = [worker, job, output]\n",
    "runpy.run_path(worker, run_name=\"__main__\")\n",
    "\"\"\"\n",
    "REPORT_BOOTSTRAP = \"\"\"\n",
    "import pathlib, runpy, sys\n",
    "script, config = sys.argv[1:]\n",
    "sys.path.insert(0, str(pathlib.Path(script).resolve().parent))\n",
    "sys.argv = [script, config]\n",
    "runpy.run_path(script, run_name=\"__main__\")\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "def digest(value):\n",
    "    return hashlib.sha256(json.dumps(value,sort_keys=True,separators=(\",\",\":\"),allow_nan=False).encode()).hexdigest()\n",
    "\n",
    "\n",
    "def environment(config,framework,threads):\n",
    "    env=os.environ.copy()\n",
    "    for key in [\"PYTHONPATH\", \"PYTHONHOME\", \"PYTHONSTARTUP\", \"PYTHONWARNINGS\"]:\n",
    "        env.pop(key, None)\n",
    "    env.update(PYTHONNOUSERSITE=\"1\", PYTHONUNBUFFERED=\"1\")\n",
    "    if framework==\"classical\": threads=1\n",
    "    for k in [\"OPENBLAS_NUM_THREADS\",\"MKL_NUM_THREADS\",\"NUMEXPR_NUM_THREADS\",\"VECLIB_MAXIMUM_THREADS\"]: env[k]=\"1\"\n",
    "    env.update(OMP_NUM_THREADS=str(threads),OMP_DYNAMIC=\"FALSE\",RAYON_NUM_THREADS=str(threads),\n",
    "        QULACS_NUM_THREADS=str(threads),SIM_THREADS=str(threads),SF_F32=\"0\",PYTHONHASHSEED=\"0\")\n",
    "    for key in list(env):\n",
    "        if key.startswith(\"SF_\") and key!=\"SF_F32\": env.pop(key)\n",
    "    return env\n",
    "\n",
    "\n",
    "def invoke(config,job,force=False):\n",
    "    root=Path(config[\"root\"]); env=environment(config,job[\"framework\"],job[\"threads\"])\n",
    "    job={**job,\"warmups\":config[\"profile\"][\"warmups\"],\"inner_repetitions\":config[\"profile\"][\"inner_repetitions\"],\n",
    "         \"max_statebank_bytes\":config[\"max_statebank_bytes\"],\n",
    "         \"kernel_block_rows\":config[\"profile\"].get(\"kernel_block_rows\",128),\n",
    "         \"kernel_row_cap\":(config.get(\"kernel_row_caps\") or {}).get(job.get(\"n_qubits\")),\n",
    "         \"manifest_sha256\":config[\"manifest_sha256\"]}\n",
    "    fingerprint=dict(job=job,script_sha256={name:hashlib.sha256((root/name).read_bytes()).hexdigest() for name in SCRIPT_NAMES},\n",
    "        data_sha256=hashlib.sha256(Path(job[\"data_path\"]).read_bytes()).hexdigest() if \"data_path\" in job else None,\n",
    "        thread_environment={k:env.get(k) for k in [\"OMP_NUM_THREADS\",\"OMP_DYNAMIC\",\"RAYON_NUM_THREADS\",\"QULACS_NUM_THREADS\",\"SIM_THREADS\",\"SF_F32\",\"OPENBLAS_NUM_THREADS\"]})\n",
    "    job[\"cache_key\"]=digest(fingerprint); job[\"job_id\"]=job[\"cache_key\"][:24]\n",
    "    directory=root/\"raw\"; directory.mkdir(exist_ok=True)\n",
    "    path=directory/(job[\"job_id\"]+\".json\"); job_path=directory/(job[\"job_id\"]+\".config.json\")\n",
    "    log_path=directory/(job[\"job_id\"]+\".log\")\n",
    "    if path.exists() and not force:\n",
    "        old=json.loads(path.read_text())\n",
    "        if old.get(\"status\")==\"ok\" and old.get(\"cache_key\")==job[\"cache_key\"]: return old\n",
    "    job_path.write_text(json.dumps(job,indent=2)); path.unlink(missing_ok=True)\n",
    "    before = time.monotonic()\n",
    "    with log_path.open(\"w\") as log:\n",
    "        try:\n",
    "            execution=subprocess.run([config[\"python\"],\"-I\",\"-c\",WORKER_BOOTSTRAP,\n",
    "                str(root/\"study_worker.py\"),str(job_path),str(path),config[\"sites\"].get(job[\"framework\"],\"\")],cwd=root,env=env,\n",
    "                stdout=log,stderr=subprocess.STDOUT,timeout=config[\"profile\"][\"timeout_s\"])\n",
    "        except subprocess.TimeoutExpired: execution=None\n",
    "    if path.exists():\n",
    "        result=json.loads(path.read_text())\n",
    "        result.update(worker_log=str(log_path), worker_result=str(path),\n",
    "                      worker_wall_time_s=time.monotonic()-before,\n",
    "                      worker_returncode=execution.returncode if execution is not None else None)\n",
    "        if execution is None:\n",
    "            result.update(status=\"error\", error=\"timeout\")\n",
    "        if execution is not None and execution.returncode!=0 and result.get(\"status\")==\"ok\":\n",
    "            result.update(status=\"error\",error=\"worker reported success but exited nonzero\")\n",
    "        path.write_text(json.dumps(result,indent=2,allow_nan=False))\n",
    "        return result\n",
    "    result={**job,\"status\":\"error\",\"error\":\"timeout\" if execution is None else f\"worker exited {execution.returncode}\",\n",
    "            \"log_tail\":log_path.read_text(errors=\"replace\")[-6000:],\n",
    "            \"worker_log\":str(log_path),\"worker_result\":str(path),\n",
    "            \"worker_wall_time_s\":time.monotonic()-before,\n",
    "            \"worker_returncode\":execution.returncode if execution is not None else None}\n",
    "    path.write_text(json.dumps(result,indent=2)); return result\n",
    "\n",
    "\n",
    "def verify_manifest(config):\n",
    "    root=Path(config[\"root\"]); path=root/\"manifest.json\"\n",
    "    if hashlib.sha256(path.read_bytes()).hexdigest()!=config[\"manifest_sha256\"]: raise RuntimeError(\"manifest changed\")\n",
    "    manifest=json.loads(path.read_text())\n",
    "    for name,expected in manifest[\"script_sha256\"].items():\n",
    "        if hashlib.sha256((root/name).read_bytes()).hexdigest()!=expected: raise RuntimeError(f\"script changed: {name}; regenerate the manifest and rerun checks\")\n",
    "    inputs=json.loads((root/\"data_manifest.json\").read_text())\n",
    "    if digest(inputs)!=digest(manifest[\"data\"]): raise RuntimeError(\"dataset manifest changed\")\n",
    "    for key,path in inputs[\"paths\"].items():\n",
    "        if hashlib.sha256(Path(path).read_bytes()).hexdigest()!=inputs[\"sha256\"][key]: raise RuntimeError(f\"data changed: {key}\")\n",
    "    return inputs\n",
    "\n",
    "\n",
    "def report_failures(root, results, name):\n",
    "    failed = [result for result in results if result[\"status\"] != \"ok\"]\n",
    "    path = root/(name+\"_errors.json\")\n",
    "    if not failed:\n",
    "        path.unlink(missing_ok=True)\n",
    "        return\n",
    "    path.write_text(json.dumps(failed, indent=2))\n",
    "    for result in failed:\n",
    "        print(f\"\\nFAILED {result['framework']} / {result['n_qubits']} qubits: \"\n",
    "              f\"{result.get('error', 'unknown error')}\", flush=True)\n",
    "        print(result.get(\"traceback\", result.get(\"log_tail\", \"No traceback; inspect the worker log.\"))[-4000:], flush=True)\n",
    "        print(\"Worker log:\", result.get(\"worker_log\", \"unavailable\"), flush=True)\n",
    "\n",
    "\n",
    "def preflight(config):\n",
    "    root=Path(config[\"root\"]); results=[]\n",
    "    for framework in config[\"frameworks\"]:\n",
    "        result=invoke(config,dict(task=\"preflight\",framework=framework,dataset=\"backend_smoke\",\n",
    "            n_qubits=2,threads=1,repetition=0,seed=42,track=\"environment\",depth=1,\n",
    "            batch_size=2,iterations=1,feature_map=\"angle\",family=\"preflight\"))\n",
    "        results.append(result)\n",
    "        print(f\"Import/native smoke {framework}: {result['status']}\",flush=True)\n",
    "    (root/\"backend_preflight.json\").write_text(json.dumps(results,indent=2))\n",
    "    report_failures(root,results,\"backend_preflight\")\n",
    "    if any(result[\"status\"]!=\"ok\" for result in results):\n",
    "        raise RuntimeError(\"Backend preflight failed. The actual traceback is printed above and saved in backend_preflight_errors.json.\")\n",
    "    print(\"All eight installed backends passed isolated native-state/native-readout smoke checks.\",flush=True)\n",
    "\n",
    "\n",
    "def validate(config):\n",
    "    root=Path(config[\"root\"]); results=[]\n",
    "    (root/\"correctness_passed.json\").unlink(missing_ok=True)\n",
    "    (root/\"correctness.csv\").unlink(missing_ok=True)\n",
    "    for n,framework in itertools.product(config[\"profile\"][\"validation_qubits\"],config[\"frameworks\"]):\n",
    "        job=dict(task=\"validation\",framework=framework,dataset=\"independent_reference\",n_qubits=n,\n",
    "            threads=1,repetition=0,seed=42,track=\"correctness\",depth=1,batch_size=2,iterations=1,\n",
    "            feature_map=\"angle\",family=\"validation\")\n",
    "        result=invoke(config,job); results.append(result)\n",
    "        print(f'Checked {framework}, {n} qubits: {result[\"status\"]}',flush=True)\n",
    "    (root/\"validation_results.json\").write_text(json.dumps(results,indent=2))\n",
    "    failed=[r for r in results if r[\"status\"]!=\"ok\"]\n",
    "    report_failures(root,results,\"validation\")\n",
    "    if failed:\n",
    "        raise RuntimeError(\"Independent correctness checks failed. The actual worker tracebacks are printed above and saved in validation_errors.json; no performance ranking will run.\")\n",
    "    checks=[dict(framework=r[\"framework\"],n_qubits=r[\"n_qubits\"],**case) for r in results for case in r[\"checks\"]]\n",
    "    pd.DataFrame(checks).to_csv(root/\"correctness.csv\",index=False)\n",
    "    (root/\"correctness_passed.json\").write_text(json.dumps(dict(manifest_sha256=config[\"manifest_sha256\"],\n",
    "        configuration_sha256=digest(config),checks=len(checks))))\n",
    "    print(f'Passed {len(checks)} independent full-state/native-observable/gradient checks.',flush=True)\n",
    "\n",
    "\n",
    "def groups(config,inputs):\n",
    "    p=config[\"profile\"]; result=[]\n",
    "    dataset_audit={(row[\"dataset\"],row[\"n_qubits\"],row[\"seed\"]):row for row in inputs[\"datasets\"]}\n",
    "    optimization_steps=p.get(\"optimization_iterations\",p[\"iterations\"])\n",
    "    ml_steps=p.get(\"variational_iterations\",p[\"iterations\"])\n",
    "    def append(base,analytical=False):\n",
    "        base={\"dataset\":\"synthetic\",\"n_qubits\":p[\"qml_qubits\"][0],\n",
    "              \"feature_map\":\"angle\",\"family\":\"application\",\"track\":\"statevector\",\n",
    "              \"depth\":1,\"batch_size\":p[\"training_batch\"],\"iterations\":optimization_steps,\n",
    "              \"max_statebank_bytes\":config[\"max_statebank_bytes\"],\n",
    "              \"kernel_block_rows\":p.get(\"kernel_block_rows\",128),**base}\n",
    "        problem={k:v for k,v in base.items() if k!=\"framework\"}\n",
    "        base[\"problem_id\"]=digest(problem)[:20]\n",
    "        frameworks=[\"classical\"] if base.get(\"framework\")==\"classical\" else list(config[\"frameworks\"])\n",
    "        jobs=[dict(base,framework=f) for f in frameworks]\n",
    "        if analytical: jobs.append(dict(base,framework=\"analytical_angle\",track=\"analytical\"))\n",
    "        result.append(jobs)\n",
    "    outer=itertools.product(config[\"threads\"],range(p[\"repetitions\"]),p[\"seeds\"])\n",
    "    for threads,repetition,seed in outer:\n",
    "        common=dict(threads=threads,repetition=repetition,seed=seed)\n",
    "        for n in p[\"qml_qubits\"]:\n",
    "            condition=dict(common,n_qubits=n)\n",
    "            for name in p[\"classification_datasets\"]+p[\"regression_datasets\"]:\n",
    "                path=inputs[\"paths\"][f\"{name}:{n}:{seed}\"]\n",
    "                regression=name in p[\"regression_datasets\"]\n",
    "                for feature_map in p[\"kernel_maps\"]:\n",
    "                    append(dict(condition,task=\"qkrr\" if regression else \"qsvm\",dataset=name,\n",
    "                                feature_map=feature_map,data_path=path),analytical=feature_map==\"angle\")\n",
    "                if name in p[\"qkpca_datasets\"]:\n",
    "                    append(dict(condition,task=\"qkpca\",dataset=name,feature_map=\"zz\",data_path=path))\n",
    "                if name in p[\"feature_selection_datasets\"] and dataset_audit[(name,n,seed)].get(\"feature_selection_available\",True):\n",
    "                    for track in [\"statevector\",\"native_readout\"]:\n",
    "                        append(dict(condition,task=\"qaoa_fs\",dataset=name,track=track,\n",
    "                                    depth=p[\"qaoa_depth\"],data_path=path))\n",
    "                models=[\"ridge\",\"rbf_krr\",\"rf_regressor\"] if regression else [\"rbf_svc\",\"logistic\",\"rf_classifier\"]\n",
    "                for model in models:\n",
    "                    append(dict(condition,task=\"classical\",dataset=name,framework=\"classical\",model=model,\n",
    "                                kind=\"regression\" if regression else \"classification\",data_path=path))\n",
    "            for graph,track in itertools.product([\"ring\",\"erdos_renyi\"],[\"statevector\",\"native_readout\"]):\n",
    "                append(dict(condition,task=\"maxcut\",dataset=graph,track=track,depth=p[\"qaoa_depth\"]))\n",
    "        # VQC and VQR have a separate qubit grid and a separate iteration budget.\n",
    "        for n in p.get(\"variational_qubits\",p[\"qml_qubits\"]):\n",
    "            condition=dict(common,n_qubits=n)\n",
    "            for name in p[\"vqc_datasets\"]+p[\"vqr_datasets\"]:\n",
    "                path=inputs[\"paths\"][f\"{name}:{n}:{seed}\"]\n",
    "                for track,depth in itertools.product([\"statevector\",\"native_readout\"],p[\"variational_depths\"]):\n",
    "                    batch=dataset_audit[(name,n,seed)][\"train_samples\"] if p.get(\"variational_full_batch\",False) else p[\"training_batch\"]\n",
    "                    append(dict(condition,task=\"vqr\" if name in p[\"vqr_datasets\"] else \"vqc\",dataset=name,\n",
    "                                track=track,depth=depth,data_path=path,iterations=ml_steps,batch_size=batch,\n",
    "                                training_batch_mode=\"full_train_partition\" if p.get(\"variational_full_batch\",False) else \"minibatch\"))\n",
    "        for n,track in itertools.product(p[\"vqe_qubits\"],[\"statevector\",\"native_readout\"]):\n",
    "            append(dict(common,task=\"vqe\",dataset=\"TFIM_open_chain\",n_qubits=n,track=track,depth=2))\n",
    "        for n,track in itertools.product(p[\"gradient_qubits\"],[\"statevector\",\"native_readout\"]):\n",
    "            append(dict(common,task=\"gradient\",n_qubits=n,track=track,depth=1))\n",
    "        for n,family in itertools.product(p[\"state_qubits\"],[\"ghz\",\"qft\",\"random\"]):\n",
    "            append(dict(common,task=\"circuit\",family=family,n_qubits=n,batch_size=1,depth=2))\n",
    "        for n,family in itertools.product(p[\"map_qubits\"],[\"angle\",\"phase\",\"pauli\",\"zz\"]):\n",
    "            append(dict(common,task=\"circuit\",family=family,n_qubits=n,batch_size=p[\"map_batch\"],depth=1))\n",
    "        for n,batch in itertools.product(p.get(\"sweep_qubits\",[p[\"batch_qubits\"]]),p[\"batch_sizes\"]):\n",
    "            append(dict(common,task=\"circuit\",family=\"angle\",dataset=\"batch_sweep\",n_qubits=n,batch_size=batch,depth=1))\n",
    "        for n,depth in itertools.product(p.get(\"sweep_qubits\",[p[\"batch_qubits\"]]),p[\"circuit_depths\"]):\n",
    "            append(dict(common,task=\"circuit\",family=\"random\",dataset=\"depth_sweep\",n_qubits=n,batch_size=1,depth=depth))\n",
    "    return result\n",
    "\n",
    "\n",
    "\n",
    "def preview(config,inputs):\n",
    "    campaign=groups(config,inputs); jobs=[j for group in campaign for j in group]\n",
    "    table=pd.DataFrame(jobs)\n",
    "    dataset_sizes={(row[\"dataset\"],row[\"n_qubits\"],row[\"seed\"]):\n",
    "        row[\"train_samples\"]+row[\"test_samples\"] for row in inputs[\"datasets\"]}\n",
    "    maximum_split_sizes={(row[\"dataset\"],row[\"n_qubits\"],row[\"seed\"]):\n",
    "        max(row[\"train_samples\"],row[\"test_samples\"]) for row in inputs[\"datasets\"]}\n",
    "    counts=table.groupby([\"task\",\"framework\"]).size().unstack(fill_value=0)\n",
    "    counts.to_csv(Path(config[\"root\"])/\"planned_jobs.csv\")\n",
    "    # Exported-bank estimates follow the actual bounded execution strategy.\n",
    "    # Backend workspaces, reductions, audits and other copies need additional RAM.\n",
    "    budget_rows=[]\n",
    "    for job in jobs:\n",
    "        if job[\"task\"]==\"circuit\":\n",
    "            batch=job[\"batch_size\"]\n",
    "        elif job[\"task\"] in [\"qsvm\",\"qkrr\",\"qkpca\"]:\n",
    "            batch=dataset_sizes[(job[\"dataset\"],job[\"n_qubits\"],job[\"seed\"])]\n",
    "            kernel_cap=(config.get(\"kernel_row_caps\") or {}).get(job[\"n_qubits\"])\n",
    "            if kernel_cap: batch=min(batch,2*int(kernel_cap))\n",
    "        elif job[\"task\"] in [\"vqc\",\"vqr\"]:\n",
    "            batch=maximum_split_sizes[(job[\"dataset\"],job[\"n_qubits\"],job[\"seed\"])]\n",
    "        else:\n",
    "            batch=1\n",
    "        logical_bank=batch*(1 << job[\"n_qubits\"])*16\n",
    "        if job[\"task\"]==\"classical\":\n",
    "            logical_bank=0;bank=0;strategy=\"classical_no_state_bank\"\n",
    "        elif job[\"task\"] in [\"qsvm\",\"qkrr\",\"qkpca\"]:\n",
    "            if job[\"framework\"]==\"analytical_angle\":\n",
    "                chunk=state_chunk_rows(job[\"n_qubits\"],config[\"max_statebank_bytes\"],2,config[\"profile\"].get(\"kernel_block_rows\",128))\n",
    "                bank=min(6,2*chunk)*(1 << job[\"n_qubits\"])*16\n",
    "                strategy=\"analytical_with_blocked_reference_audit\"\n",
    "            elif logical_bank<=config[\"max_statebank_bytes\"]:\n",
    "                bank=logical_bank;strategy=\"retained_state_bank\"\n",
    "            else:\n",
    "                chunk=state_chunk_rows(job[\"n_qubits\"],config[\"max_statebank_bytes\"],2,config[\"profile\"].get(\"kernel_block_rows\",128))\n",
    "                bank=min(batch,2*chunk)*(1 << job[\"n_qubits\"])*16\n",
    "                strategy=\"bounded_reencoding_blocks\"\n",
    "        else:\n",
    "            count=4*job[\"n_qubits\"]*job[\"depth\"] if job[\"task\"]==\"gradient\" else batch\n",
    "            chunk=state_chunk_rows(job[\"n_qubits\"],config[\"max_statebank_bytes\"],1 if job[\"task\"]==\"circuit\" else 2)\n",
    "            bank=min(count,chunk)*(1 << job[\"n_qubits\"])*16\n",
    "            strategy=\"chunked_state_exports\" if job[\"task\"]==\"circuit\" else \"chunked_readout_evaluations\"\n",
    "        budget_rows.append(dict(task=job[\"task\"],dataset=job[\"dataset\"],framework=job[\"framework\"],\n",
    "            n_qubits=job[\"n_qubits\"],track=job[\"track\"],seed=job[\"seed\"],repetition=job[\"repetition\"],\n",
    "            execution_strategy=strategy,logical_statebank_mib=logical_bank/2**20,\n",
    "            estimated_statebank_mib=bank/2**20,limit_mib=config[\"max_statebank_bytes\"]/2**20,\n",
    "            limit_exceeded=bank>config[\"max_statebank_bytes\"]))\n",
    "    budgets=pd.DataFrame(budget_rows)\n",
    "    budgets.to_csv(Path(config[\"root\"])/\"statebank_budget.csv\",index=False)\n",
    "    report=dict(jobs=len(jobs),paired_groups=len(campaign),profile=config[\"profile_name\"],\n",
    "                frameworks=config[\"frameworks\"],fresh_process_repetitions=config[\"profile\"][\"repetitions\"],\n",
    "                split_seeds=config[\"profile\"][\"seeds\"],max_statebank_bytes=config[\"max_statebank_bytes\"],\n",
    "                max_jobs=config[\"max_jobs\"],job_limit_exceeded=len(jobs)>config[\"max_jobs\"],\n",
    "                statebank_limit_exceeded_jobs=int(budgets.limit_exceeded.sum()),\n",
    "                kernel_row_caps=config.get(\"kernel_row_caps\") or {},\n",
    "                largest_estimated_statebank_mib=float(budgets.estimated_statebank_mib.max()))\n",
    "    (Path(config[\"root\"])/\"campaign_plan.json\").write_text(json.dumps(report,indent=2))\n",
    "    print(json.dumps(report,indent=2)); print(counts.to_string())\n",
    "    if budgets.limit_exceeded.any():\n",
    "        print(budgets[budgets.limit_exceeded].head(8).to_string(index=False),flush=True)\n",
    "        raise RuntimeError(\"Requested state banks exceed MAX_STATEBANK_MIB; campaign_plan.json and statebank_budget.csv contain the requirements. Review the qubit/sample/batch settings or memory budget before launching.\")\n",
    "    return campaign\n",
    "\n",
    "\n",
    "def campaign(config,inputs,family=None):\n",
    "    root=Path(config[\"root\"]); gate=json.loads((root/\"correctness_passed.json\").read_text())\n",
    "    if gate[\"manifest_sha256\"]!=config[\"manifest_sha256\"] or gate[\"configuration_sha256\"]!=digest(config):\n",
    "        raise RuntimeError(\"correctness gate belongs to a different build/configuration\")\n",
    "    campaign=groups(config,inputs)\n",
    "    if family: campaign=[g for g in campaign if g[0][\"task\"] in family.split(\",\")]\n",
    "    count=sum(len(g) for g in campaign)\n",
    "    if count>config[\"max_jobs\"]: raise RuntimeError(f\"{count} jobs exceed MAX_JOBS={config['max_jobs']}; inspect the plan and raise the visible budget to run this profile\")\n",
    "    rng=random.Random(96331); rng.shuffle(campaign)\n",
    "    if config.get(\"order_qubits_first\",False):campaign.sort(key=lambda group:group[0][\"n_qubits\"])\n",
    "    for group in campaign: rng.shuffle(group)\n",
    "    rows=[]; before=time.monotonic()\n",
    "    path=root/(\"results_\"+(family.replace(\",\",\"_\") if family else \"all\")+\".json\")\n",
    "    path.write_text(\"[]\")\n",
    "    report_after=float(config.get(\"report_refresh_seconds\",0))\n",
    "    last_report=time.monotonic()\n",
    "    print(f\"Executing {count} jobs sequentially in fresh processes. Cached successes may resume.\",flush=True)\n",
    "    for i,job in enumerate([j for group in campaign for j in group],1):\n",
    "        result=invoke(config,job); rows.append(result)\n",
    "        if i%8==0 or result[\"status\"]!=\"ok\" or i==count:\n",
    "            print(f'{i}/{count}: {job[\"task\"]} {job[\"dataset\"]} {job[\"framework\"]}: {result[\"status\"]}; elapsed {time.monotonic()-before:.1f}s',flush=True)\n",
    "            path.write_text(json.dumps(rows,indent=2))\n",
    "        if report_after>0 and time.monotonic()-last_report>=report_after:\n",
    "            # Run between workers so report generation does not compete with a timed job.\n",
    "            report_config=root/\"periodic_report_config.json\"\n",
    "            report_config.write_text(json.dumps(config,indent=2))\n",
    "            report_env=environment(config,\"classical\",1);report_env[\"MPLBACKEND\"]=\"Agg\"\n",
    "            report_log=root/\"periodic_reports.log\"\n",
    "            with report_log.open(\"a\") as log:\n",
    "                refresh=subprocess.run([config[\"python\"],\"-I\",\"-c\",REPORT_BOOTSTRAP,\n",
    "                    str(root/\"analyze_study.py\"),str(report_config)],cwd=root,env=report_env,\n",
    "                    stdout=log,stderr=subprocess.STDOUT)\n",
    "            print(\"Time/RAM figures refreshed from checkpoints.\" if refresh.returncode==0 else\n",
    "                  f\"Report refresh failed ({refresh.returncode}); inspect {report_log.name}.\",flush=True)\n",
    "            last_report=time.monotonic()\n",
    "        if result[\"status\"]!=\"ok\" and config.get(\"fail_fast\",True):\n",
    "            (root/\"latest_failure.json\").write_text(json.dumps(result,indent=2))\n",
    "            report_failures(root,[result],\"benchmark\")\n",
    "            raise RuntimeError(\"Benchmark failed; inspect latest_failure.json. Successful checkpoints are retained.\")\n",
    "    path.write_text(json.dumps(rows,indent=2))\n",
    "    (root/(\"campaign_receipt_\"+path.stem+\".json\")).write_text(json.dumps(dict(jobs=count,\n",
    "        success=sum(r[\"status\"]==\"ok\" for r in rows),failed=sum(r[\"status\"]!=\"ok\" for r in rows),\n",
    "        manifest_sha256=config[\"manifest_sha256\"],wall_time_s=time.monotonic()-before),indent=2))\n",
    "    print(f\"Saved {path.name}: {len(rows)} measured jobs.\",flush=True)\n",
    "\n",
    "\n",
    "if __name__==\"__main__\":\n",
    "    config=json.loads(Path(sys.argv[1]).read_text()); inputs=verify_manifest(config)\n",
    "    action=sys.argv[2]\n",
    "    if action==\"preflight\": preflight(config)\n",
    "    elif action==\"validate\": validate(config)\n",
    "    elif action==\"preview\": preview(config,inputs)\n",
    "    elif action==\"run\": campaign(config,inputs,sys.argv[3] if len(sys.argv)>3 else None)\n",
    "    else: raise ValueError(action)\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'study_driver.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote study_driver.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b5ce503",
   "metadata": {
    "id": "9b5ce503"
   },
   "source": [
    "#### Editable statistics and plotting code\n",
    "\n",
    "Open this source cell to inspect or modify `analyze_study.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bf158eb4",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "bf158eb4",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "d4e25afb-7d65-4406-cef6-ac7874b1ebc7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote analyze_study.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Inspectable medians, paired comparisons, outcome audits, and scientific figures.\"\"\"\n",
    "import json\n",
    "import hashlib\n",
    "import os\n",
    "from pathlib import Path\n",
    "import sys\n",
    "\n",
    "import matplotlib\n",
    "matplotlib.use(\"Agg\")\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "from study_driver import groups, verify_manifest\n",
    "\n",
    "LABELS={\"superfermion_optimized\":\"SF modified\", \"superfermion_source_baseline\":\"SF source\",\n",
    "        \"superfermion_wheel\":\"SF published\", \"qiskit\":\"Aer f64\", \"pennylane\":\"Lightning f64\",\n",
    "        \"cirq\":\"qsim f32\", \"cirq_f64\":\"Cirq f64\", \"qulacs\":\"Qulacs f64\", \"analytical_angle\":\"Analytical Angle\"}\n",
    "ORDER=[\"superfermion_optimized\",\"superfermion_source_baseline\",\"superfermion_wheel\",\n",
    "       \"qiskit\",\"pennylane\",\"qulacs\",\"cirq\",\"cirq_f64\"]\n",
    "COLORS={\"superfermion_optimized\":\"#174c78\",\"superfermion_source_baseline\":\"#668aa8\",\n",
    "        \"superfermion_wheel\":\"#a5b9c9\",\"qiskit\":\"#a38120\",\"pennylane\":\"#b96121\",\n",
    "        \"qulacs\":\"#984d72\",\"cirq\":\"#5c6269\",\"cirq_f64\":\"#949ba1\",\"analytical_angle\":\"#23272b\"}\n",
    "MARKERS=dict(zip(ORDER,[\"o\",\"s\",\"^\",\"D\",\"v\",\"P\",\"x\",\"*\"]))\n",
    "CONDITION=[\"task\",\"dataset\",\"n_qubits\",\"feature_map\",\"family\",\"track\",\"depth\",\"batch_size\",\n",
    "           \"iterations\",\"threads\",\"seed\",\"model\"]\n",
    "METRICS=[\"accuracy\",\"balanced_accuracy\",\"f1_macro\",\"roc_auc\",\"rmse\",\"mae\",\"r2\",\"final_loss\",\n",
    "         \"final_energy\",\"ground_energy\",\"energy_gap\",\"approximation_ratio\",\"optimum_probability\",\n",
    "         \"fs_downstream_accuracy\",\"qkpca_variance_fraction\",\"max_gradient_error\"]\n",
    "RAM_METRICS={\"worker_peak\":\"worker_peak_rss_mib\",\n",
    "             \"primary_stage_peak\":\"primary_stage_peak_rss_mib\",\n",
    "             \"entry_rss\":\"worker_entry_rss_mib\", \"exit_rss\":\"worker_exit_rss_mib\",\n",
    "             \"rss_change\":\"worker_rss_change_mib\"}\n",
    "RAM_TASKS=[\"qsvm\",\"qkrr\",\"qkpca\",\"vqc\",\"vqr\",\"qaoa_fs\",\"maxcut\",\"vqe\",\"gradient\",\"circuit\"]\n",
    "RAM_TASK_LABELS={\"qsvm\":\"QSVM\",\"qkrr\":\"QKRR\",\"qkpca\":\"QKPCA\",\"vqc\":\"VQC\",\"vqr\":\"VQR\",\n",
    "                 \"qaoa_fs\":\"QAOA FS\",\"maxcut\":\"MaxCut\",\"vqe\":\"VQE\",\"gradient\":\"Gradient\",\"circuit\":\"Circuit\"}\n",
    "\n",
    "\n",
    "def style():\n",
    "    plt.rcParams.update({\"figure.dpi\":110,\"savefig.dpi\":150,\"font.size\":11,\"axes.titlesize\":12,\n",
    "        \"axes.labelsize\":11,\"xtick.labelsize\":10,\"ytick.labelsize\":10,\"figure.facecolor\":\"white\",\n",
    "        \"axes.spines.top\":False,\"axes.spines.right\":False,\"axes.axisbelow\":True,\n",
    "        \"grid.color\":\"#e2e5e8\",\"grid.linewidth\":.6,\"lines.linewidth\":1.6})\n",
    "\n",
    "\n",
    "def load_results(root,manifest_sha):\n",
    "    indexed={}\n",
    "    for path in root.glob(\"results_*.json\"):\n",
    "        for row in json.loads(path.read_text()):\n",
    "            if row.get(\"manifest_sha256\")==manifest_sha: indexed[row[\"job_id\"]]=row\n",
    "    # Include per-job checkpoints when a campaign has not finished its section.\n",
    "    for path in (root/\"raw\").glob(\"*.json\"):\n",
    "        if path.name.endswith(\".config.json\"):continue\n",
    "        row=json.loads(path.read_text())\n",
    "        if row.get(\"manifest_sha256\")==manifest_sha and row.get(\"task\") not in [\"preflight\",\"validation\"] and \"status\" in row:\n",
    "            indexed[row[\"job_id\"]]=row\n",
    "    return list(indexed.values())\n",
    "\n",
    "\n",
    "def html_table(root,name,table,limit=100):\n",
    "    table.to_csv(root/(name+\".csv\"),index=False)\n",
    "    css=\"\"\"<style>table {border-collapse:collapse; font:13px system-ui,sans-serif;} th,td{padding:6px 9px;text-align:left;border-bottom:1px solid #ddd;} th{background:#eef3f7;} </style>\"\"\"\n",
    "    (root/(name+\".html\")).write_text(css+table.head(limit).to_html(index=False,float_format=lambda x:f\"{x:.4g}\"))\n",
    "\n",
    "\n",
    "def aggregate(frame):\n",
    "    result=[]\n",
    "    for key,subset in frame.groupby(CONDITION+[\"framework\"],dropna=False,sort=False):\n",
    "        row=dict(zip(CONDITION+[\"framework\"],key))\n",
    "        x=subset[\"primary_runtime_s\"].to_numpy()*1000\n",
    "        row.update(median_ms=float(np.median(x)),q25_ms=float(np.quantile(x,.25)),q75_ms=float(np.quantile(x,.75)),\n",
    "            repetitions=len(x),end_to_end_median_ms=float(subset.get(\"end_to_end_s\",subset.primary_runtime_s).median()*1000),\n",
    "            peak_process_hwm_mib=float(subset.peak_measured_stage_mb.median()))\n",
    "        for metric in METRICS:\n",
    "            if metric in subset: row[metric]=float(subset[metric].median()) if subset[metric].notna().any() else np.nan\n",
    "        result.append(row)\n",
    "    return pd.DataFrame(result,columns=CONDITION+[\"framework\",\"median_ms\",\"q25_ms\",\"q75_ms\",\n",
    "        \"repetitions\",\"end_to_end_median_ms\",\"peak_process_hwm_mib\"]+METRICS)\n",
    "\n",
    "\n",
    "def ram_aggregate(frame, keys):\n",
    "    \"\"\"Summarize per-job RSS measurements; never sum process peaks.\"\"\"\n",
    "    records=[]\n",
    "    for key,part in frame.groupby(keys,dropna=False,sort=False):\n",
    "        if not isinstance(key,tuple): key=(key,)\n",
    "        record=dict(zip(keys,key))\n",
    "        ok=part[part.status==\"ok\"]\n",
    "        available=ok[np.isfinite(ok.worker_peak_rss_mib)&(ok.worker_peak_rss_mib>0)]\n",
    "        record.update(jobs=len(part),successful_jobs=len(ok),failed_jobs=len(part)-len(ok),\n",
    "            measured_jobs=len(available),missing_peak_jobs=len(ok)-len(available),\n",
    "            conditions=int(available[CONDITION].drop_duplicates().shape[0]),\n",
    "            datasets=int(available.dataset.nunique()),tasks=int(available.task.nunique()))\n",
    "        for prefix,column in RAM_METRICS.items():\n",
    "            values=available[column].dropna().to_numpy(dtype=float)\n",
    "            values=values[np.isfinite(values)]\n",
    "            record[prefix+\"_measured_jobs\"]=len(values)\n",
    "            for suffix,quantile in [(\"min\",0),(\"q25\",.25),(\"median\",.5),(\"q75\",.75),(\"p95\",.95),(\"max\",1)]:\n",
    "                record[f\"{prefix}_{suffix}_mib\"]=float(np.quantile(values,quantile)) if len(values) else np.nan\n",
    "        records.append(record)\n",
    "    columns=keys+[\"jobs\",\"successful_jobs\",\"failed_jobs\",\"measured_jobs\",\"missing_peak_jobs\",\n",
    "                  \"conditions\",\"datasets\",\"tasks\"]\n",
    "    for prefix in RAM_METRICS:\n",
    "        columns += [prefix+\"_measured_jobs\"]+[f\"{prefix}_{s}_mib\" for s in [\"min\",\"q25\",\"median\",\"q75\",\"p95\",\"max\"]]\n",
    "    return pd.DataFrame(records,columns=columns)\n",
    "\n",
    "\n",
    "def ram_reports(root, rows, config):\n",
    "    \"\"\"Raw, condition-level, framework/task and matched RAM reports.\"\"\"\n",
    "    collected={row[\"job_id\"]:row for row in rows}\n",
    "    for name in [\"backend_preflight.json\",\"validation_results.json\"]:\n",
    "        path=root/name\n",
    "        if path.exists():\n",
    "            for row in json.loads(path.read_text()):\n",
    "                if row.get(\"manifest_sha256\")==config[\"manifest_sha256\"]:\n",
    "                    collected[row[\"job_id\"]]=row\n",
    "    frame=pd.DataFrame([{k:v for k,v in row.items() if not isinstance(v,(list,dict))}\n",
    "                        for row in collected.values()])\n",
    "    if frame.empty:frame=pd.DataFrame(columns=list(dict.fromkeys([\"job_id\",\"framework\",\"status\"]+CONDITION)))\n",
    "    for column in CONDITION:\n",
    "        if column not in frame: frame[column]=\"none\"\n",
    "    frame[\"model\"]=frame.model.fillna(\"none\")\n",
    "    if \"repetition\" not in frame:frame[\"repetition\"]=np.nan\n",
    "    for column in RAM_METRICS.values():\n",
    "        if column not in frame: frame[column]=np.nan\n",
    "        frame[column]=pd.to_numeric(frame[column],errors=\"coerce\")\n",
    "    frame[\"lane_kind\"]=frame.framework.map(lambda f:\n",
    "        \"simulator\" if f in config[\"frameworks\"] else \"analytical\" if f==\"analytical_angle\" else \"classical\")\n",
    "    ordered=[\"job_id\",\"framework\",\"lane_kind\",\"backend\",\"internal_precision\"]+CONDITION+[\n",
    "        \"repetition\",\"status\",\"train_samples\",\"test_samples\"]+list(RAM_METRICS.values())+[\n",
    "        \"worker_entry_rss_source\",\"worker_exit_rss_source\",\"error\"]\n",
    "    html_table(root,\"ram_per_job\",frame[[c for c in ordered if c in frame]],80)\n",
    "    diagnostics=frame[frame.task.isin([\"preflight\",\"validation\"])].copy()\n",
    "    html_table(root,\"ram_backend_checks\",diagnostics[[c for c in ordered if c in frame]],40)\n",
    "    benchmark=frame[~frame.task.isin([\"preflight\",\"validation\"])].copy()\n",
    "    successful=benchmark[benchmark.status==\"ok\"]\n",
    "    valid=np.isfinite(successful.worker_peak_rss_mib)&(successful.worker_peak_rss_mib>0)\n",
    "    if not valid.all():\n",
    "        raise RuntimeError(\"Successful jobs are missing worker peak RAM. Inspect ram_per_job.csv and rerun those jobs.\")\n",
    "    stages=successful.primary_stage_peak_rss_mib.dropna()\n",
    "    if (successful.loc[stages.index,\"worker_peak_rss_mib\"]+1e-9<stages).any():\n",
    "        raise RuntimeError(\"A worker peak is below its earlier primary-stage high-water mark.\")\n",
    "    tables={\n",
    "        \"ram_by_condition\":ram_aggregate(benchmark,CONDITION+[\"framework\"]),\n",
    "        \"ram_by_framework_task\":ram_aggregate(benchmark,[\"framework\",\"task\",\"track\",\"threads\"]),\n",
    "        \"ram_framework_summary\":ram_aggregate(benchmark,[\"framework\",\"threads\"]),\n",
    "    }\n",
    "    for name,table in tables.items(): html_table(root,name,table,100)\n",
    "    pairs=[]\n",
    "    simulators=successful[successful.framework.isin(config[\"frameworks\"])]\n",
    "    for key,part in simulators.groupby(CONDITION+[\"repetition\"],dropna=False,sort=False):\n",
    "        if len(part)!=len(config[\"frameworks\"]) or set(part.framework)!=set(config[\"frameworks\"]): continue\n",
    "        modified=float(part.loc[part.framework==\"superfermion_optimized\",\"worker_peak_rss_mib\"].iloc[0])\n",
    "        for _,row in part.iterrows():\n",
    "            if row.framework==\"superfermion_optimized\": continue\n",
    "            record=dict(zip(CONDITION+[\"repetition\"],key))\n",
    "            record.update(competitor=row.framework,competitor_peak_mib=float(row.worker_peak_rss_mib),\n",
    "                modified_peak_mib=modified,competitor_over_modified_ram=float(row.worker_peak_rss_mib/modified),\n",
    "                competitor_minus_modified_mib=float(row.worker_peak_rss_mib-modified))\n",
    "            pairs.append(record)\n",
    "    pair_columns=CONDITION+[\"repetition\",\"competitor\",\"competitor_peak_mib\",\"modified_peak_mib\",\n",
    "                            \"competitor_over_modified_ram\",\"competitor_minus_modified_mib\"]\n",
    "    html_table(root,\"ram_paired_comparisons\",pd.DataFrame(pairs,columns=pair_columns),100)\n",
    "    methodology=dict(units=\"MiB (2**20 bytes)\",scope=\"CPU worker process resident RAM, including native allocations\",\n",
    "        worker_peak=(\"Windows psutil peak_wset at job end\" if os.name==\"nt\" else \"OS ru_maxrss/1024 at job end\")+\"; includes imports, setup, warmup and all later stages/audits performed by that job; sampled before JSON serialization\",\n",
    "        primary_stage_peak=(\"Windows psutil peak_wset\" if os.name==\"nt\" else \"Existing OS high-water mark\")+\" at the primary stage endpoint; includes earlier imports/setup/warmup and is not a resettable stage-only allocation counter\",\n",
    "        entry_exit=(\"Windows psutil current RSS before/after run(job)\" if os.name==\"nt\" else \"Current resident pages from /proc/self/statm before/after run(job)\")+\"; missing measurements stay missing, never a substituted high-water mark\",\n",
    "        rss_change=\"Exit minus entry resident RSS; retained change, not peak allocation; can be negative\",\n",
    "        aggregation=\"Median, IQR, P95 and maximum of per-job measurements, using successful jobs; not time-averaged RSS; failed and missing counts retained\",\n",
    "        overview=\"Framework and task summaries pool campaign settings; conditions and job counts are recorded; they are descriptive, not universal framework rankings\",\n",
    "        comparisons=\"Use ram_by_condition.csv or complete matched groups in ram_paired_comparisons.csv; compare the same dataset, seed, qubits, track, depth, batch, iterations, threads and model\",\n",
    "        limitations=[\"Does not measure GPU memory, virtual address size, whole-machine RAM or child-process memory\",\n",
    "                     \"Shared resident pages mean process RSS values must not be summed as physical-machine RAM\",\n",
    "                     \"Current RSS snapshots can miss transient peaks; OS worker high-water marks retain those peaks\",\n",
    "                     \"Preflight/validation footprints are exported separately from benchmark summaries\"])\n",
    "    (root/\"ram_methodology.json\").write_text(json.dumps(methodology,indent=2))\n",
    "    tables[\"ram_per_job\"]=frame\n",
    "    return tables\n",
    "\n",
    "\n",
    "def task_cost_reports(root,rows,config,inputs):\n",
    "    \"\"\"Every planned condition/qubit, including failures and pending jobs.\"\"\"\n",
    "    planned=[job for group in groups(config,inputs) for job in group]\n",
    "    key_fields=CONDITION+[\"repetition\",\"framework\"]\n",
    "    def key(row):return tuple(row.get(k,\"none\") for k in key_fields)\n",
    "    indexed={key(row):row for row in rows}\n",
    "    records=[]\n",
    "    for job in planned:\n",
    "        result=indexed.get(key(job))\n",
    "        record={**job,**(result or {})}\n",
    "        record[\"status\"]=result[\"status\"] if result else \"not_started\"\n",
    "        record[\"model\"]=record.get(\"model\",\"none\")\n",
    "        for metric in [\"primary_runtime_s\",\"worker_wall_time_s\",\"worker_peak_rss_mib\"]:\n",
    "            record[metric]=record.get(metric,np.nan)\n",
    "        records.append({k:v for k,v in record.items() if not isinstance(v,(dict,list))})\n",
    "    frame=pd.DataFrame(records)\n",
    "    html_table(root,\"experiment_job_status\",frame,100)\n",
    "    result=[]\n",
    "    for k,part in frame.groupby(CONDITION+[\"framework\"],dropna=False,sort=False):\n",
    "        record=dict(zip(CONDITION+[\"framework\"],k))\n",
    "        ok=part[part.status==\"ok\"]\n",
    "        record.update(expected_jobs=len(part),successful_jobs=len(ok),\n",
    "            failed_jobs=int((part.status==\"error\").sum()),pending_jobs=int((part.status==\"not_started\").sum()))\n",
    "        for source,prefix in [(\"primary_runtime_s\",\"primary_runtime\"),\n",
    "                              (\"worker_wall_time_s\",\"worker_wall_time\"),\n",
    "                              (\"worker_peak_rss_mib\",\"worker_peak\")]:\n",
    "            values=pd.to_numeric(ok[source],errors=\"coerce\").dropna().to_numpy(dtype=float)\n",
    "            values=values[np.isfinite(values)&(values>0)]\n",
    "            for suffix,q in [(\"q25\",.25),(\"median\",.5),(\"q75\",.75)]:\n",
    "                units=\"mib\" if source==\"worker_peak_rss_mib\" else \"s\"\n",
    "                record[f\"{prefix}_{suffix}_{units}\"]=float(np.quantile(values,q)) if len(values) else np.nan\n",
    "        result.append(record)\n",
    "    summary=pd.DataFrame(result)\n",
    "    html_table(root,\"all_experiment_time_ram\",summary,100)\n",
    "    return summary,frame\n",
    "\n",
    "\n",
    "def summarize_pairs(frame,frameworks):\n",
    "    pairs=[]; coverage=[]\n",
    "    simulators=frame[frame.framework.isin(frameworks)]\n",
    "    for key,subset in simulators.groupby(CONDITION+[\"repetition\"],dropna=False,sort=False):\n",
    "        base=dict(zip(CONDITION+[\"repetition\"],key)); present=set(subset.framework)\n",
    "        complete=present==set(frameworks) and len(subset)==len(frameworks)\n",
    "        coverage.append(dict(base,complete=complete,present=\";\".join(sorted(present))))\n",
    "        if not complete: continue\n",
    "        modified=float(subset[subset.framework==\"superfermion_optimized\"].primary_runtime_s.iloc[0])\n",
    "        for _,row in subset.iterrows():\n",
    "            if row.framework==\"superfermion_optimized\": continue\n",
    "            pairs.append(dict(base,competitor=row.framework,competitor_over_modified=float(row.primary_runtime_s/modified)))\n",
    "    return pd.DataFrame(pairs,columns=CONDITION+[\"repetition\",\"competitor\",\"competitor_over_modified\"]),pd.DataFrame(coverage,columns=CONDITION+[\"repetition\",\"complete\",\"present\"])\n",
    "\n",
    "\n",
    "def audit_outcomes(rows,frameworks):\n",
    "    buckets={}\n",
    "    for row in rows:\n",
    "        if row.get(\"status\")!=\"ok\" or row[\"framework\"] not in frameworks: continue\n",
    "        key=tuple(row.get(k,\"none\") for k in CONDITION+[\"repetition\"])\n",
    "        buckets.setdefault(key,[]).append(row)\n",
    "    result=[]\n",
    "    for key,group in buckets.items():\n",
    "        ref=next((r for r in group if r[\"framework\"]==\"superfermion_source_baseline\"),None)\n",
    "        if not ref: continue\n",
    "        for row in group:\n",
    "            record=dict(zip(CONDITION+[\"repetition\"],key)); record.update(framework=row[\"framework\"])\n",
    "            if \"predictions\" in ref and \"predictions\" in row:\n",
    "                a,b=np.asarray(row[\"predictions\"]),np.asarray(ref[\"predictions\"])\n",
    "                record[\"prediction_max_difference\"]=float(np.max(np.abs(a-b)))\n",
    "                record[\"prediction_mismatches\"]=int(np.sum(a!=b)) if row[\"task\"] in [\"qsvm\",\"qkpca\",\"vqc\"] else None\n",
    "            for metric in [\"final_energy\",\"final_loss\",\"balanced_accuracy\",\"rmse\"]:\n",
    "                if metric in ref and metric in row: record[metric+\"_difference\"]=abs(row[metric]-ref[metric])\n",
    "            for field in [\"kernel_probe\",\"test_kernel_probe\",\"gradient\",\"optimization_trace\"]:\n",
    "                if field in ref and field in row:\n",
    "                    record[field+\"_max_difference\"]=float(np.max(np.abs(np.asarray(row[field])-np.asarray(ref[field]))))\n",
    "            result.append(record)\n",
    "    return pd.DataFrame(result)\n",
    "\n",
    "\n",
    "class Figures:\n",
    "    def __init__(self,root): self.root=root; self.paths={}; (root/\"figures\").mkdir(exist_ok=True)\n",
    "    def save(self,key,fig):\n",
    "        fig.savefig(self.root/\"figures\"/(key+\".png\"),bbox_inches=\"tight\")\n",
    "        fig.savefig(self.root/\"figures\"/(key+\".svg\"),bbox_inches=\"tight\")\n",
    "        plt.close(fig); self.paths[key]=str(self.root/\"figures\"/(key+\".png\"))\n",
    "\n",
    "    def ram(self,tables):\n",
    "        overview=tables[\"ram_framework_summary\"]\n",
    "        overview=overview[overview.framework.isin(ORDER)&(overview.measured_jobs>0)]\n",
    "        if overview.empty: return\n",
    "        threads=int(overview.threads.min())\n",
    "        overview=overview[overview.threads==threads]\n",
    "        order=[f for f in ORDER if f in set(overview.framework)]\n",
    "        fig,ax=plt.subplots(figsize=(10.5,6))\n",
    "        for index,framework in enumerate(order):\n",
    "            row=overview[overview.framework==framework].iloc[0]\n",
    "            ax.errorbar(row.worker_peak_median_mib,index,\n",
    "                xerr=[[row.worker_peak_median_mib-row.worker_peak_q25_mib],\n",
    "                      [row.worker_peak_q75_mib-row.worker_peak_median_mib]],\n",
    "                fmt=MARKERS[framework],color=COLORS[framework],capsize=3,markersize=7)\n",
    "        ax.set(yticks=range(len(order)),yticklabels=[LABELS[f] for f in order],\n",
    "               xlabel=\"Worker peak resident RAM (MiB)\",xlim=(0,None),\n",
    "               title=f\"RAM per simulator framework · {threads} thread budget\")\n",
    "        ax.set_ylim(len(order)-.5,-.5);ax.grid(axis=\"x\")\n",
    "        fig.text(.5,.015,\"Median / IQR of per-job peaks across benchmark tasks and settings; includes setup and audits.\\nPooled description, not a matched ranking. See condition and paired RAM tables.\",\n",
    "                 ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout(rect=(0,.09,1,1));self.save(\"ram_framework_overview\",fig)\n",
    "\n",
    "        by_task=tables[\"ram_by_framework_task\"]\n",
    "        by_task=by_task[by_task.framework.isin(ORDER)&(by_task.threads==threads)&(by_task.measured_jobs>0)]\n",
    "        if by_task.empty: return\n",
    "        maximum=max(float(by_task.worker_peak_median_mib.max()),1.)\n",
    "        cmap=plt.get_cmap(\"Blues\").copy();cmap.set_bad(\"#eef1f3\")\n",
    "        for track in [\"statevector\",\"native_readout\"]:\n",
    "            part=by_task[by_task.track==track]\n",
    "            if part.empty: continue\n",
    "            tasks=[task for task in RAM_TASKS if task in set(part.task)]\n",
    "            matrix=part.pivot(index=\"framework\",columns=\"task\",values=\"worker_peak_median_mib\")\n",
    "            matrix=matrix.reindex(index=order,columns=tasks)\n",
    "            values=matrix.to_numpy(dtype=float)\n",
    "            fig,ax=plt.subplots(figsize=(max(8.5,len(tasks)*1.05+3),6))\n",
    "            image=ax.imshow(np.ma.masked_invalid(values),cmap=cmap,vmin=0,vmax=maximum,aspect=\"auto\")\n",
    "            for i in range(len(order)):\n",
    "                for j in range(len(tasks)):\n",
    "                    value=values[i,j]\n",
    "                    ax.text(j,i,f\"{value:.0f}\" if np.isfinite(value) else \"—\",ha=\"center\",va=\"center\",\n",
    "                        fontsize=10,color=\"white\" if np.isfinite(value) and value>maximum*.65 else \"#23272b\")\n",
    "            ax.set(xticks=range(len(tasks)),xticklabels=[RAM_TASK_LABELS[t] for t in tasks],\n",
    "                   yticks=range(len(order)),yticklabels=[LABELS[f] for f in order],\n",
    "                   title=f\"RAM per framework and task · {track} · {threads} thread budget\")\n",
    "            plt.setp(ax.get_xticklabels(),rotation=35,ha=\"right\")\n",
    "            fig.colorbar(image,ax=ax,pad=.025,label=\"Median worker peak RAM (MiB)\")\n",
    "            fig.text(.5,.015,\"Cells pool dataset/qubit/depth/seed settings within each task and track; job counts and IQR are in CSVs.\\nGrey / — means not run; both tracks use the same colour scale. Includes setup and job diagnostics.\",\n",
    "                     ha=\"center\",fontsize=10)\n",
    "            fig.tight_layout(rect=(0,.1,1,1));self.save(\"ram_task_\"+track,fig)\n",
    "\n",
    "    def all_task_costs(self,summary,config):\n",
    "        \"\"\"Three panels per exact experiment condition; qubit grids never pooled.\"\"\"\n",
    "        cases=[c for c in CONDITION if c!=\"n_qubits\"]\n",
    "        index=[]\n",
    "        for k,part in summary.groupby(cases,dropna=False,sort=True):\n",
    "            case={field:(value.item() if isinstance(value,np.generic) else value) for field,value in zip(cases,k)};task=case[\"task\"]\n",
    "            profile=config[\"profile\"]\n",
    "            if task in [\"vqc\",\"vqr\"]:requested=profile.get(\"variational_qubits\",profile[\"qml_qubits\"])\n",
    "            elif task==\"vqe\":requested=profile[\"vqe_qubits\"]\n",
    "            elif task==\"gradient\":requested=profile[\"gradient_qubits\"]\n",
    "            elif task==\"circuit\":\n",
    "                if case[\"dataset\"] in [\"batch_sweep\",\"depth_sweep\"]:requested=profile.get(\"sweep_qubits\",[profile[\"batch_qubits\"]])\n",
    "                elif case[\"family\"] in [\"ghz\",\"qft\",\"random\"]:requested=profile[\"state_qubits\"]\n",
    "                else:requested=profile[\"map_qubits\"]\n",
    "            else:requested=profile[\"qml_qubits\"]\n",
    "            framework_order=[f for f in ORDER+[\"analytical_angle\",\"classical\"] if f in set(part.framework)]\n",
    "            fig,axes=plt.subplots(1,3,figsize=(16,4.8))\n",
    "            panels=[(\"primary_runtime\",\"s\",\"Primary computation time (s)\",True),\n",
    "                    (\"worker_wall_time\",\"s\",\"Full worker elapsed time (s)\",True),\n",
    "                    (\"worker_peak\",\"mib\",\"Worker peak resident RAM (MiB)\",False)]\n",
    "            for ax,(prefix,units,label,logarithmic) in zip(axes,panels):\n",
    "                measured=False\n",
    "                for framework in framework_order:\n",
    "                    values=part[part.framework==framework].set_index(\"n_qubits\").reindex(requested)\n",
    "                    y=values[f\"{prefix}_median_{units}\"].to_numpy(dtype=float)\n",
    "                    lo=values[f\"{prefix}_q25_{units}\"].to_numpy(dtype=float)\n",
    "                    hi=values[f\"{prefix}_q75_{units}\"].to_numpy(dtype=float)\n",
    "                    measured |= bool(np.isfinite(y).any())\n",
    "                    ax.plot(requested,y,color=COLORS.get(framework,\"#23272b\"),marker=MARKERS.get(framework,\"o\"),\n",
    "                        label=LABELS.get(framework,framework),linestyle=\"--\" if framework in [\"cirq_f64\",\"superfermion_source_baseline\"] else \"-\")\n",
    "                    ax.fill_between(requested,lo,hi,color=COLORS.get(framework,\"#23272b\"),alpha=.10)\n",
    "                ax.set(xlabel=\"Qubits / projected input dimensions\",ylabel=label,xticks=requested)\n",
    "                ax.set_xlim(min(requested)-.5,max(requested)+.5)\n",
    "                ax.grid(axis=\"y\")\n",
    "                if measured:\n",
    "                    if logarithmic:ax.set_yscale(\"log\")\n",
    "                    else:ax.set_ylim(bottom=0)\n",
    "                else:\n",
    "                    ax.set_yticks([]);ax.text(.5,.5,\"No successful measurements\",transform=ax.transAxes,ha=\"center\",va=\"center\")\n",
    "            title=f'{task.upper()} · {case[\"dataset\"]} · {case[\"track\"]}'\n",
    "            subtitle=f'seed {case[\"seed\"]}; threads {case[\"threads\"]}'\n",
    "            if task in [\"qsvm\",\"qkrr\",\"qkpca\"]:\n",
    "                title+=' · '+str(case[\"feature_map\"])+\" map\"\n",
    "                kernel_cap=(config.get(\"kernel_row_caps\") or {}).get(case[\"n_qubits\"])\n",
    "                subtitle+=('; kernel rows capped to %d train / %d test (exact same jobs in every lane); matched kernel strategy by qubit count'%(kernel_cap,kernel_cap)\n",
    "                    if kernel_cap else '; full 80/20 dataset; matched kernel strategy by qubit count')\n",
    "            elif task==\"circuit\":\n",
    "                title+=' · '+str(case[\"family\"])\n",
    "                subtitle+=f'; depth {case[\"depth\"]}; logical output batch {case[\"batch_size\"]}; warmups {profile[\"warmups\"]} + measured passes {profile[\"inner_repetitions\"]}'\n",
    "            elif task==\"gradient\":\n",
    "                subtitle+=f'; depth {case[\"depth\"]}; 2P shifts per gradient; warmups {profile[\"warmups\"]} + measured passes {profile[\"inner_repetitions\"]}'\n",
    "            elif task in [\"vqc\",\"vqr\"]:\n",
    "                batch_label=\"full training batch\" if profile.get(\"variational_full_batch\",False) else \"minibatch\"\n",
    "                subtitle+=f'; depth {case[\"depth\"]}; {batch_label} {case[\"batch_size\"]}; SPSA updates {case[\"iterations\"]}; full training-loss trace'\n",
    "            elif task==\"classical\":subtitle+='; model '+str(case[\"model\"])+\"; full 80/20 dataset\"\n",
    "            else:\n",
    "                subtitle+=f'; depth {case[\"depth\"]}; SPSA updates {case[\"iterations\"]}'\n",
    "                if task==\"qaoa_fs\":subtitle+='; real-feature/ancilla counts in dataset audit'\n",
    "            success=int(part.successful_jobs.sum());expected=int(part.expected_jobs.sum())\n",
    "            failures=int(part.failed_jobs.sum());pending=int(part.pending_jobs.sum())\n",
    "            fig.suptitle(title+\"\\n\"+subtitle,fontsize=12)\n",
    "            handles,labels=axes[0].get_legend_handles_labels()\n",
    "            fig.legend(handles,labels,loc=\"lower center\",bbox_to_anchor=(.5,.115),ncol=5,frameon=False,fontsize=9)\n",
    "            footer=f'{success}/{expected} planned jobs successful; {failures} failed; {pending} pending. Lines/bands show median/process IQR, not confidence intervals.\\n'\n",
    "            footer+='Gaps are missing measurements, never zero. RAM includes setup and audits. Full worker time includes imports/warmup/reference checks.\\n'\n",
    "            footer+='Kernel/state exports use the documented bounded strategy; backend workspaces need extra RAM. Feature-selection ancillas never create dataset features.'\n",
    "            fig.text(.5,.005,footer,ha=\"center\",fontsize=8.5)\n",
    "            fig.tight_layout(rect=(0,.28,1,.89))\n",
    "            token=hashlib.sha256(json.dumps(case,sort_keys=True,default=str).encode()).hexdigest()[:16]\n",
    "            key=\"time_ram_\"+task+\"_\"+token;self.save(key,fig)\n",
    "            index.append(dict(case,key=key,figure_title=title,successful_jobs=success,expected_jobs=expected,\n",
    "                              failed_jobs=failures,pending_jobs=pending,\n",
    "                              png=self.paths[key],svg=str(self.root/\"figures\"/(key+\".svg\"))))\n",
    "        html_table(self.root,\"all_experiment_figures\",pd.DataFrame(index),100)\n",
    "        (self.root/\"all_experiment_figures.json\").write_text(json.dumps(index,indent=2))\n",
    "\n",
    "    def latency(self,key,summary,task,facet=\"dataset\",track=\"native_readout\",feature_map=None):\n",
    "        subset=summary[(summary.task==task)&(summary.track==track)&summary.framework.isin(ORDER)]\n",
    "        if feature_map is not None: subset=subset[subset.feature_map==feature_map]\n",
    "        if subset.empty: return\n",
    "        # A figure shows one explicit n/depth/seed/thread configuration. The\n",
    "        # complete tables retain every other configuration; no max-speedup\n",
    "        # selection is used to choose the displayed slice.\n",
    "        for field in [\"n_qubits\",\"depth\",\"seed\",\"threads\"]: subset=subset[subset[field]==subset[field].min()]\n",
    "        facets=list(dict.fromkeys(subset[facet])); cols=min(2,len(facets)); r=(len(facets)+cols-1)//cols\n",
    "        fig,axes=plt.subplots(r,cols,figsize=(6.4*cols,4.7*r),squeeze=False,sharex=True,sharey=True)\n",
    "        order=[f for f in ORDER if f in set(subset.framework)]\n",
    "        low=max(float(subset.q25_ms.min())*.65,1e-4); high=float(subset.q75_ms.max())*1.6\n",
    "        for ax,label in zip(axes.flat,facets):\n",
    "            part=subset[subset[facet]==label]\n",
    "            for index,f in enumerate(order):\n",
    "                available=part[part.framework==f]\n",
    "                if available.empty:continue\n",
    "                row=available.iloc[0]\n",
    "                ax.errorbar(row.median_ms,index,xerr=[[row.median_ms-row.q25_ms],[row.q75_ms-row.median_ms]],\n",
    "                    color=COLORS[f],fmt=MARKERS[f],capsize=3,markersize=6)\n",
    "            ax.set(yticks=range(len(order)),yticklabels=[LABELS[f] for f in order],xscale=\"log\",\n",
    "                   xlim=(low,high),title=str(label),xlabel=\"Runtime (ms, log scale)\")\n",
    "            ax.grid(axis=\"x\"); ax.set_ylim(len(order)-.5,-.5)\n",
    "        for ax in list(axes.flat)[len(facets):]: ax.set_visible(False)\n",
    "        row=subset.iloc[0]\n",
    "        fig.suptitle(f'{task.upper()} · {track} · {int(row.n_qubits)} qubits · depth {int(row.depth)} · {int(row.threads)} thread(s)',y=1.01,fontsize=14)\n",
    "        fig.text(.5,-.01,\"Dots: median of fresh processes. Whiskers: process IQR, not a confidence interval. Fixed seed shown.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout(); self.save(key,fig)\n",
    "\n",
    "    def circuit_scaling(self,summary):\n",
    "        subset=summary[(summary.task==\"circuit\")&(summary.dataset==\"synthetic\")&summary.family.isin([\"ghz\",\"qft\",\"random\"])]\n",
    "        if subset.empty: return\n",
    "        subset=subset[(subset.seed==subset.seed.min())&(subset.threads==subset.threads.min())]\n",
    "        fig,axes=plt.subplots(1,3,figsize=(16,5),sharey=True)\n",
    "        for ax,family in zip(axes,[\"ghz\",\"qft\",\"random\"]):\n",
    "            for f in ORDER:\n",
    "                part=subset[(subset.framework==f)&(subset.family==family)].sort_values(\"n_qubits\")\n",
    "                if part.empty: continue\n",
    "                ax.plot(part.n_qubits,part.median_ms,marker=MARKERS[f],color=COLORS[f],label=LABELS[f],\n",
    "                        linestyle=\"--\" if f in [\"superfermion_source_baseline\",\"cirq_f64\"] else \"-\")\n",
    "                ax.fill_between(part.n_qubits,part.q25_ms,part.q75_ms,color=COLORS[f],alpha=.12)\n",
    "            ax.set(title=family.upper(),xlabel=\"Qubits\",yscale=\"log\",xticks=sorted(subset.n_qubits.unique()));ax.grid(axis=\"y\")\n",
    "        axes[0].set_ylabel(\"Statevector API runtime (ms, log scale)\")\n",
    "        handles,labels=axes[0].get_legend_handles_labels();fig.legend(handles,labels,loc=\"lower center\",bbox_to_anchor=(.5,-.15),ncol=4,frameon=False)\n",
    "        fig.suptitle(\"CPU statevector scaling · batch 1 · one fixed seed and thread budget; shaded process IQR\",fontsize=14)\n",
    "        fig.tight_layout();self.save(\"circuit_scaling\",fig)\n",
    "\n",
    "    def sweep(self,key,summary,dataset,xfield,title,per_circuit=False):\n",
    "        subset=summary[(summary.task==\"circuit\")&(summary.dataset==dataset)]\n",
    "        if subset.empty: return\n",
    "        for field in [\"n_qubits\",\"seed\",\"threads\"]: subset=subset[subset[field]==subset[field].min()]\n",
    "        fig,ax=plt.subplots(figsize=(9,5))\n",
    "        for f in ORDER:\n",
    "            part=subset[subset.framework==f].sort_values(xfield)\n",
    "            divisor=part.batch_size if per_circuit else 1\n",
    "            ax.plot(part[xfield],part.median_ms/divisor,color=COLORS[f],marker=MARKERS[f],label=LABELS[f])\n",
    "            ax.fill_between(part[xfield],part.q25_ms/divisor,part.q75_ms/divisor,color=COLORS[f],alpha=.10)\n",
    "        row=subset.iloc[0]\n",
    "        ax.set(title=f'{title} · {int(row.n_qubits)} qubits · {int(row.threads)} thread(s)',xlabel=\"Batch size\" if xfield==\"batch_size\" else \"Circuit layers\",\n",
    "               ylabel=\"ms per circuit\" if per_circuit else \"Batch runtime (ms)\",yscale=\"log\",xticks=sorted(subset[xfield].unique()))\n",
    "        ax.grid(axis=\"y\");ax.legend(ncol=2,loc=\"upper left\",bbox_to_anchor=(1,1),frameon=False)\n",
    "        fig.text(.5,-.02,\"Same complex128 output contract; qsim computes internally in complex64. Bands show process IQR.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout();self.save(key,fig)\n",
    "\n",
    "    def speedup_distribution(self,pairs):\n",
    "        if pairs.empty:return\n",
    "        order=[f for f in ORDER if f!=\"superfermion_optimized\" and f in set(pairs.competitor)]\n",
    "        arrays=[pairs[pairs.competitor==f].competitor_over_modified.to_numpy() for f in order]\n",
    "        fig,ax=plt.subplots(figsize=(10,6));box=ax.boxplot(arrays,vert=False,tick_labels=[LABELS[f] for f in order],patch_artist=True,showfliers=False)\n",
    "        for patch,f in zip(box[\"boxes\"],order):patch.set_facecolor(COLORS[f]);patch.set_alpha(.55)\n",
    "        ax.axvline(1,color=\"#272c31\",linestyle=\"--\",linewidth=1)\n",
    "        ax.set(xscale=\"log\",xlabel=\"Competitor runtime / modified SF runtime (log scale)\",title=\"Paired runtime ratios across the measured configurations\")\n",
    "        ax.invert_yaxis();ax.grid(axis=\"x\")\n",
    "        fig.text(.5,-.01,\"Below 1: competitor faster. Boxes show workload/repetition heterogeneity, not statistical confidence.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout();self.save(\"paired_speedup_distribution\",fig)\n",
    "\n",
    "    def readout(self,frame):\n",
    "        tasks=[\"vqc\",\"vqr\",\"qaoa_fs\",\"maxcut\",\"vqe\",\"gradient\"]\n",
    "        part=frame[frame.task.isin(tasks)&frame.framework.isin(ORDER)]\n",
    "        key=[k for k in CONDITION if k!=\"track\"]+[\"repetition\",\"framework\"]\n",
    "        wide=part.pivot_table(index=key,columns=\"track\",values=\"primary_runtime_s\",aggfunc=\"first\").reset_index()\n",
    "        if not {\"statevector\",\"native_readout\"}<=set(wide):return\n",
    "        wide=wide.dropna(subset=[\"statevector\",\"native_readout\"])\n",
    "        wide[\"statevector_over_native\"]=wide.statevector/wide.native_readout\n",
    "        wide.to_csv(self.root/\"native_readout_ratios.csv\",index=False)\n",
    "        fig,axes=plt.subplots(2,3,figsize=(15,10),sharex=True,sharey=True)\n",
    "        for ax,task in zip(axes.flat,tasks):\n",
    "            for index,f in enumerate(ORDER):\n",
    "                values=wide[(wide.task==task)&(wide.framework==f)].statevector_over_native\n",
    "                if values.empty:continue\n",
    "                mid,q25,q75=float(values.median()),float(values.quantile(.25)),float(values.quantile(.75))\n",
    "                ax.errorbar(mid,index,xerr=[[mid-q25],[q75-mid]],fmt=MARKERS[f],color=COLORS[f],capsize=3)\n",
    "            ax.axvline(1,color=\"#333\",linestyle=\"--\");ax.set(title=task.upper(),xscale=\"log\",yticks=range(len(ORDER)),yticklabels=[LABELS[f] for f in ORDER],xlabel=\"State export / native readout runtime\")\n",
    "            ax.grid(axis=\"x\");ax.set_ylim(len(ORDER)-.5,-.5)\n",
    "        fig.suptitle(\"Output-contract sensitivity · above 1 means native readout is faster\",fontsize=14)\n",
    "        fig.text(.5,-.01,\"Dots: median paired ratio. Whiskers: IQR across recorded cases/repeats; equivalent observables, different APIs.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout();self.save(\"readout_sensitivity\",fig)\n",
    "\n",
    "    def quality(self,frame):\n",
    "        ref=frame[(frame.framework.isin([\"superfermion_optimized\",\"classical\"]))&(frame.repetition==0)]\n",
    "        ref=ref[(ref.seed==ref.seed.min())&(ref.n_qubits==ref.n_qubits.min())&(ref.threads==ref.threads.min())]\n",
    "        series={\"RBF SVC\":ref[(ref.task==\"classical\")&(ref.model==\"rbf_svc\")],\n",
    "                \"Logistic\":ref[(ref.task==\"classical\")&(ref.model==\"logistic\")],\n",
    "                \"Random forest\":ref[(ref.task==\"classical\")&(ref.model==\"rf_classifier\")],\n",
    "                \"QSVM (ZZ)\":ref[(ref.task==\"qsvm\")&(ref.feature_map==\"zz\")],\n",
    "                \"QKPCA + logistic\":ref[ref.task==\"qkpca\"],\n",
    "                \"VQC\":ref[(ref.task==\"vqc\")&(ref.track==\"native_readout\")]}\n",
    "        datasets=list(dict.fromkeys(ref[ref.task==\"qsvm\"].dataset));fig,ax=plt.subplots(figsize=(10,6))\n",
    "        colors=[\"#656b71\",\"#92999f\",\"#ac8a29\",\"#174c78\",\"#668aa8\",\"#984d72\"]\n",
    "        for j,((label,part),color) in enumerate(zip(series.items(),colors)):\n",
    "            values=[float(part[part.dataset==d].balanced_accuracy.iloc[0]) if len(part[part.dataset==d]) else np.nan for d in datasets]\n",
    "            ax.plot(values,np.arange(len(datasets))+(j-2.5)*.09,linestyle=\"none\",marker=[\"o\",\"s\",\"^\",\"D\",\"v\",\"P\"][j],color=color,label=label)\n",
    "        ax.set(yticks=range(len(datasets)),yticklabels=datasets,xlim=(0,1.03),xlabel=\"Held-out balanced accuracy\",title=\"QML and classical model quality · same projected input and split\")\n",
    "        ax.invert_yaxis();ax.grid(axis=\"x\");ax.legend(loc=\"upper left\",bbox_to_anchor=(1,1),frameon=False)\n",
    "        fig.text(.5,-.02,\"One small validation split shown; missing models are omitted. No confidence interval or quantum-advantage claim.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout();self.save(\"classification_quality\",fig)\n",
    "        regression=ref[ref.task.isin([\"qkrr\",\"vqr\",\"classical\"])&ref.rmse.notna()]\n",
    "        if regression.empty:return\n",
    "        names=list(dict.fromkeys(regression.dataset));fig,axes=plt.subplots(1,len(names),figsize=(6*len(names),4),squeeze=False)\n",
    "        for ax,d in zip(axes.flat,names):\n",
    "            part=regression[regression.dataset==d]\n",
    "            records=[]\n",
    "            for _,row in part.iterrows():\n",
    "                if row.task==\"classical\":label=row.model\n",
    "                elif row.task==\"vqr\":\n",
    "                    if row.track!=\"native_readout\":continue\n",
    "                    label=\"VQR\"\n",
    "                else:label=\"QKRR \"+row.feature_map\n",
    "                records.append((label,row.rmse))\n",
    "            ax.barh([r[0] for r in records],[r[1] for r in records],color=\"#668aa8\")\n",
    "            ax.set(title=d,xlabel=\"Held-out RMSE (original target units)\");ax.invert_yaxis();ax.grid(axis=\"x\")\n",
    "        fig.tight_layout();self.save(\"regression_quality\",fig)\n",
    "\n",
    "    def traces(self,rows):\n",
    "        selected=[r for r in rows if r.get(\"status\")==\"ok\" and r[\"framework\"] in [\"superfermion_optimized\",\"qulacs\",\"cirq\"]\n",
    "                  and r[\"track\"]==\"native_readout\" and r[\"repetition\"]==0 and \"optimization_trace\" in r]\n",
    "        if not selected:return\n",
    "        first_seed=min(r[\"seed\"] for r in selected);selected=[r for r in selected if r[\"seed\"]==first_seed]\n",
    "        cases=list(dict.fromkeys((r[\"task\"],r[\"dataset\"],r[\"n_qubits\"],r[\"depth\"]) for r in selected))[:8]\n",
    "        fig,axes=plt.subplots((len(cases)+1)//2,2,figsize=(12,4*((len(cases)+1)//2)),squeeze=False)\n",
    "        for ax,case in zip(axes.flat,cases):\n",
    "            part=[r for r in selected if (r[\"task\"],r[\"dataset\"],r[\"n_qubits\"],r[\"depth\"])==case]\n",
    "            for row in part:\n",
    "                f=row[\"framework\"];values=row[\"optimization_trace\"]\n",
    "                ax.plot(range(len(values)),values,color=COLORS[f],marker=MARKERS[f],label=LABELS[f],linestyle=\"--\" if f==\"qulacs\" else \"-\")\n",
    "            ax.set(title=f'{case[0].upper()} · {case[1]} · {case[2]}q',xlabel=\"SPSA update\",ylabel=\"Full training loss\" if case[0] in [\"vqc\",\"vqr\"] else \"Energy\")\n",
    "            ax.grid(axis=\"y\");ax.legend(frameon=False)\n",
    "        for ax in list(axes.flat)[len(cases):]:ax.set_visible(False)\n",
    "        fig.suptitle(\"Matched optimizer traces · overlap indicates numerical agreement, not better learning\",fontsize=14,y=1.01)\n",
    "        fig.tight_layout();self.save(\"optimization_traces\",fig)\n",
    "\n",
    "    def memory(self,summary):\n",
    "        part=summary[(summary.task==\"circuit\")&(summary.family==\"random\")&(summary.dataset==\"synthetic\")]\n",
    "        if part.empty:return\n",
    "        part=part[(part.n_qubits==part.n_qubits.max())&(part.seed==part.seed.min())&(part.threads==part.threads.min())]\n",
    "        fig,ax=plt.subplots(figsize=(9,5))\n",
    "        for i,f in enumerate(ORDER):\n",
    "            row=part[part.framework==f]\n",
    "            if row.empty:continue\n",
    "            ax.plot(float(row.peak_process_hwm_mib.iloc[0]),i,marker=MARKERS[f],color=COLORS[f],linestyle=\"none\")\n",
    "        ax.set(yticks=range(len(ORDER)),yticklabels=[LABELS[f] for f in ORDER],xlabel=\"Process high-water RSS (MiB)\",title=f'Process memory footprint · random circuit · {int(part.n_qubits.max())} qubits')\n",
    "        ax.set_xlim(left=0);ax.invert_yaxis();ax.grid(axis=\"x\")\n",
    "        fig.text(.5,-.01,\"Includes imports, preparation and warmup; captured before numerical audit. This is not statevector-only memory.\",ha=\"center\",fontsize=10)\n",
    "        fig.tight_layout();self.save(\"process_memory\",fig)\n",
    "\n",
    "\n",
    "def analyze(config):\n",
    "    style();root=Path(config[\"root\"]);inputs=verify_manifest(config)\n",
    "    rows=load_results(root,config[\"manifest_sha256\"])\n",
    "    frame=pd.DataFrame([{k:v for k,v in row.items() if not isinstance(v,(list,dict))} for row in rows])\n",
    "    for column in CONDITION:\n",
    "        if column not in frame:frame[column]=\"none\"\n",
    "    frame[\"model\"]=frame.model.fillna(\"none\")\n",
    "    for column in [\"status\",\"framework\",\"repetition\",\"primary_runtime_s\",\"peak_measured_stage_mb\"]+METRICS:\n",
    "        if column not in frame:frame[column]=np.nan\n",
    "    frame.to_csv(root/\"all_results.csv\",index=False);(root/\"all_results.json\").write_text(json.dumps(rows,indent=2))\n",
    "    successful=frame[frame.status==\"ok\"].copy();summary=aggregate(successful)\n",
    "    html_table(root,\"timing_summary\",summary,80)\n",
    "    ram_tables=ram_reports(root,rows,config)\n",
    "    pairs,coverage=summarize_pairs(successful,config[\"frameworks\"])\n",
    "    html_table(root,\"paired_speedups\",pairs,80);html_table(root,\"group_coverage\",coverage,60)\n",
    "    agreement=audit_outcomes(rows,config[\"frameworks\"]);html_table(root,\"outcome_agreement\",agreement,60)\n",
    "    simulator_summary=summary[summary.framework.isin(config[\"frameworks\"])]\n",
    "    leaders=[]\n",
    "    for key,part in simulator_summary.groupby(CONDITION,dropna=False,sort=False):\n",
    "        if set(part.framework)!=set(config[\"frameworks\"]):continue\n",
    "        best=part.loc[part.median_ms.idxmin()];f64=part[part.framework!=\"cirq\"];best64=f64.loc[f64.median_ms.idxmin()]\n",
    "        modified=part[part.framework==\"superfermion_optimized\"].iloc[0]\n",
    "        source=part[part.framework==\"superfermion_source_baseline\"].iloc[0]\n",
    "        ql=part[part.framework==\"qulacs\"].iloc[0]\n",
    "        leaders.append(dict(zip(CONDITION,key),fastest_all=best.framework,fastest_f64=best64.framework,\n",
    "            modified_ms=modified.median_ms,source_over_modified=source.median_ms/modified.median_ms,\n",
    "            qulacs_over_modified=ql.median_ms/modified.median_ms))\n",
    "    leaders=pd.DataFrame(leaders,columns=CONDITION+[\"fastest_all\",\"fastest_f64\",\"modified_ms\",\n",
    "        \"source_over_modified\",\"qulacs_over_modified\"]);html_table(root,\"condition_leaders\",leaders,100)\n",
    "    quality_columns=[c for c in CONDITION+[\"framework\",\"repetitions\"]+METRICS if c in summary]\n",
    "    quality=summary[quality_columns].copy()\n",
    "    quality=quality[quality[[c for c in METRICS if c in quality]].notna().any(axis=1)]\n",
    "    html_table(root,\"model_and_solver_quality\",quality,100)\n",
    "    expected=sum(len(g) for g in groups(config,inputs))\n",
    "    overview=dict(profile=config[\"profile_name\"],expected_jobs=expected,completed_jobs=len(rows),\n",
    "        successful_jobs=int((frame.status==\"ok\").sum()),failed_jobs=int((frame.status!=\"ok\").sum()),\n",
    "        dataset_names=[r[\"dataset\"] for r in inputs[\"datasets\"]],\n",
    "        simulator_lanes=config[\"frameworks\"],complete_process_groups=int(coverage.complete.sum()),\n",
    "        measured_conditions=len(leaders),modified_fastest_all=int((leaders.fastest_all==\"superfermion_optimized\").sum()),\n",
    "        modified_fastest_f64=int((leaders.fastest_f64==\"superfermion_optimized\").sum()),\n",
    "        source_over_modified_median=float(leaders.source_over_modified.median()) if len(leaders) else None,\n",
    "        source_over_modified_min=float(leaders.source_over_modified.min()) if len(leaders) else None,\n",
    "        source_over_modified_max=float(leaders.source_over_modified.max()) if len(leaders) else None,\n",
    "        qulacs_over_modified_median=float(leaders.qulacs_over_modified.median()) if len(leaders) else None,\n",
    "        fresh_process_repetitions=config[\"profile\"][\"repetitions\"],split_seeds=config[\"profile\"][\"seeds\"],\n",
    "        limitations=[\"CPU ideal statevector experiments only; no GPU, noise or hardware results\",\n",
    "            \"Runtime IQR is descriptive; validation profile is not a publication-quality statistical study\",\n",
    "            \"Small held-out splits and short optimizer budgets do not establish quantum ML advantage\",\n",
    "            \"Process memory includes imports/preparation/warmup, not statevector-only memory\"],\n",
    "        attempted_complete=bool(len(rows)==expected),pending_jobs=max(0,expected-len(rows)),\n",
    "        complete=bool(len(rows)==expected and (frame.status==\"ok\").all() and coverage.complete.all()))\n",
    "    overview[\"dataset_names\"]=list(dict.fromkeys(overview[\"dataset_names\"]))\n",
    "    (root/\"overview.json\").write_text(json.dumps(overview,indent=2))\n",
    "    figures=Figures(root)\n",
    "    cost_summary,cost_jobs=task_cost_reports(root,rows,config,inputs)\n",
    "    figures.all_task_costs(cost_summary,config)\n",
    "    for key,task,track,feature in [(\"qsvm_latency\",\"qsvm\",\"statevector\",\"zz\"),(\"qkrr_latency\",\"qkrr\",\"statevector\",\"zz\"),\n",
    "        (\"qkpca_latency\",\"qkpca\",\"statevector\",\"zz\"),(\"vqc_latency\",\"vqc\",\"native_readout\",None),\n",
    "        (\"vqr_latency\",\"vqr\",\"native_readout\",None),(\"qaoa_fs_latency\",\"qaoa_fs\",\"native_readout\",None),\n",
    "        (\"maxcut_latency\",\"maxcut\",\"native_readout\",None),(\"vqe_latency\",\"vqe\",\"native_readout\",None),\n",
    "        (\"gradient_latency\",\"gradient\",\"native_readout\",None)]:\n",
    "        figures.latency(key,summary,task,track=track,feature_map=feature)\n",
    "    figures.latency(\"feature_maps_latency\",summary[summary.family.isin([\"angle\",\"phase\",\"pauli\",\"zz\"])&(summary.dataset==\"synthetic\")],\"circuit\",facet=\"family\",track=\"statevector\")\n",
    "    figures.circuit_scaling(summary)\n",
    "    figures.sweep(\"batch_runtime\",summary,\"batch_sweep\",\"batch_size\",\"Native batch scaling\")\n",
    "    figures.sweep(\"batch_per_circuit\",summary,\"batch_sweep\",\"batch_size\",\"Native batch amortization\",per_circuit=True)\n",
    "    figures.sweep(\"depth_scaling\",summary,\"depth_sweep\",\"depth\",\"Random entangling circuit depth scaling\")\n",
    "    figures.speedup_distribution(pairs);figures.readout(successful);figures.quality(successful)\n",
    "    figures.traces(rows);figures.memory(summary)\n",
    "    figures.ram(ram_tables)\n",
    "    (root/\"figure_index.json\").write_text(json.dumps(figures.paths,indent=2))\n",
    "    print(json.dumps(overview,indent=2));print(f\"Rendered {len(figures.paths)} figure views with PNG and editable SVG exports.\")\n",
    "\n",
    "\n",
    "if __name__==\"__main__\":analyze(json.loads(Path(sys.argv[1]).read_text()))\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'analyze_study.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote analyze_study.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a03babcf",
   "metadata": {
    "id": "a03babcf"
   },
   "source": [
    "#### Independent dense/Fourier/Pauli math checks\n",
    "\n",
    "Open this source cell to inspect or modify `offline_checks.py`. Its SHA256 is recorded before timing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "06a2d1a2",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "id": "06a2d1a2",
    "jupyter": {
     "source_hidden": true
    },
    "outputId": "4d26853d-33b4-46fd-a2fc-04c3ae2aba42"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote offline_checks.py\n"
     ]
    }
   ],
   "source": [
    "MODULE_SOURCE = r'''\n",
    "\"\"\"Independent NumPy checks; these are not compiled-framework benchmarks.\"\"\"\n",
    "\n",
    "import importlib.util\n",
    "import itertools\n",
    "import json\n",
    "from pathlib import Path\n",
    "import sys\n",
    "import tempfile\n",
    "import time\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def load(name, path):\n",
    "    spec = importlib.util.spec_from_file_location(name, path)\n",
    "    module = importlib.util.module_from_spec(spec); spec.loader.exec_module(module)\n",
    "    return module\n",
    "\n",
    "\n",
    "def single(state, matrix, q):\n",
    "    stride = 1 << q; pairs = state.reshape(-1, 2*stride)\n",
    "    left, right = pairs[:, :stride].copy(), pairs[:, stride:].copy()\n",
    "    pairs[:, :stride] = matrix[0, 0]*left+matrix[0, 1]*right\n",
    "    pairs[:, stride:] = matrix[1, 0]*left+matrix[1, 1]*right\n",
    "\n",
    "\n",
    "def simulate(n, operations, values):\n",
    "    state = np.zeros(1 << n, complex); state[0] = 1\n",
    "    for gate, wires, key in operations:\n",
    "        angle = values[key] if key is not None else 0.\n",
    "        c, s = np.cos(angle/2), np.sin(angle/2)\n",
    "        if gate == \"CX\":\n",
    "            indices = np.arange(len(state)); mask = ((indices >> wires[0]) & 1)*(1 << wires[1])\n",
    "            state = state[indices ^ mask]\n",
    "            continue\n",
    "        matrices = {\"H\": np.array([[1, 1], [1, -1]])/np.sqrt(2), \"X\": np.array([[0, 1], [1, 0]]),\n",
    "                    \"RX\": np.array([[c, -1j*s], [-1j*s, c]]), \"RY\": np.array([[c, -s], [s, c]]),\n",
    "                    \"RZ\": np.diag([np.exp(-1j*angle/2), np.exp(1j*angle/2)]), \"P\": np.diag([1., np.exp(1j*angle)])}\n",
    "        single(state, matrices[gate], wires[0])\n",
    "    return state\n",
    "\n",
    "\n",
    "PAULIS = [np.eye(2), np.array([[0, 1], [1, 0]]), np.array([[0, -1j], [1j, 0]]), np.diag([1, -1])]\n",
    "\n",
    "\n",
    "def dense_pauli(codes):\n",
    "    result = np.ones((1, 1), complex)\n",
    "    for code in reversed(codes): result = np.kron(result, PAULIS[code])\n",
    "    return result\n",
    "\n",
    "\n",
    "def bitmask_expectation(state, codes):\n",
    "    flip = sum(1 << q for q, p in enumerate(codes) if p in [1, 2])\n",
    "    sign = sum(1 << q for q, p in enumerate(codes) if p in [2, 3])\n",
    "    phase = (-1j)**codes.count(2)\n",
    "    return sum(np.conj(z)*phase*((-1)**((i & sign).bit_count()))*state[i ^ flip] for i, z in enumerate(state))\n",
    "\n",
    "\n",
    "def main(source_dir=None):\n",
    "    here = Path(__file__).resolve().parent\n",
    "    source = Path(source_dir) if source_dir else here.parent/\"superfermion-optimized\"\n",
    "    worker = load(\"benchmark_math\", here/\"legacy_adapter.py\")\n",
    "    kernel = load(\"analytical_kernel\", source/\"superfermion/kernels.py\")\n",
    "    rng = np.random.default_rng(331)\n",
    "    cases = 0; maximum = 0.\n",
    "    for n in range(1, 6):\n",
    "        state = rng.normal(size=1 << n)+1j*rng.normal(size=1 << n); state /= np.linalg.norm(state)\n",
    "        for codes in itertools.product(range(4), repeat=n):\n",
    "            expected = np.vdot(state, dense_pauli(codes) @ state)\n",
    "            actual = bitmask_expectation(state, list(codes))\n",
    "            maximum = max(maximum, abs(expected-actual)); cases += 1\n",
    "            np.testing.assert_allclose(actual, expected, atol=2e-12)\n",
    "        x, y = rng.normal(size=(5, n)), rng.normal(size=(3, n))\n",
    "        encode = lambda rows: np.stack([simulate(n, worker.feature_spec(n, \"angle\"), worker.feature_values(row)) for row in rows])\n",
    "        actual = kernel.angle_fidelity_kernel(x, y, block_rows=2)\n",
    "        np.testing.assert_allclose(actual, np.abs(encode(x).conj() @ encode(y).T)**2, atol=2e-12)\n",
    "        np.testing.assert_allclose(worker.mean_z_weights(n), [(n-2*i.bit_count())/n for i in range(1 << n)])\n",
    "    n = 4; a = rng.normal(size=n); b = rng.normal(size=(n, n)); b = (b+b.T)/2; np.fill_diagonal(b, 0)\n",
    "    constant = .71; h, pairs, offset = worker.qubo_ising(a, b, constant)\n",
    "    indices = np.arange(1 << n); bits = ((indices[:, None] >> np.arange(n)) & 1).astype(float)\n",
    "    costs = constant+bits @ a+.5*np.einsum(\"bi,ij,bj->b\", bits, b, bits)\n",
    "    spins = 1-2*bits\n",
    "    ising_costs = offset+spins @ h+sum(value*spins[:, i]*spins[:, j] for i, j, value in pairs)\n",
    "    np.testing.assert_allclose(costs, ising_costs, atol=1e-12)\n",
    "    for gamma, beta in [(.11, .23), (.4, .3), (-.53, .17)]:\n",
    "        actual = simulate(n, worker.qaoa_spec(n, pairs), worker.qaoa_values(n, h, pairs, gamma, beta))\n",
    "        expected = np.exp(-1j*gamma*costs)/np.sqrt(1 << n)\n",
    "        rx = np.array([[np.cos(beta), -1j*np.sin(beta)], [-1j*np.sin(beta), np.cos(beta)]])\n",
    "        for q in range(n): single(expected, rx, q)\n",
    "        phase = np.vdot(expected, actual); phase /= abs(phase)\n",
    "        np.testing.assert_allclose(actual/phase, expected, atol=1e-12)\n",
    "\n",
    "    class ReferenceAdapter:\n",
    "        def __init__(self, framework, n, operations, output=\"state\", terms=None, weights=None):\n",
    "            self.n, self.operations, self.output = n, operations, output\n",
    "            self.backend = \"NumPy reference, offline harness check only\"; self.precision = \"complex128\"\n",
    "            self.calls = 0; self.execute_s = 0.\n",
    "            self.observable = sum(coefficient*dense_pauli(pauli) for pauli, coefficient in terms) if terms else None\n",
    "        def reset(self): self.calls = 0; self.execute_s = 0.\n",
    "        def state(self, values):\n",
    "            start = time.perf_counter(); result = simulate(self.n, self.operations, values)\n",
    "            self.calls += 1; self.execute_s += time.perf_counter()-start; return result\n",
    "        def states(self, values): return np.stack([self.state(row) for row in values])\n",
    "        def readouts(self, values):\n",
    "            return np.array([np.vdot(vector, self.observable @ vector).real for vector in self.states(values)])\n",
    "    worker.Adapter = ReferenceAdapter\n",
    "    tasks = 0\n",
    "    with tempfile.TemporaryDirectory() as temporary:\n",
    "        directory = Path(temporary)\n",
    "        x = rng.normal(size=(24, n)); y = np.array([0, 1]*12)\n",
    "        main_path = directory/\"main.npz\"; batch_path = directory/\"batch.npz\"; qubo_path = directory/\"qubo.npz\"\n",
    "        np.savez(main_path, X_train=x[:16], y_train=y[:16], X_test=x[16:], y_test=y[16:])\n",
    "        np.savez(batch_path, X_batch=x[:6])\n",
    "        np.savez(qubo_path, a=a, B=b, const=constant, costvec=costs, cards=bits.sum(axis=1).astype(int), select_k=2)\n",
    "        config = dict(framework=\"numpy_reference\", n_qubits=n, seed=42, kernel_block_rows=2, vqc_layers=1,\n",
    "                      vqc_batch=3, vqc_iterations=2, qaoa_iterations=2, data_path=str(main_path), qubo_path=str(qubo_path))\n",
    "        for task in [\"qsvm\", \"qkpca\"]:\n",
    "            job = {**config, \"task\": task}\n",
    "            if task == \"qkpca\": job[\"data_path\"] = str(batch_path)\n",
    "            result = worker.report_kernel(job); json.dumps(result, allow_nan=False); tasks += 1\n",
    "        for name in [\"angle\", \"phase\", \"pauli\", \"zz\"]:\n",
    "            result = worker.report_feature({**config, \"feature_map\": name, \"data_path\": str(batch_path)})\n",
    "            assert result[\"max_norm_error\"] < 1e-12; tasks += 1\n",
    "        for track in [\"common_statevector\", \"native_readout\"]:\n",
    "            for function in [worker.report_vqc, worker.report_qaoa]:\n",
    "                result = function({**config, \"track\": track}); json.dumps(result, allow_nan=False); tasks += 1\n",
    "        common = worker.report_qaoa({**config, \"track\": \"common_statevector\"})\n",
    "        native = worker.report_qaoa({**config, \"track\": \"native_readout\"})\n",
    "        np.testing.assert_allclose(common[\"initial_energy\"], native[\"initial_energy\"], atol=1e-12)\n",
    "        np.testing.assert_allclose(common[\"final_energy\"], native[\"final_energy\"], atol=1e-9)\n",
    "        assert common[\"circuit_evaluations\"] == native[\"circuit_evaluations\"]\n",
    "        result = worker.report_validation(config)\n",
    "        assert all(abs(case[\"norm\"]-1) < 1e-12 for case in result[\"cases\"])\n",
    "    report = {\"status\": \"passed\", \"pauli_strings_checked\": cases, \"max_pauli_error\": maximum,\n",
    "              \"harness_tasks_checked\": tasks, \"analytical_kernel\": \"matches independently simulated states\",\n",
    "              \"qubo_ising\": \"matches all basis-state costs\", \"qaoa\": \"matches direct diagonal phase evolution\",\n",
    "              \"compiled_rust_and_external_frameworks\": \"not tested by this offline checker\"}\n",
    "    import experiment_core as study\n",
    "    qft_errors=[]\n",
    "    for qubits in range(2,7):\n",
    "        op,values=study.circuit_spec(qubits,\"qft\",1,42)\n",
    "        input_state=simulate(qubits,op[:qubits],values)\n",
    "        expected=np.fft.ifft(input_state)*np.sqrt(1 << qubits)\n",
    "        actual=study.reference_state(qubits,op,values)\n",
    "        qft_errors.append(float(np.max(np.abs(actual-expected))))\n",
    "        np.testing.assert_allclose(actual,expected,atol=2e-12)\n",
    "    upper=np.triu(b,1); h,pairs,offset=study.qubo_to_ising(a,upper,constant)\n",
    "    np.testing.assert_allclose(costs,offset+spins@h+sum(c*spins[:,i]*spins[:,j] for i,j,c in pairs),atol=2e-12)\n",
    "    terms=study.tfim_terms(n)+[([2,1,0,3],.17)]\n",
    "    state=rng.normal(size=1 << n)+1j*rng.normal(size=1 << n); state/=np.linalg.norm(state)\n",
    "    expected=np.vdot(state,study.hamiltonian_matrix(n,terms)@state).real\n",
    "    np.testing.assert_allclose(study.pauli_expectations([state],terms,n)[0],expected,atol=2e-12)\n",
    "    report.update(study_qft=\"agrees with dense Fourier transform for 2..6 qubits\",\n",
    "                  study_qft_max_error=max(qft_errors),study_upper_qubo=\"all basis costs agree\",\n",
    "                  study_mixed_pauli_observable=\"agrees with independently formed dense matrix\")\n",
    "    ground_errors=[]\n",
    "    for qubits in [1,2,4,6]:\n",
    "        for coupling,field in [(1.,.7),(.3,1.2),(0.,.7),(1.,0.)]:\n",
    "            dense=study.hamiltonian_matrix(qubits,study.tfim_terms(qubits,coupling,field))\n",
    "            exact=float(np.linalg.eigvalsh(dense)[0])\n",
    "            reduced=study.tfim_ground_energy(qubits,coupling,field)\n",
    "            ground_errors.append(abs(exact-reduced))\n",
    "            np.testing.assert_allclose(reduced,exact,rtol=1e-12,atol=2e-12)\n",
    "    kernel_errors=[]\n",
    "    for family in [\"angle\",\"zz\"]:\n",
    "        operations=study.feature_spec(n,family)\n",
    "        train=[study.feature_values(row,family) for row in rng.uniform(-1,1,(7,n))]\n",
    "        test=[study.feature_values(row,family) for row in rng.uniform(-1,1,(3,n))]\n",
    "        class IndependentStates:\n",
    "            def __init__(self):self.n=n\n",
    "            def states(self,rows):return np.stack([simulate(n,operations,row) for row in rows]) if rows else np.empty((0,1 << n),complex)\n",
    "        adapter=IndependentStates()\n",
    "        dense_train,dense_test=adapter.states(train),adapter.states(test)\n",
    "        expected_train=np.abs(dense_train.conj()@dense_train.T)**2\n",
    "        expected_test=np.abs(dense_test.conj()@dense_train.T)**2\n",
    "        for budget,cap in [(512,1),(1024,2),(10_000,128)]:\n",
    "            actual_train,actual_test,info=study.quantum_kernel_matrices(adapter,train,test,budget,cap)\n",
    "            np.testing.assert_allclose(actual_train,expected_train,rtol=1e-12,atol=2e-12)\n",
    "            np.testing.assert_allclose(actual_test,expected_test,rtol=1e-12,atol=2e-12)\n",
    "            assert info[\"exported_bank_peak_bytes\"]<=budget\n",
    "            kernel_errors.append(max(float(np.max(np.abs(actual_train-expected_train))),float(np.max(np.abs(actual_test-expected_test)))))\n",
    "    assert study.state_chunk_rows(24,512*2**20,2)==1\n",
    "    try:study.state_chunk_rows(24,256*2**20,2)\n",
    "    except MemoryError:pass\n",
    "    else:raise AssertionError(\"An impossible two-bank budget was accepted\")\n",
    "    report.update(open_tfim_reference=\"16 small-chain dense-eigenvalue comparisons passed\",\n",
    "                  open_tfim_max_error=max(ground_errors),\n",
    "                  bounded_kernel=\"Angle/ZZ kernels agree with independently retained states in dense and blocked modes\",\n",
    "                  bounded_kernel_max_error=max(kernel_errors),bounded_state_budget=\"24-qubit two-bank budget boundaries checked\")\n",
    "    from sklearn.datasets import load_iris\n",
    "    from prepare_study_data import qubo_inputs\n",
    "    iris=load_iris()\n",
    "    logical=qubo_inputs(iris.data,iris.target,4,42)\n",
    "    embedded=qubo_inputs(iris.data,iris.target,8,42,allow_ancillas=True)\n",
    "    np.testing.assert_allclose(embedded[\"qubo_cost\"],np.tile(logical[\"qubo_cost\"],16),atol=2e-12)\n",
    "    assert len(embedded[\"selected_original_features\"])==4 and int(embedded[\"feature_selection_ancillas\"])==4\n",
    "    energies=[]\n",
    "    for physical,qubo in [(4,logical),(8,embedded)]:\n",
    "        h,pairs,offset=study.qubo_to_ising(qubo[\"qubo_a\"],qubo[\"qubo_b\"],float(qubo[\"qubo_constant\"]))\n",
    "        op,values=study.qaoa_spec_values(physical,h,pairs,1,[.31,.23])\n",
    "        state=simulate(physical,op,values)\n",
    "        energies.append(float(np.dot(np.abs(state)**2,qubo[\"qubo_cost\"])))\n",
    "    np.testing.assert_allclose(energies[0],energies[1],atol=2e-12)\n",
    "    report[\"feature_selection_ancillas\"]=\"8-qubit physical embedding preserves the 4-real-feature cost and QAOA energy\"\n",
    "    print(json.dumps(report, indent=2))\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\": main(sys.argv[1] if len(sys.argv) > 1 else None)\n",
    "'''\n",
    "(EXPERIMENT_ROOT/'offline_checks.py').write_bytes(MODULE_SOURCE.lstrip(\"\\n\").encode(\"utf-8\"))\n",
    "print(\"Wrote offline_checks.py\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5d51b22",
   "metadata": {
    "id": "d5d51b22"
   },
   "source": [
    "### 7. Verify math independently of all simulator adapters\n",
    "\n",
    "These checks compare bitmask Pauli values with dense matrices, the Angle\n",
    "formula with explicit states, QUBO and Ising costs on every small basis\n",
    "state, and QFT with a dense Fourier transform. They check the reference math;\n",
    "the independent cross-framework gate below checks the compiled simulators.\n",
    "\n",
    "The new scaling helpers also check bounded Angle/ZZ kernels against independently\n",
    "retained states, exported-bank limits at 24 qubits, and the reduced open-TFIM\n",
    "ground reference against 16 small-chain dense eigensolves. These checks do not\n",
    "substitute for compiled-framework validation or constitute performance benchmarks.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4b0fd81d",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 550
    },
    "id": "4b0fd81d",
    "outputId": "7546f0b1-d53f-4660-f3c1-9bc2cf2990ec"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"font-family:system-ui,sans-serif;max-width:1100px;border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\"><div style=\"font-size:18px;font-weight:650\">Independent Math</div><div style=\"color:#475569;margin:5px 0 12px\">Finished · Elapsed 00:00:03</div><div>This preparation/check/report command has no benchmark-job denominator.</div><div style=\"font-size:12px;color:#475569;margin-top:8px\">Detailed log: independent_math.log</div></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished independent_math in 3.1 seconds\n",
      "{\n",
      "  \"status\": \"passed\",\n",
      "  \"pauli_strings_checked\": 1364,\n",
      "  \"max_pauli_error\": 2.220513810852149e-16,\n",
      "  \"harness_tasks_checked\": 10,\n",
      "  \"analytical_kernel\": \"matches independently simulated states\",\n",
      "  \"qubo_ising\": \"matches all basis-state costs\",\n",
      "  \"qaoa\": \"matches direct diagonal phase evolution\",\n",
      "  \"compiled_rust_and_external_frameworks\": \"not tested by this offline checker\",\n",
      "  \"study_qft\": \"agrees with dense Fourier transform for 2..6 qubits\",\n",
      "  \"study_qft_max_error\": 2.8305244335018383e-16,\n",
      "  \"study_upper_qubo\": \"all basis costs agree\",\n",
      "  \"study_mixed_pauli_observable\": \"agrees with independently formed dense matrix\",\n",
      "  \"open_tfim_reference\": \"16 small-chain dense-eigenvalue comparisons passed\",\n",
      "  \"open_tfim_max_error\": 9.769962616701378e-15,\n",
      "  \"bounded_kernel\": \"Angle/ZZ kernels agree with independently retained states in dense and blocked modes\",\n",
      "  \"bounded_kernel_max_error\": 6.661338147750939e-16,\n",
      "  \"bounded_state_budget\": \"24-qubit two-bank budget boundaries checked\",\n",
      "  \"feature_selection_ancillas\": \"8-qubit physical embedding preserves the 4-real-feature cost and QAOA energy\"\n",
      "}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"offline_checks.py\",OPT],\"independent_math\",timeout=600)\n",
    "print((LOGS/\"independent_math.log\").read_text())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0655d4be",
   "metadata": {
    "id": "0655d4be"
   },
   "source": [
    "## Data\n",
    "\n",
    "### 8. Prepare shared training and test inputs\n",
    "\n",
    "| Dataset | Kind | Labels / target | Origin |\n",
    "|---|---|---|---|\n",
    "| Breast Cancer | Binary classification | Original scikit-learn labels | Wisconsin diagnostic data |\n",
    "| Iris | Multiclass classification | All three species | Bundled real dataset |\n",
    "| Wine | Multiclass classification | All three classes | Bundled real dataset |\n",
    "| Digits 0/1 | Binary classification | Only handwritten digits 0 and 1 | Subset of bundled digits |\n",
    "| Moons | Binary classification | Two noisy crescents | Seeded synthetic generator |\n",
    "| Diabetes | Regression | Continuous original response | Bundled real dataset |\n",
    "| Friedman1 | Regression | Nonlinear continuous response | Seeded synthetic generator |\n",
    "\n",
    "Use all available rows in an **80% training / 20% testing** split.\n",
    "Classification splits are stratified and each split uses its configured seed.\n",
    "There are no fixed sample caps; integer rounding is recorded in the audit. Fit `StandardScaler`, full-SVD PCA, and the 95th-percentile\n",
    "angle limit **on training rows only**. Transform held-out rows with those\n",
    "fitted objects, clip angles to \\([-\\pi,\\pi]\\), and save identical inputs for\n",
    "every backend. Regression target mean/std also come from training only.\n",
    "No test label enters feature selection, PCA, angle scaling or model fitting.\n",
    "\n",
    "If qubits exceed available PCA components, extra angles are zero-padded.\n",
    "The audit reports active components and padded qubits; padding adds no new\n",
    "dataset information. Original rows, indices and preprocessing arrays are\n",
    "retained in each NPZ. QAOA feature selection uses original features rather\n",
    "than PCA coordinates, with train-only relevance/correlation coefficients.\n",
    "\n",
    "Feature-selection logical variables represent original features. A physical\n",
    "register may add explicitly audited ancillas. Wine's 16/20/24-qubit registers embed its 13-feature\n",
    "problem with 3/7/11 ancillas. Ancillary coefficients are zero, the cardinality\n",
    "penalty acts only on real feature bits and downstream models ignore ancillary\n",
    "bits. The dataset audit records both counts. No feature values are fabricated.\n",
    "The requested preset supports every feature-selection grid point this way;\n",
    "disabling `feature_selection_ancillas` restores the explicit unsupported-case guard.\n",
    "QUBO diagonal costs are constructed in small bit-index blocks, avoiding a\n",
    "2**24-by-24 temporary bit matrix. The full cost vector is still retained.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "03278288",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "03278288",
    "outputId": "326913d1-50c0-47c3-87de-52e957ad0dc5"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"font-family:system-ui,sans-serif;max-width:1100px;border:1px solid #d0d7de;border-radius:8px;padding:16px;margin:10px 0\"><div style=\"font-size:18px;font-weight:650\">Prepare Data</div><div style=\"color:#475569;margin:5px 0 12px\">Finished · Elapsed 00:00:10</div><div>This preparation/check/report command has no benchmark-job denominator.</div><div style=\"font-size:12px;color:#475569;margin-top:8px\">Detailed log: prepare_data.log</div></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished prepare_data in 10.5 seconds\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<style>th,td{padding:6px 9px;border-bottom:1px solid #ddd;text-align:left}table{border-collapse:collapse}</style><table><thead><tr><th>dataset</th><th>kind</th><th>original_samples</th><th>original_features</th><th>n_qubits</th><th>active_components</th><th>padded_qubits</th><th>train_samples</th><th>test_samples</th><th>actual_train_ratio</th><th>actual_test_ratio</th><th>feature_selection_available</th><th>feature_selection_active_features</th><th>feature_selection_ancilla_qubits</th><th>pca_explained_variance</th></tr></thead><tbody><tr><td>breast_cancer</td><td>classification</td><td>569</td><td>30</td><td>4</td><td>4</td><td>0</td><td>455</td><td>114</td><td>0.79965</td><td>0.20035</td><td>True</td><td>4</td><td>0</td><td>0.79626</td></tr><tr><td>breast_cancer</td><td>classification</td><td>569</td><td>30</td><td>8</td><td>8</td><td>0</td><td>455</td><td>114</td><td>0.79965</td><td>0.20035</td><td>True</td><td>8</td><td>0</td><td>0.92843</td></tr><tr><td>breast_cancer</td><td>classification</td><td>569</td><td>30</td><td>12</td><td>12</td><td>0</td><td>455</td><td>114</td><td>0.79965</td><td>0.20035</td><td>True</td><td>12</td><td>0</td><td>0.97041</td></tr><tr><td>breast_cancer</td><td>classification</td><td>569</td><td>30</td><td>16</td><td>16</td><td>0</td><td>455</td><td>114</td><td>0.79965</td><td>0.20035</td><td>True</td><td>16</td><td>0</td><td>0.98941</td></tr><tr><td>breast_cancer</td><td>classification</td><td>569</td><td>30</td><td>20</td><td>20</td><td>0</td><td>455</td><td>114</td><td>0.79965</td><td>0.20035</td><td>True</td><td>20</td><td>0</td><td>0.99585</td></tr><tr><td>iris</td><td>classification</td><td>150</td><td>4</td><td>4</td><td>4</td><td>0</td><td>120</td><td>30</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>iris</td><td>classification</td><td>150</td><td>4</td><td>8</td><td>4</td><td>4</td><td>120</td><td>30</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>iris</td><td>classification</td><td>150</td><td>4</td><td>12</td><td>4</td><td>8</td><td>120</td><td>30</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>iris</td><td>classification</td><td>150</td><td>4</td><td>16</td><td>4</td><td>12</td><td>120</td><td>30</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>iris</td><td>classification</td><td>150</td><td>4</td><td>20</td><td>4</td><td>16</td><td>120</td><td>30</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>wine</td><td>classification</td><td>178</td><td>13</td><td>4</td><td>4</td><td>0</td><td>142</td><td>36</td><td>0.79775</td><td>0.20225</td><td>True</td><td>4</td><td>0</td><td>0.73355</td></tr><tr><td>wine</td><td>classification</td><td>178</td><td>13</td><td>8</td><td>8</td><td>0</td><td>142</td><td>36</td><td>0.79775</td><td>0.20225</td><td>True</td><td>8</td><td>0</td><td>0.92087</td></tr><tr><td>wine</td><td>classification</td><td>178</td><td>13</td><td>12</td><td>12</td><td>0</td><td>142</td><td>36</td><td>0.79775</td><td>0.20225</td><td>True</td><td>12</td><td>0</td><td>0.99282</td></tr><tr><td>wine</td><td>classification</td><td>178</td><td>13</td><td>16</td><td>13</td><td>3</td><td>142</td><td>36</td><td>0.79775</td><td>0.20225</td><td>True</td><td>13</td><td>3</td><td>1</td></tr><tr><td>wine</td><td>classification</td><td>178</td><td>13</td><td>20</td><td>13</td><td>7</td><td>142</td><td>36</td><td>0.79775</td><td>0.20225</td><td>True</td><td>13</td><td>7</td><td>1</td></tr><tr><td>digits_01</td><td>classification</td><td>360</td><td>64</td><td>4</td><td>4</td><td>0</td><td>288</td><td>72</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>0.617</td></tr><tr><td>digits_01</td><td>classification</td><td>360</td><td>64</td><td>8</td><td>8</td><td>0</td><td>288</td><td>72</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>0.75515</td></tr><tr><td>digits_01</td><td>classification</td><td>360</td><td>64</td><td>12</td><td>12</td><td>0</td><td>288</td><td>72</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>0.84329</td></tr><tr><td>digits_01</td><td>classification</td><td>360</td><td>64</td><td>16</td><td>16</td><td>0</td><td>288</td><td>72</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>0.8941</td></tr><tr><td>digits_01</td><td>classification</td><td>360</td><td>64</td><td>20</td><td>20</td><td>0</td><td>288</td><td>72</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>0.92607</td></tr><tr><td>moons</td><td>classification</td><td>400</td><td>2</td><td>4</td><td>2</td><td>2</td><td>320</td><td>80</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>moons</td><td>classification</td><td>400</td><td>2</td><td>8</td><td>2</td><td>6</td><td>320</td><td>80</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>moons</td><td>classification</td><td>400</td><td>2</td><td>12</td><td>2</td><td>10</td><td>320</td><td>80</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>moons</td><td>classification</td><td>400</td><td>2</td><td>16</td><td>2</td><td>14</td><td>320</td><td>80</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr><tr><td>moons</td><td>classification</td><td>400</td><td>2</td><td>20</td><td>2</td><td>18</td><td>320</td><td>80</td><td>0.8</td><td>0.2</td><td>False</td><td>0</td><td>0</td><td>1</td></tr></tbody></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Showing 25/35 rows; full table: dataset_audit.csv\n"
     ]
    }
   ],
   "source": [
    "CONFIG_PATH = EXPERIMENT_ROOT/\"run_config.json\"\n",
    "CONFIG_PATH.write_text(json.dumps(CONF,indent=2))\n",
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"prepare_study_data.py\",CONFIG_PATH],\"prepare_data\",timeout=600)\n",
    "INPUTS = json.loads((EXPERIMENT_ROOT/\"data_manifest.json\").read_text())\n",
    "from IPython.display import HTML, Image, display\n",
    "\n",
    "def show_table(name,fields=None,filters=None,limit=25):\n",
    "    path=EXPERIMENT_ROOT/(name+\".csv\")\n",
    "    with path.open() as handle: rows=list(csv.DictReader(handle))\n",
    "    if filters: rows=[r for r in rows if all(r.get(k)==str(v) for k,v in filters.items())]\n",
    "    fields=fields or (list(rows[0]) if rows else [])\n",
    "    def fmt(value):\n",
    "        if value in [None,\"\",\"nan\"]:return \"—\"\n",
    "        try:return f\"{float(value):.5g}\"\n",
    "        except (ValueError,TypeError):return str(value)\n",
    "    table='<table><thead><tr>'+''.join('<th>'+html.escape(k)+'</th>' for k in fields)+'</tr></thead><tbody>'\n",
    "    table+=''.join('<tr>'+''.join('<td>'+html.escape(fmt(r.get(k)))+'</td>' for k in fields)+'</tr>' for r in rows[:limit])\n",
    "    table+='</tbody></table>'\n",
    "    display(HTML('<style>th,td{padding:6px 9px;border-bottom:1px solid #ddd;text-align:left}table{border-collapse:collapse}</style>'+table))\n",
    "    print(f\"Showing {min(limit,len(rows))}/{len(rows)} rows; full table: {path.name}\")\n",
    "\n",
    "show_table(\"dataset_audit\",[\"dataset\",\"kind\",\"original_samples\",\"original_features\",\"n_qubits\",\n",
    "    \"active_components\",\"padded_qubits\",\"train_samples\",\"test_samples\",\n",
    "    \"actual_train_ratio\",\"actual_test_ratio\",\"feature_selection_available\",\n",
    "    \"feature_selection_active_features\",\"feature_selection_ancilla_qubits\",\"pca_explained_variance\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6e2dfd1",
   "metadata": {
    "id": "f6e2dfd1"
   },
   "source": [
    "### 9. Record source, wheels, native extensions, packages and data\n",
    "\n",
    "The manifest records actual extension and wheel hashes, compiler version and\n",
    "flags, machine/platform information, script hashes, and input bytes. The\n",
    "published wheel's build choices can differ from the source builds; use\n",
    "**SF source vs SF modified** to attribute changes to this patch."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "4571bc1f",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 211
    },
    "id": "4571bc1f",
    "outputId": "382eb8a7-e3b5-4e49-f3b2-217a7420f510"
   },
   "outputs": [
    {
     "ename": "AssertionError",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_29689/1209345406.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     14\u001b[0m     \u001b[0menv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0menviron\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m;\u001b[0m \u001b[0menv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mPYTHONPATH\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msite\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mEXPECTED_SITE\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msite\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSF_F32\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"0\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m     \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_output\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mPYTHON\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-I\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-c\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mprobe\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msite\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcwd\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mROOT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0menv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m     \u001b[0;32massert\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"version\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"0.1.14\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     17\u001b[0m     \u001b[0;32massert\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"has_prepared_api\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mframework\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"superfermion_optimized\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m     result.update(framework=framework, wheel=SITE_WHEELS[framework],\n",
      "\u001b[0;31mAssertionError\u001b[0m: "
     ]
    }
   ],
   "source": [
    "PROVENANCE = []\n",
    "probe = r\"\"\"\n",
    "import hashlib, json, os, pathlib, sys\n",
    "site = pathlib.Path(sys.argv[1]).resolve()\n",
    "sys.path.insert(0,str(site))\n",
    "import superfermion as sf\n",
    "import superfermion._sf_core as core\n",
    "assert pathlib.Path(sf.__file__).resolve().is_relative_to(site)\n",
    "print(json.dumps({'version': sf.__version__, 'package_file': sf.__file__,\n",
    "                  'extension_file': core.__file__, 'extension_sha256': hashlib.sha256(pathlib.Path(core.__file__).read_bytes()).hexdigest(),\n",
    "                  'has_prepared_api': hasattr(sf, 'prepare')}))\n",
    "\"\"\"\n",
    "for framework, site in SITES.items():\n",
    "    env = os.environ.copy(); env.update(PYTHONPATH=site, EXPECTED_SITE=site, SF_F32=\"0\")\n",
    "    result = json.loads(subprocess.check_output([PYTHON, \"-I\", \"-c\", probe, site], cwd=ROOT, env=env, text=True))\n",
    "    assert result[\"version\"] == \"0.1.14\"\n",
    "    assert result[\"has_prepared_api\"] == (framework == \"superfermion_optimized\")\n",
    "    result.update(framework=framework, wheel=SITE_WHEELS[framework],\n",
    "                  wheel_sha256=hashlib.sha256(Path(SITE_WHEELS[framework]).read_bytes()).hexdigest())\n",
    "    PROVENANCE.append(result)\n",
    "packages = json.loads(subprocess.check_output([PYTHON, \"-I\", \"-m\", \"pip\", \"list\", \"--format=json\"], text=True))\n",
    "cpu_probe = subprocess.run([\"lscpu\"], text=True, capture_output=True) if shutil.which(\"lscpu\") else None\n",
    "cpu = cpu_probe.stdout if cpu_probe is not None and cpu_probe.returncode == 0 else json.dumps({\n",
    "    \"machine\": platform.machine(), \"logical_cpus\": os.cpu_count(), \"processor\": platform.processor(),\n",
    "    \"detail_unavailable\": cpu_probe.stderr.strip() if cpu_probe else \"lscpu not installed\"})\n",
    "scripts = [\"legacy_adapter.py\",\"experiment_core.py\",\"prepare_study_data.py\",\"study_worker.py\",\"study_driver.py\",\"analyze_study.py\",\"offline_checks.py\"]\n",
    "MANIFEST = dict(base_commit=BASE_COMMIT, patch_sha256=PATCH_SHA256, source_hashes=EXPECTED_SOURCE_SHA256,\n",
    "                installations=PROVENANCE, packages=packages, cpu=cpu, platform=platform.platform(),\n",
    "                python=subprocess.check_output([PYTHON, \"--version\"], text=True).strip(),\n",
    "                rust=subprocess.check_output([CARGO, \"--version\"], env=BUILD_ENV, text=True).strip(),\n",
    "                build_flags=\"--release --locked; repository portable CPU flags; no native/LTO overrides\",\n",
    "                rustflags=BUILD_ENV.get(\"RUSTFLAGS\", \"repository .cargo/config.toml\"),\n",
    "                script_sha256={name: hashlib.sha256((EXPERIMENT_ROOT/name).read_bytes()).hexdigest() for name in scripts},\n",
    "                data=INPUTS, profile=RUN_PROFILE, repetitions=PROFILE[\"repetitions\"], threads=THREADS,\n",
    "                experiment_profile=PROFILE,simulator_lanes=FRAMEWORKS,setup_logs=str(LOGS),\n",
    "                worker_invocation=\"Python -I bootstrap; explicit benchmark and selected library paths\",\n",
    "                dependency_lock_sha256=hashlib.sha256(LOCK_PATH.read_bytes()).hexdigest(),\n",
    "                notebook_revision=\"requested_grid_24q_v8_1_desktop_mt16_t20min\")\n",
    "manifest_path = EXPERIMENT_ROOT/\"manifest.json\"; manifest_path.write_text(json.dumps(MANIFEST, indent=2))\n",
    "CONF[\"manifest_sha256\"] = hashlib.sha256(manifest_path.read_bytes()).hexdigest()\n",
    "CONFIG_PATH.write_text(json.dumps(CONF, indent=2))\n",
    "print(\"Manifest SHA256:\", CONF[\"manifest_sha256\"])\n",
    "for installation in PROVENANCE:\n",
    "    print(installation[\"framework\"], installation[\"wheel_sha256\"][:16], installation[\"extension_sha256\"][:16])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7138fd10",
   "metadata": {
    "id": "7138fd10"
   },
   "source": [
    "### 10. Check every simulator before timing\n",
    "\n",
    "At the configured validation qubits (4/8/12 for the requested grid), compare full first/last batch statevectors against\n",
    "independent NumPy propagation for Angle, Phase, Pauli, ZZ, GHZ, random and\n",
    "nontrivial-input QFT circuits. Check asymmetric endian order, mixed X/Y/Z\n",
    "observables, native mean-Z/diagonal batches, and parameter-shift gradients\n",
    "against finite differences. f64 tolerance is `3e-9`; qsim f32 uses `3e-5`,\n",
    "scaled by observable magnitude where needed. Each later state job also\n",
    "checks all norms and full first/last states outside timing.\n",
    "\n",
    "A failed gate stops the campaign. Failed worker logs are retained. No\n",
    "incomplete group is presented as a complete framework comparison.\n",
    "\n",
    "The native smoke test checks actual imports, two parameter rows, nontrivial state\n",
    "amplitudes, and mean-Z expectations in each installed backend. `backend_preflight.json`\n",
    "records Python paths, package versions, module files and isolation flags. This\n",
    "is preparation, not an extra timing comparison. A failure prints the original\n",
    "worker traceback in this cell, in addition to saving it as JSON.\n",
    "\n",
    "If this cell fails in your Colab runtime, read the **ROOT ERROR** displayed above\n",
    "the final controller error. A missing import, native library loading error,\n",
    "worker signal/timeout, and numerical mismatch are distinct failures; no generic\n",
    "fallback or tolerance increase is applied. To inspect an earlier failed run:\n",
    "\n",
    "```python\n",
    "for item in json.loads((EXPERIMENT_ROOT/\"validation_errors.json\").read_text()):\n",
    "    print(item[\"framework\"], item[\"n_qubits\"])\n",
    "    print(item.get(\"traceback\", item.get(\"log_tail\", item.get(\"error\"))))\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d2978f4",
   "metadata": {
    "id": "9d2978f4"
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import json\n",
    "\n",
    "# Save the original helper once, so rerunning this cell is safe.\n",
    "if \"_sf_run_logged_original\" not in globals():\n",
    "    _sf_run_logged_original = run_logged\n",
    "\n",
    "def run_logged(command, name, cwd=None, env=None, timeout=3600):\n",
    "    worker_env = os.environ.copy() if env is None else dict(env)\n",
    "    worker_env[\"MPLBACKEND\"] = \"Agg\"\n",
    "\n",
    "    return _sf_run_logged_original(\n",
    "        command,\n",
    "        name,\n",
    "        cwd=cwd,\n",
    "        env=worker_env,\n",
    "        timeout=timeout,\n",
    "    )\n",
    "\n",
    "\n",
    "# 1. Check backend imports and isolation.\n",
    "run_logged(\n",
    "    [PYTHON, EXPERIMENT_ROOT / \"study_driver.py\", CONFIG_PATH, \"preflight\"],\n",
    "    \"backend_preflight\",\n",
    "    timeout=1800,\n",
    ")\n",
    "\n",
    "print(\n",
    "    (LOGS / \"backend_preflight.log\")\n",
    "    .read_text(errors=\"replace\")[-2500:]\n",
    ")\n",
    "\n",
    "PREFLIGHT = json.loads(\n",
    "    (EXPERIMENT_ROOT / \"backend_preflight.json\").read_text()\n",
    ")\n",
    "\n",
    "assert PREFLIGHT, \"Preflight returned no results.\"\n",
    "assert all(\n",
    "    row[\"status\"] == \"ok\"\n",
    "    and row[\"isolated_python\"]\n",
    "    and row[\"user_site_disabled\"]\n",
    "    for row in PREFLIGHT\n",
    "), \"Backend preflight failed. Inspect backend_preflight.log.\"\n",
    "\n",
    "for row in PREFLIGHT:\n",
    "    print(\n",
    "        row[\"framework\"], \"->\", row[\"backend\"],\n",
    "        \"; isolated:\", row[\"isolated_python\"],\n",
    "    )\n",
    "\n",
    "\n",
    "# 2. Validate correctness before benchmarking.\n",
    "run_logged(\n",
    "    [PYTHON, EXPERIMENT_ROOT / \"study_driver.py\", CONFIG_PATH, \"validate\"],\n",
    "    \"independent_framework_checks\",\n",
    "    timeout=7200,\n",
    ")\n",
    "\n",
    "print(\n",
    "    (LOGS / \"independent_framework_checks.log\")\n",
    "    .read_text(errors=\"replace\")[-3500:]\n",
    ")\n",
    "\n",
    "show_table(\n",
    "    \"correctness\",\n",
    "    [\n",
    "        \"framework\",\n",
    "        \"n_qubits\",\n",
    "        \"case\",\n",
    "        \"max_amplitude_error\",\n",
    "        \"max_norm_error\",\n",
    "        \"native_readout_error\",\n",
    "        \"max_gradient_error\",\n",
    "        \"passed\",\n",
    "    ],\n",
    "    limit=20,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4f99c9f",
   "metadata": {
    "id": "d4f99c9f"
   },
   "source": [
    "### 11. Preview all requested jobs and bounded allocations\n",
    "\n",
    "Preview emits the 2,520 supported jobs, full logical bank requirements and the\n",
    "bounded exported-bank estimates. Large kernels share the same strategy across\n",
    "frameworks. Allocation guards remain active; their 512 MiB limit covers exported\n",
    "banks rather than total process RSS. Read actual RAM from worker measurements.\n",
    "\n",
    "Workers execute sequentially and retain per-job checkpoints. Failed/time-out\n",
    "workers remain explicit and do not stop later benchmark jobs when `fail_fast=False`.\n",
    "Preflight/independent correctness errors still stop the run. A free session may\n",
    "finish only part of this grid; analysis uses available checkpoints and reports\n",
    "pending/failed conditions instead of presenting a complete performance ranking.\n",
    "Groups run in ascending qubit bands; order is shuffled within bands and within\n",
    "framework groups. Reports refresh between jobs every 900 seconds. Computation\n",
    "timers and worker RAM are unaffected by simultaneous rendering because rendering\n",
    "runs in a separate process between workers. Campaign elapsed time includes it.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c1e396e",
   "metadata": {
    "id": "0c1e396e"
   },
   "outputs": [],
   "source": [
    "PLAN = None\n",
    "for name in [\"campaign_plan.json\", \"statebank_budget.csv\"]:\n",
    "    (EXPERIMENT_ROOT/name).unlink(missing_ok=True)\n",
    "try:\n",
    "    run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"preview\"],\"job_preview\",timeout=600)\n",
    "finally:\n",
    "    plan_path=EXPERIMENT_ROOT/\"campaign_plan.json\"\n",
    "    if plan_path.exists():\n",
    "        PLAN=json.loads(plan_path.read_text())\n",
    "        print(json.dumps(PLAN,indent=2))\n",
    "        show_table(\"planned_jobs\",limit=20)\n",
    "        show_table(\"statebank_budget\",[\"task\",\"dataset\",\"framework\",\"n_qubits\",\"track\",\n",
    "            \"execution_strategy\",\"logical_statebank_mib\",\"estimated_statebank_mib\",\"limit_mib\",\"limit_exceeded\"],\n",
    "            filters={\"limit_exceeded\":\"True\"},limit=12)\n",
    "if PLAN is None:\n",
    "    raise RuntimeError(\"Preview did not produce campaign_plan.json; inspect job_preview.log.\")\n",
    "if PLAN[\"jobs\"]>MAX_JOBS:\n",
    "    raise RuntimeError(f\"Preview has {PLAN['jobs']} jobs; MAX_JOBS={MAX_JOBS}. Review the plan and adjust the grid or visible cap.\")\n",
    "if RUN_PROFILE!=\"validation\" and not ALLOW_LARGE_RUN:\n",
    "    raise RuntimeError(\"Set ALLOW_LARGE_RUN=True to intentionally execute the displayed campaign\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6df2fdbb",
   "metadata": {
    "id": "6df2fdbb"
   },
   "source": [
    "### 12. Run QSVM, kernel regression, QKPCA and classical controls\n",
    "\n",
    "**QSVM/QKRR:** encode each sample once, construct\n",
    "\\(K_{ij}=|\\langle\\phi(x_i)|\\phi(x_j)\\rangle|^2\\), then use a precomputed\n",
    "SVC (`C=1`) or KernelRidge (`alpha=0.1`). Both Angle and ZZ kernels run on\n",
    "every dataset. The Angle map is independent RY gates plus a fixed entangler,\n",
    "so \\(K_{ij}=\\prod_q\\cos^2((x_{iq}-x_{jq})/2)\\) is an exact separate classical\n",
    "baseline. ZZ includes data-dependent two-wire phases and uses simulation.\n",
    "\n",
    "**QKPCA:** center the training kernel, retain up to three positive\n",
    "eigencomponents, and center held-out kernel rows with training column/grand\n",
    "means. Train a logistic head only on training embeddings. Kernel encoding,\n",
    "matrix algebra and the eigensolver/head are separate timings.\n",
    "\n",
    "**Classical controls:** use the same projected angles and fixed split.\n",
    "Full-original-feature classification accuracy is recorded separately to\n",
    "show whether dimensionality reduction removed useful information. No\n",
    "hyperparameter search or test-based model selection is performed.\n",
    "\n",
    "At high qubit counts, kernel banks are processed by bounded re-encoding blocks.\n",
    "Large memory requirements remain visible in the preview as logical banks; the\n",
    "actual execution uses bounded exports without changing the full dataset split.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47ac762f",
   "metadata": {
    "id": "47ac762f"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"run\",\"qsvm,qkrr,qkpca,classical\"],\n",
    "           \"kernel_and_classical_campaign\",timeout=172800)\n",
    "print((LOGS/\"kernel_and_classical_campaign.log\").read_text()[-2200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1042f740",
   "metadata": {
    "id": "1042f740"
   },
   "source": [
    "### 13. Train VQC and VQR with matched optimizer budgets\n",
    "\n",
    "A hardware-efficient ansatz adds RY/RZ layers and a CNOT chain to the Angle\n",
    "encoding. Its readout is the mean of single-qubit Z expectations. Binary\n",
    "VQC uses \\(\\sigma(2\\langle\\bar Z\\rangle+b)\\). Multiclass VQC uses one\n",
    "parameterized circuit per class and softmax-normalized scores. VQR uses\n",
    "\\(a\\langle\\bar Z\\rangle+b\\), trained on train-standardized targets and\n",
    "evaluated in original target units.\n",
    "\n",
    "The requested preset uses five full-batch SPSA updates on 4/8/12 qubits.\n",
    "Every perturbation loss uses the complete 80% training partition. Initial\n",
    "parameters, row orders, perturbation signs and update schedules match across\n",
    "all backends. Other presets may explicitly use minibatches. The learning rates are fixed:\n",
    "\\(a_k=0.12/(k+1)^{0.602}\\), \\(c_k=0.1/(k+1)^{0.101}\\). Full training loss\n",
    "is measured after every update for interpretable traces. No backend gets\n",
    "extra training steps, early stopping, or a different optimizer. The final\n",
    "training loss is reused rather than recomputed. Small validation budgets\n",
    "can produce poor predictions; that is retained in the quality results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ede1afb",
   "metadata": {
    "id": "1ede1afb"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"run\",\"vqc,vqr\"],\n",
    "           \"variational_qml_campaign\",timeout=172800)\n",
    "print((LOGS/\"variational_qml_campaign.log\").read_text()[-2200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21665fda",
   "metadata": {
    "id": "21665fda"
   },
   "source": [
    "### 14. Run QAOA feature selection, MaxCut and Ising VQE\n",
    "\n",
    "**Feature selection:** rank original features by train-only mutual\n",
    "information. Minimize a shared QUBO combining negative relevance, absolute\n",
    "correlation redundancy and a cardinality penalty. With binary variables\n",
    "\\(z_i\\), the cost is\n",
    "\\(-\\sum_i r_i z_i+0.25\\sum_{i<j}|\\rho_{ij}|z_i z_j+1.5(\\sum_i z_i-k)^2\\),\n",
    "with \\(k=\\max(1,\\lfloor m/2\\rfloor)\\), where \\(m\\) is the number of\n",
    "real feature variables. Ancillas have zero coefficients, are excluded from\n",
    "this cardinality penalty and do not enter the downstream feature selection. The QUBO→Ising transformation uses\n",
    "\\(z_i=(1-Z_i)/2\\). A cached diagonal vector is given to all state-track\n",
    "reductions and equivalent native Pauli observables to the native track.\n",
    "The modal bitstring's original features train a logistic classifier;\n",
    "an empty selection is explicitly scored with a majority-class classifier.\n",
    "\n",
    "**MaxCut:** weighted ring and seeded Erdős–Rényi graphs. Minimize negative\n",
    "cut weight. Enumerate all bitstrings for the exact optimum and report\n",
    "the expected-cut/optimal-cut ratio, energy gap and optimum probability.\n",
    "These quantities differ from the cost of the modal bitstring.\n",
    "\n",
    "**VQE:** the open transverse-field Ising Hamiltonian\n",
    "\\(H=-\\sum_{q=0}^{n-2}Z_q Z_{q+1}-0.7\\sum_{q=0}^{n-1}X_q\\), a two-layer\n",
    "RY/RZ ansatz, and an exact open-chain free-fermion ground-state energy. Mixed\n",
    "observables make this a different workload from diagonal QAOA readouts.\n",
    "Native training, final state diagnostics and downstream classifier time\n",
    "are kept separate. The same matched SPSA budget applies to every lane.\n",
    "\n",
    "For the open TFIM only, the exact reference is now `-sum(svd(bidiagonal(field,\n",
    "coupling)))`, using an n-by-n matrix. Small systems are checked independently\n",
    "against the original dense spin Hamiltonian. Reference time is recorded separately;\n",
    "full worker elapsed plots include setup/references/diagnostics. QAOA diagonals\n",
    "and MaxCut costs retain full exact bitstring costs but construct them in blocks.\n",
    "See [The quantum Ising chain for beginners](https://arxiv.org/abs/2009.09208)\n",
    "for the Jordan-Wigner/free-fermion diagonalization background.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d7ca112",
   "metadata": {
    "id": "9d7ca112"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"run\",\"qaoa_fs,maxcut,vqe\"],\n",
    "           \"optimization_campaign\",timeout=172800)\n",
    "print((LOGS/\"optimization_campaign.log\").read_text()[-2200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45364a02",
   "metadata": {
    "id": "45364a02"
   },
   "source": [
    "### 15. Differentiate with a matched parameter-shift algorithm\n",
    "\n",
    "Every trainable RY/RZ angle occurs in exactly one gate, so\n",
    "\\(\\partial_{\\theta_j}f=(f(\\theta_j+\\pi/2)-f(\\theta_j-\\pi/2))/2\\).\n",
    "Batch the same \\(2P\\) shifted circuits for every backend. Check the resulting\n",
    "vector against independent NumPy central finite differences (`epsilon=1e-6`).\n",
    "Compare common state export with native scalar reductions.\n",
    "\n",
    "This measures the same differentiation algorithm across all frameworks.\n",
    "It does **not** claim that parameter shift is faster than each framework's\n",
    "best adjoint/backprop implementation. Native-adjoint and accelerator studies\n",
    "would be separate, capability-matched experiments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c20a303a",
   "metadata": {
    "id": "c20a303a"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"run\",\"gradient\"],\n",
    "           \"gradient_campaign\",timeout=172800)\n",
    "print((LOGS/\"gradient_campaign.log\").read_text()[-2200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d452ab39",
   "metadata": {
    "id": "d452ab39"
   },
   "source": [
    "### 16. Scale qubits, feature maps, batches and circuit depth\n",
    "\n",
    "GHZ exercises Clifford structure but uses the same general statevector\n",
    "contract for all lanes. QFT starts from a seeded nontrivial product state;\n",
    "controlled phases are decomposed into P/CNOT gates and final bit swaps.\n",
    "Random circuits interleave RY/RZ layers and alternating entangling chains.\n",
    "Angle, Phase, Pauli and ZZ map batches use identical generated inputs.\n",
    "\n",
    "Batch sweeps expose binding/export amortization; depth sweeps expose gate\n",
    "work and fusion. Repetition order is paired and randomised. The memory metric\n",
    "is Linux process high-water RSS at the end of the measured stage, before\n",
    "independent numerical audits. It includes imports, preparation and warmup;\n",
    "state-bank bytes are recorded separately. It is not a device-memory metric.\n",
    "\n",
    "Every family, batch-size case and depth case now spans all six qubit counts.\n",
    "Large state outputs are exported/discarded in bounded chunks. Every measured\n",
    "state norm is reduced inside the timer; first/last full states are independently\n",
    "replayed after timing for amplitude checks. All backends share this output contract.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70591b48",
   "metadata": {
    "id": "70591b48"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"study_driver.py\",CONFIG_PATH,\"run\",\"circuit\"],\n",
    "           \"circuit_scaling_campaign\",timeout=172800)\n",
    "print((LOGS/\"circuit_scaling_campaign.log\").read_text()[-2200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d1e1c81",
   "metadata": {
    "id": "3d1e1c81"
   },
   "source": [
    "## Results\n",
    "\n",
    "### 17. Reconcile coverage, timings and outcome agreement\n",
    "\n",
    "Only complete simulator groups receive paired speedups. Analytical and\n",
    "classical algorithms remain separate lanes. Compare f64-only leaders as\n",
    "well as all-lane leaders because qsim computes in f32. The source/modified\n",
    "comparison uses the same compiler and flags. Ratios below one mean the\n",
    "competitor is faster; those losses remain in the tables and figures.\n",
    "\n",
    "Repeated model metrics are numerical consistency checks. Independent split\n",
    "seeds, not repeated copies of the same test split, are needed for broader\n",
    "ML conclusions. Native and state tracks are different output contracts, so\n",
    "compare within a track before interpreting cross-track savings.\n",
    "\n",
    "Analysis also reconciles the entire requested plan against available checkpoints.\n",
    "Successful complete groups alone receive paired ratios. Failure/pending conditions\n",
    "remain in the all-experiment time/RAM table, and every cost figure retains requested\n",
    "qubit ticks with gaps for missing measurements. Single-repeat IQR is not uncertainty.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76743257",
   "metadata": {
    "id": "76743257"
   },
   "outputs": [],
   "source": [
    "run_logged([PYTHON,EXPERIMENT_ROOT/\"analyze_study.py\",CONFIG_PATH],\"analysis\",timeout=1800)\n",
    "OVERVIEW=json.loads((EXPERIMENT_ROOT/\"overview.json\").read_text())\n",
    "print(json.dumps(OVERVIEW,indent=2))\n",
    "if not OVERVIEW[\"complete\"]:\n",
    "    print(\"INCOMPLETE CAMPAIGN:\", OVERVIEW[\"failed_jobs\"], \"failed jobs;\", OVERVIEW[\"pending_jobs\"], \"pending. Only successful complete groups receive paired comparisons.\")\n",
    "FIGURES=json.loads((EXPERIMENT_ROOT/\"figure_index.json\").read_text())\n",
    "def show_figure(key):\n",
    "    if key not in FIGURES:\n",
    "        print(f\"No figure for {key}: inspect successful measurements and experiment_job_status.csv.\")\n",
    "        return\n",
    "    display(Image(filename=FIGURES[key]))\n",
    "show_table(\"condition_leaders\",[\"task\",\"dataset\",\"n_qubits\",\"feature_map\",\"family\",\"track\",\n",
    "    \"depth\",\"batch_size\",\"fastest_all\",\"fastest_f64\",\"source_over_modified\",\"qulacs_over_modified\"],limit=18)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a55dc94e",
   "metadata": {
    "id": "a55dc94e"
   },
   "source": [
    "### Kernel classification across five datasets\n",
    "\n",
    "The figures show the ZZ map at the smallest recorded QML qubit count,\n",
    "first thread budget and smallest seed value. That fixed slice is chosen\n",
    "before viewing the winning times. Full Angle/ZZ and all other configurations\n",
    "are retained in `timing_summary.csv`. Read encoding versus kernel-algebra\n",
    "columns when larger sample counts make BLAS work dominate.\n",
    "\n",
    "Displayed validation slice: ZZ map, 24 training and 12 test rows, four qubits, seed 42, two process repeats."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6931229e",
   "metadata": {
    "id": "6931229e"
   },
   "outputs": [],
   "source": [
    "show_figure(\"qsvm_latency\")\n",
    "show_table(\"timing_summary\",[\"dataset\",\"framework\",\"median_ms\",\"q25_ms\",\"q75_ms\",\"repetitions\",\n",
    "    \"accuracy\",\"balanced_accuracy\",\"f1_macro\"],filters={\"task\":\"qsvm\",\"feature_map\":\"zz\"},limit=40)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "588f2053",
   "metadata": {
    "id": "588f2053"
   },
   "source": [
    "### Kernel regression and representation learning\n",
    "\n",
    "Regression targets are evaluated in their original units; comparing RMSE\n",
    "magnitudes across unrelated target scales is not a model ranking. QKPCA\n",
    "timing separates the simulator/kernel stage from eigendecomposition and\n",
    "the classical head. Its held-out transform uses training means and eigenvectors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fa83ae4d",
   "metadata": {
    "id": "fa83ae4d"
   },
   "outputs": [],
   "source": [
    "show_figure(\"qkrr_latency\")\n",
    "show_figure(\"qkpca_latency\")\n",
    "show_table(\"model_and_solver_quality\",[\"task\",\"dataset\",\"framework\",\"feature_map\",\"rmse\",\"mae\",\"r2\",\n",
    "    \"balanced_accuracy\",\"qkpca_variance_fraction\"],filters={\"framework\":\"superfermion_optimized\"},limit=30)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c76d7b1a",
   "metadata": {
    "id": "c76d7b1a"
   },
   "source": [
    "### Variational classification and regression\n",
    "\n",
    "Compare native-readout runtime and test quality together. A faster library\n",
    "runs the same training procedure more quickly; it does not change the\n",
    "ansatz's expressive power or guarantee convergence. The three-class Iris\n",
    "VQC has one circuit per class, which is more work than the binary classifier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f9985941",
   "metadata": {
    "id": "f9985941"
   },
   "outputs": [],
   "source": [
    "show_figure(\"vqc_latency\")\n",
    "show_figure(\"vqr_latency\")\n",
    "show_table(\"model_and_solver_quality\",[\"task\",\"dataset\",\"track\",\"framework\",\"final_loss\",\"accuracy\",\n",
    "    \"balanced_accuracy\",\"rmse\",\"mae\",\"r2\"],filters={\"framework\":\"superfermion_optimized\",\"track\":\"native_readout\"},limit=25)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff16de99",
   "metadata": {
    "id": "ff16de99"
   },
   "source": [
    "### QAOA and physical VQE\n",
    "\n",
    "Exact-optimum gaps, cut ratios and solution probabilities complement timing.\n",
    "A short validation optimizer can retain a large gap; no convergence target\n",
    "is silently relaxed to make one backend appear better. The final modal\n",
    "feature subset and downstream accuracy are present in the raw job records."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f8db614",
   "metadata": {
    "id": "1f8db614"
   },
   "outputs": [],
   "source": [
    "show_figure(\"qaoa_fs_latency\")\n",
    "show_figure(\"maxcut_latency\")\n",
    "show_figure(\"vqe_latency\")\n",
    "show_table(\"model_and_solver_quality\",[\"task\",\"dataset\",\"framework\",\"final_energy\",\"ground_energy\",\n",
    "    \"energy_gap\",\"approximation_ratio\",\"optimum_probability\",\"fs_downstream_accuracy\"],\n",
    "    filters={\"framework\":\"superfermion_optimized\",\"track\":\"native_readout\"},limit=25)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95eac430",
   "metadata": {
    "id": "95eac430"
   },
   "source": [
    "### Gradient and readout sensitivity\n",
    "\n",
    "Parameter-shift uses the same shifted-circuit count on every backend. The\n",
    "second figure compares state-export and native-readout variants of the\n",
    "same workload. Above one means native scalar execution saved time; below\n",
    "one means its overhead outweighed export savings in that configuration."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ce64f01",
   "metadata": {
    "id": "4ce64f01"
   },
   "outputs": [],
   "source": [
    "show_figure(\"gradient_latency\")\n",
    "show_figure(\"readout_sensitivity\")\n",
    "show_table(\"outcome_agreement\",[\"task\",\"dataset\",\"framework\",\"gradient_max_difference\",\n",
    "    \"kernel_probe_max_difference\",\"prediction_mismatches\",\"final_energy_difference\",\"final_loss_difference\"],limit=25)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3050045",
   "metadata": {
    "id": "a3050045"
   },
   "source": [
    "### Scaling and feature-map sensitivity\n",
    "\n",
    "Lines connect genuinely different qubit/depth settings; bands show fresh\n",
    "process IQR. Single-configuration figures use points and whiskers. Inspect\n",
    "the batch plot before attributing a large speedup to faster gate kernels:\n",
    "wrapper and export amortization can dominate at small qubit counts.\n",
    "\n",
    "Validation figures: GHZ/QFT/random use batch 1 and 4/8/12 qubits. The feature-map comparison uses 16 circuits at eight qubits. Angle batch sweeps use 1/8/32 circuits; random depth sweeps use 1/4/8 layers, at eight qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71be0aca",
   "metadata": {
    "id": "71be0aca"
   },
   "outputs": [],
   "source": [
    "show_figure(\"circuit_scaling\")\n",
    "show_figure(\"feature_maps_latency\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6878764e",
   "metadata": {
    "id": "6878764e"
   },
   "outputs": [],
   "source": [
    "show_figure(\"batch_runtime\")\n",
    "show_figure(\"batch_per_circuit\")\n",
    "show_figure(\"depth_scaling\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4ee4bf7",
   "metadata": {
    "id": "f4ee4bf7"
   },
   "source": [
    "### Model quality and optimizer traces\n",
    "\n",
    "Classical estimators use the same projected inputs and split. Their fitting\n",
    "times are end-to-end model workload timings, so compare those with quantum\n",
    "end-to-end timings, not with a gate-only or encoding-only number. The quality\n",
    "charts show one validation split without a confidence interval; absent\n",
    "models are omitted, not plotted as zero.\n",
    "\n",
    "The trace figure uses full training losses or full energies at each SPSA\n",
    "iterate. Overlapping simulator traces indicate numerical agreement. They\n",
    "do not show that one implementation learned a better model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f295edcc",
   "metadata": {
    "id": "f295edcc"
   },
   "outputs": [],
   "source": [
    "show_figure(\"classification_quality\")\n",
    "show_figure(\"regression_quality\")\n",
    "show_figure(\"optimization_traces\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ad98ade",
   "metadata": {
    "id": "3ad98ade"
   },
   "source": [
    "### RAM consumption per framework\n",
    "\n",
    "Each job runs in its own CPU worker. RSS includes Python objects, native\n",
    "Rust/C++ buffers and resident library pages. Units are **MiB (2²⁰ bytes)**.\n",
    "\n",
    "| Metric | Meaning |\n",
    "|---|---|\n",
    "| `worker_peak_rss_mib` | OS high-water mark at job end, before JSON serialization; includes imports, setup, warmup, fitting/inference, diagnostics and audits performed by the job |\n",
    "| `primary_stage_peak_rss_mib` | Existing OS high-water mark at the primary stage endpoint; includes earlier imports/setup/warmup |\n",
    "| `worker_entry_rss_mib`, `worker_exit_rss_mib` | Current RSS snapshots before/after the task from Linux procfs; unavailable readings stay missing |\n",
    "| `worker_rss_change_mib` | Exit minus entry RSS; retained change, can be negative, and is not peak allocated memory |\n",
    "\n",
    "Primary-stage HWM is not a resettable, stage-only allocation counter. Median,\n",
    "IQR, P95 and maximum describe **per-job measurements**, not time-averaged RAM.\n",
    "Pooled summaries mix workload settings; use condition-level/matched tables\n",
    "for comparisons. Snapshots do not measure GPU, whole-machine or child-process\n",
    "RAM. Do not sum process RSS as physical-machine usage because resident pages\n",
    "can be shared. Recording uses endpoint reads without a polling thread inside\n",
    "the timed stages.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ebf94382",
   "metadata": {
    "id": "ebf94382"
   },
   "outputs": [],
   "source": [
    "show_figure(\"ram_framework_overview\")\n",
    "show_table(\"ram_framework_summary\",[\"framework\",\"threads\",\"tasks\",\"conditions\",\"measured_jobs\",\n",
    "    \"worker_peak_median_mib\",\"worker_peak_q25_mib\",\"worker_peak_q75_mib\",\n",
    "    \"worker_peak_p95_mib\",\"worker_peak_max_mib\",\"missing_peak_jobs\"],limit=20)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a03ba1a",
   "metadata": {
    "id": "0a03ba1a"
   },
   "source": [
    "### RAM per framework and each task\n",
    "\n",
    "The heatmaps keep statevector and native-readout tracks separate and share one\n",
    "colour scale. Cells pool settings within each task; tables report job counts,\n",
    "IQR, P95 and maximum. Grey cells are not run, not zero. Analytical and classical\n",
    "controls appear in the CSV tables with their own task sets. Preflight/validation\n",
    "footprints are reported separately from benchmark summaries.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bee34865",
   "metadata": {
    "id": "bee34865"
   },
   "outputs": [],
   "source": [
    "show_figure(\"ram_task_statevector\")\n",
    "show_figure(\"ram_task_native_readout\")\n",
    "show_table(\"ram_by_framework_task\",[\"task\",\"track\",\"framework\",\"threads\",\"measured_jobs\",\"conditions\",\n",
    "    \"worker_peak_median_mib\",\"worker_peak_q25_mib\",\"worker_peak_q75_mib\",\n",
    "    \"worker_peak_p95_mib\",\"worker_peak_max_mib\",\"primary_stage_peak_median_mib\"],limit=60)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4062660c",
   "metadata": {
    "id": "4062660c"
   },
   "source": [
    "### Inspect RAM for an exact workload\n",
    "\n",
    "Edit `RAM_FILTERS` to choose a task, dataset, qubit count, track or framework.\n",
    "The complete CSVs retain every setting and repeat. Paired ratios use complete\n",
    "eight-backend groups with identical conditions. A competitor/modified RAM\n",
    "ratio below 1 means the competitor used less peak resident RAM in that job.\n",
    "Shared import/setup costs are included; this does not establish a universal\n",
    "simulator-memory ranking. qsim remains labelled as the f32 lane.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fbc81fe7",
   "metadata": {
    "id": "fbc81fe7"
   },
   "outputs": [],
   "source": [
    "RAM_FILTERS={\"task\":\"qsvm\"}  # e.g. add \"dataset\":\"iris\", \"n_qubits\":4\n",
    "show_table(\"ram_by_condition\",[\"task\",\"dataset\",\"n_qubits\",\"feature_map\",\"track\",\"depth\",\n",
    "    \"batch_size\",\"seed\",\"threads\",\"framework\",\"measured_jobs\",\"worker_peak_median_mib\",\n",
    "    \"worker_peak_q25_mib\",\"worker_peak_q75_mib\",\"worker_peak_max_mib\",\n",
    "    \"primary_stage_peak_median_mib\",\"entry_rss_median_mib\",\"exit_rss_median_mib\"],\n",
    "    filters=RAM_FILTERS,limit=24)\n",
    "PAIR_FILTERS={k:v for k,v in RAM_FILTERS.items() if k!=\"framework\"}\n",
    "show_table(\"ram_paired_comparisons\",[\"task\",\"dataset\",\"n_qubits\",\"feature_map\",\"track\",\"seed\",\n",
    "    \"repetition\",\"competitor\",\"competitor_peak_mib\",\"modified_peak_mib\",\n",
    "    \"competitor_over_modified_ram\",\"competitor_minus_modified_mib\"],filters=PAIR_FILTERS,limit=24)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e645fad",
   "metadata": {
    "id": "5e645fad"
   },
   "source": [
    "### Raw RAM records and backend-check footprints\n",
    "\n",
    "Raw rows include status and missing measurements; failures are never turned\n",
    "into zero RAM. `ram_backend_checks.csv` contains preflight and correctness jobs,\n",
    "whose primary-stage metric is not defined. Full measurement definitions are\n",
    "exported in `ram_methodology.json`. All RAM CSV/HTML files, raw worker JSONs\n",
    "and PNG/SVG figures are included automatically in the final results ZIP.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "77a6d3cf",
   "metadata": {
    "id": "77a6d3cf"
   },
   "outputs": [],
   "source": [
    "show_table(\"ram_per_job\",[\"framework\",\"task\",\"dataset\",\"n_qubits\",\"track\",\"seed\",\"repetition\",\n",
    "    \"status\",\"worker_peak_rss_mib\",\"primary_stage_peak_rss_mib\",\"worker_entry_rss_mib\",\n",
    "    \"worker_exit_rss_mib\",\"worker_rss_change_mib\"],filters=RAM_FILTERS,limit=24)\n",
    "show_table(\"ram_backend_checks\",[\"framework\",\"task\",\"n_qubits\",\"status\",\n",
    "    \"worker_peak_rss_mib\",\"worker_entry_rss_mib\",\"worker_exit_rss_mib\"],limit=32)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9293218a",
   "metadata": {
    "id": "9293218a"
   },
   "source": [
    "### Circuit footprint and all paired runtime ratios\n",
    "\n",
    "The original circuit-memory view remains available. Runtime-ratio spread\n",
    "reflects different workloads and repeats, not uncertainty around one universal\n",
    "speedup factor. Full condition-level tables retain losses as well as wins.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d0efc8ed",
   "metadata": {
    "id": "d0efc8ed"
   },
   "outputs": [],
   "source": [
    "show_figure(\"process_memory\")\n",
    "show_figure(\"paired_speedup_distribution\")\n",
    "show_table(\"group_coverage\",[\"task\",\"dataset\",\"n_qubits\",\"track\",\"repetition\",\"complete\"],limit=15)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a8b7ca0",
   "metadata": {
    "id": "3a8b7ca0"
   },
   "source": [
    "### Time and RAM for every experiment across the requested qubit grid\n",
    "\n",
    "Every exact task/dataset/map/family/track/depth/batch/iteration/seed/thread/model\n",
    "condition has its own three-panel figure. Curves compare framework runtimes and\n",
    "process RAM at all requested qubits without pooling datasets or qubit counts.\n",
    "The full worker timer includes startup, setup, warmups, reference calculations,\n",
    "audits and serialization; primary computation time retains the experiment's timer.\n",
    "RAM is Linux worker high-water resident RAM, including native allocations.\n",
    "Missing, unsupported, failed or pending values appear as gaps, not zero.\n",
    "All figures are saved as PNG and editable SVG and are included in the result ZIP.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b4e8125",
   "metadata": {
    "id": "4b4e8125"
   },
   "outputs": [],
   "source": [
    "COST_FIGURES=json.loads((EXPERIMENT_ROOT/\"all_experiment_figures.json\").read_text())\n",
    "print(\"Exact-condition time/RAM figures:\",len(COST_FIGURES))\n",
    "show_table(\"all_experiment_figures\",[\"task\",\"dataset\",\"feature_map\",\"family\",\"track\",\"depth\",\"batch_size\",\n",
    "    \"iterations\",\"successful_jobs\",\"failed_jobs\",\"pending_jobs\",\"key\"],limit=25)\n",
    "if SHOW_ALL_EXPERIMENT_FIGURES:\n",
    "    for figure in COST_FIGURES:\n",
    "        print(figure[\"figure_title\"])\n",
    "        display(Image(filename=figure[\"png\"],width=1400))\n",
    "else:\n",
    "    print(\"All files are saved. Set SHOW_ALL_EXPERIMENT_FIGURES=True to display every figure here.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82d58734",
   "metadata": {
    "id": "82d58734"
   },
   "source": [
    "### Inspect exact time/RAM values and failed or pending jobs\n",
    "\n",
    "Filter the CSV table by task, dataset, track, framework or qubit count. The complete\n",
    "CSV contains every supported planned condition and the attempted/successful/failed/\n",
    "pending counts. Process peaks are not added together as physical machine RAM.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a01a6cbe",
   "metadata": {
    "id": "a01a6cbe"
   },
   "outputs": [],
   "source": [
    "COST_FILTERS={}  # e.g. {\"task\":\"vqe\", \"n_qubits\":24}\n",
    "show_table(\"all_experiment_time_ram\",[\"task\",\"dataset\",\"n_qubits\",\"framework\",\"track\",\"feature_map\",\"family\",\n",
    "    \"depth\",\"batch_size\",\"iterations\",\"primary_runtime_median_s\",\"worker_wall_time_median_s\",\n",
    "    \"worker_peak_median_mib\",\"expected_jobs\",\"successful_jobs\",\"failed_jobs\",\"pending_jobs\"],\n",
    "    filters=COST_FILTERS,limit=40)\n",
    "show_table(\"experiment_job_status\",[\"task\",\"dataset\",\"n_qubits\",\"framework\",\"track\",\"status\",\"error\",\n",
    "    \"primary_runtime_s\",\"worker_wall_time_s\",\"worker_peak_rss_mib\"],filters={\"status\":\"error\"},limit=20)\n",
    "show_table(\"unsupported_feature_selection\",limit=20)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b04f8030",
   "metadata": {
    "id": "b04f8030"
   },
   "source": [
    "## Takeaways\n",
    "\n",
    "The generated text below follows the measured outputs. Continue with the\n",
    "larger study only after execution and numerical agreement are clean.\n",
    "If Qulacs wins particular workloads, profile those workloads; a Rust-to-C++\n",
    "rewrite is not automatically the remedy. Investigate prepared-plan work,\n",
    "state allocation/export, gate fusion and memory bandwidth before changing\n",
    "implementation language. Include a baseline's best comparable execution\n",
    "API before making broad performance claims."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4699c049",
   "metadata": {
    "id": "4699c049"
   },
   "outputs": [],
   "source": [
    "print(f\"Successful jobs: {OVERVIEW['successful_jobs']}; failed: {OVERVIEW['failed_jobs']}; pending: {OVERVIEW['pending_jobs']}.\")\n",
    "print(\"Complete campaign:\",OVERVIEW[\"complete\"])\n",
    "print(f\"Modified SF led {OVERVIEW['modified_fastest_f64']}/{OVERVIEW['measured_conditions']} complete f64 configurations and {OVERVIEW['modified_fastest_all']}/{OVERVIEW['measured_conditions']} including qsim f32.\")\n",
    "if OVERVIEW[\"source_over_modified_median\"] is not None:\n",
    "    print(f\"Source/modified median paired ratio: {OVERVIEW['source_over_modified_median']:.3f}x.\")\n",
    "    print(f\"Qulacs/modified median paired ratio: {OVERVIEW['qulacs_over_modified_median']:.3f}x; below 1 means Qulacs faster.\")\n",
    "print(\"Read all_experiment_time_ram.csv, experiment_job_status.csv and each condition's scaling figure for the complete grid.\")\n",
    "print(\"VQC/VQR use 4/8/12 qubits and 5 updates. Other supported quantum tasks request 4/8/12/16/20/24. Every dataset uses its full 80/20 split.\")\n",
    "print(\"One seed/repeat and incomplete large-qubit coverage cannot establish universal performance or quantum ML advantage.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4da0076",
   "metadata": {
    "id": "b4da0076"
   },
   "source": [
    "### 18. Export a reproducible source and results bundle\n",
    "\n",
    "Retain fixed splits, preprocessing arrays, hashes, source patch/changed\n",
    "files, configuration, raw active jobs, failed-job evidence, logs, numerical\n",
    "checks, tables, PNG/SVG charts and exact dependency pins. The bundle excludes\n",
    "large toolchain/venv caches. In Colab, download the generated ZIP and save\n",
    "the executed notebook with **File → Download → Download .ipynb**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9075a404",
   "metadata": {
    "id": "9075a404"
   },
   "outputs": [],
   "source": [
    "import zipfile\n",
    "RESULT_ZIP=EXPERIMENT_ROOT/f\"Superfermion_{RUN_PROFILE}_Expanded_Results.zip\"\n",
    "active=json.loads((EXPERIMENT_ROOT/\"all_results.json\").read_text())+json.loads((EXPERIMENT_ROOT/\"validation_results.json\").read_text())+json.loads((EXPERIMENT_ROOT/\"backend_preflight.json\").read_text())\n",
    "active_ids={row[\"job_id\"] for row in active}\n",
    "with zipfile.ZipFile(RESULT_ZIP,\"w\",compression=zipfile.ZIP_DEFLATED) as archive:\n",
    "    for path in EXPERIMENT_ROOT.rglob(\"*\"):\n",
    "        if not path.is_file() or path==RESULT_ZIP or \"__pycache__\" in path.parts: continue\n",
    "        rel=path.relative_to(EXPERIMENT_ROOT)\n",
    "        if rel.parts[0]==\"raw\" and path.name.split(\".\")[0] not in active_ids: continue\n",
    "        archive.write(path,\"results/\"+str(rel))\n",
    "    archive.write(PATCH_PATH,\"modifications/superfermion_performance.patch\")\n",
    "    archive.writestr(\"modifications/source_manifest.json\",json.dumps({\"base_commit\":BASE_COMMIT,\n",
    "        \"patch_sha256\":PATCH_SHA256,\"modified_file_sha256\":EXPECTED_SOURCE_SHA256},indent=2))\n",
    "    for relative in EXPECTED_SOURCE_SHA256:\n",
    "        archive.write(OPT/relative,\"modifications/modified_files/\"+relative)\n",
    "        if (BASE/relative).exists():archive.write(BASE/relative,\"modifications/original_files/\"+relative)\n",
    "print(\"Bundle:\",RESULT_ZIP.name,\"bytes:\",RESULT_ZIP.stat().st_size)\n",
    "try:\n",
    "    from google.colab import files\n",
    "except ImportError:\n",
    "    print(\"Local execution: notebook and ZIP paths are retained in the execution receipt.\")\n",
    "else:\n",
    "    files.download(str(RESULT_ZIP))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14de7c9d",
   "metadata": {
    "id": "14de7c9d"
   },
   "source": [
    "### References and scope\n",
    "\n",
    "* [Superfermion source](https://github.com/Catstate101/superfermion), pinned to the commit above.\n",
    "* [Qiskit Aer Simulator](https://qiskit.github.io/qiskit-aer/stubs/qiskit_aer.AerSimulator.html): runtime parameter binding and explicit CPU options.\n",
    "* [PennyLane QNode](https://docs.pennylane.ai/en/stable/code/api/pennylane.qnode.html) and [Lightning device](https://docs.pennylane.ai/projects/lightning/en/stable/code/api/pennylane_lightning.lightning_qubit.LightningQubit.html): broadcasting is expanded by Lightning, not intrinsically fused.\n",
    "* [Cirq simulation](https://quantumai.google/cirq/simulate/simulation) and [qsim](https://quantumai.google/qsim): explicit separate f64/f32 lanes.\n",
    "* [Qulacs advanced guide](https://docs.qulacs.org/en/latest/guide/2.0_python_advanced.html) and [installation/thread controls](https://docs.qulacs.org/en/latest/intro/1_install.html): parametric circuit/state reuse and rotation conventions.\n",
    "* [scikit-learn dataset documentation](https://scikit-learn.org/stable/datasets/toy_dataset.html) and [synthetic generators](https://scikit-learn.org/stable/datasets/sample_generators.html): built-in sources and seeded generated datasets. Read the datasets' descriptions for original attribution.\n",
    "\n",
    "These are ideal CPU statevector/API benchmarks and small classical-data QML\n",
    "experiments. They do not compare every algorithm available in each framework,\n",
    "nor demonstrate quantum advantage. Saved results identify the actually\n",
    "executed profile, build flags and precision. Local checks cover notebook schema/syntax, the pure grid, independent small\n",
    "numerical helpers, NumPy-reference worker paths and pending-only report rendering.\n",
    "The full native campaign and hosted Colab runtime have not been exercised here."
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.12"
  },
  "superfermion_study": {
   "all_experiment_cost_panels": [
    "primary_runtime_s",
    "worker_wall_time_s",
    "worker_peak_rss_mib"
   ],
   "base_commit": "35f8f7c306ac2a004e6b10dee37317d87918d5dc",
   "execution_status": "full native campaign not run; schema, syntax, pure grid and separate small numerical/helper checks only",
   "full_project_tests_default": false,
   "local_numerical_helper_checks": {
    "ancillary_embedding": "4 real features in an 8-qubit register: exact costs and QAOA energy agree",
    "ancillary_embedding_energy_error": 4.440892098500626e-16,
    "basis_chunk_boundary": "19-qubit X/Y/Z/identity cases passed",
    "blocked_qubo_max_error": 2.2737367544323206e-13,
    "bounded_kernel_cases": 6,
    "bounded_kernel_max_error": 7.771561172376096e-16,
    "external_framework_benchmarks": "not run",
    "full_data_split": "Breast Cancer 455/114",
    "largest_exported_bank_mib": 512,
    "pending_figures": "3 layout checks, with no measured performance data",
    "planned_jobs": 2520,
    "small_pauli_cases": 256,
    "small_pauli_max_error": 0,
    "status": "passed",
    "tfim_dense_comparisons": 16,
    "tfim_max_error": 1.0658141036401503e-14
   },
   "local_numpy_harness_checks": {
    "checked_paths": [
     "vqc / statevector",
     "vqc / native_readout",
     "qsvm",
     "qkpca",
     "vqr / statevector",
     "vqr / native_readout",
     "qkrr",
     "gradient / statevector",
     "maxcut / statevector",
     "vqe / statevector",
     "QAOA real features + ancillas / statevector",
     "gradient / native_readout",
     "maxcut / native_readout",
     "vqe / native_readout",
     "QAOA real features + ancillas / native_readout",
     "chunked circuit exports"
    ],
    "execution_scope": "small NumPy-reference harness only; external framework/native campaign not run",
    "status": "passed"
   },
   "local_pending_report_checks": {
    "exact_condition_figures": 84,
    "measured_jobs": 0,
    "pending_jobs": 2520,
    "scope": "isolated pending-only reporting QA; no campaign gates or native results created",
    "status": "passed"
   },
   "new_ram_figures": [
    "ram_framework_overview",
    "ram_task_statevector",
    "ram_task_native_readout"
   ],
   "profile": "requested_grid",
   "progress_display": {
    "cache_or_scientific_code_changed": false,
    "denominator": "planned jobs in the active campaign, reconciled with the controller announcement",
    "fields": [
     "finished",
     "total",
     "percentage",
     "successful",
     "failed",
     "remaining",
     "per_task"
    ],
    "local_checks": {
     "checks": [
      "Live per-job counts before section snapshots; final 6/6, 4 successful and 2 failed; no double counting",
      "Per-task totals and percentages match the preview plan",
      "Old results, different manifests, incomplete JSON and workers without a confirmed exit are excluded",
      "Underscore task names and repeated cached rows remain correctly counted",
      "Cached successes count when accepted by the current controller",
      "Early process failure stays at 2/6 (33.3%) and raises the original command error",
      "Preparation commands have no invented job-completion percentage",
      "Command timeout stops the owned subprocess and preserves error handling"
     ],
     "driver_code_changed": false,
     "experiment_settings_changed": false,
     "helper_sha256": "80592ed18baee27a8d9b658b378e99f8f62ceab38730266bdde5b013de4d4f4e",
     "scope": "local progress/checkpoint fixtures only; no native framework campaign executed",
     "status": "passed"
    },
    "refresh_seconds": 5,
    "source": "controller-confirmed raw results and current campaign section checkpoints"
   },
   "quantum_qubits": [
    4,
    8,
    12,
    16,
    20,
    24
   ],
   "ram_metrics": [
    "worker_peak_rss_mib",
    "primary_stage_peak_rss_mib",
    "worker_entry_rss_mib",
    "worker_exit_rss_mib",
    "worker_rss_change_mib"
   ],
   "ram_report_tables": [
    "ram_per_job",
    "ram_backend_checks",
    "ram_by_condition",
    "ram_by_framework_task",
    "ram_framework_summary",
    "ram_paired_comparisons"
   ],
   "requested_max_jobs": 4000,
   "requested_max_statebank_mib": 512,
   "revision": "requested_grid_24q_v8",
   "sample_caps": null,
   "static_jobs_by_task": {
    "circuit": 528,
    "classical": 126,
    "gradient": 96,
    "maxcut": 192,
    "qaoa_fs": 192,
    "qkpca": 240,
    "qkrr": 204,
    "qsvm": 510,
    "vqc": 240,
    "vqe": 96,
    "vqr": 96
   },
   "static_planned_benchmark_jobs": 2520,
   "test_ratio": 0.2,
   "train_ratio": 0.8,
   "unsupported_feature_selection": [],
   "uses_all_dataset_rows": true,
   "variational_full_batch": true,
   "variational_iterations": 5,
   "variational_qubits": [
    4,
    8,
    12
   ]
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
