{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a1b2c3d4",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Kompilierungsmethoden für Hamilton-Simulationsschaltungen\"\n",
        "description: \"Vergleich der Kompilierungsmethoden SABRE, des KI-gestützten Transpilers und Rustiq anhand von Hamilton-Simulationsschaltungen aus Hamlib.\"\n",
        "---\n",
        "\n",
        "<span id=\"compilation-methods-for-hamiltonian-simulation-circuits\" />\n",
        "\n",
        "# Kompilierungsmethoden für Hamilton-Simulationsschaltungen\n",
        "\n",
        "*Geschätzte Laufzeit: unter 1 Minute auf einem „ IBM “-Heron-Prozessor (HINWEIS: Dies ist lediglich eine Schätzung. (Die Laufzeit kann variieren.)*\n",
        "\n",
        "{/* cspell:ignore Rustiq, nshuffles, edgecolors, edgecolor, Hamlib, Benchpress, Brugiere, Goubault, Martiel, Dubal, Lishman, Ivrii, fontweight, fontsize, textprops, wedgeprops, startangle, autopct, Hellinger, iloc, ylabel, frameon, ylims, CMHSC */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b1c2d3e4",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Lernziele\n",
        "\n",
        "* So verwenden Sie den Qiskit-Transpiler mit SABRE zur Layout- und Routing-Optimierung\n",
        "* So nutzen Sie den KI-gestützten Transpiler für eine fortgeschrittene Schaltungsoptimierung\n",
        "* Anleitung zur Verwendung des Rustiq-Plugins zur Synthese `PauliEvolutionGate` von Operationen in Hamilton-Simulationsschaltungen\n",
        "* Wie man Kompilierungsmethoden anhand der Zwei-Qubit-Tiefe, der Gesamtanzahl der Gatter und der Laufzeit bewertet und vergleicht\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Voraussetzungen\n",
        "\n",
        "* [Konzepte der Transpilation](/docs/guides/transpile)\n",
        "* [Transpiler-Phasen](/docs/guides/transpiler-stages)\n",
        "* [Transpilieren mit Pass-Managern](/docs/guides/transpile-with-pass-managers)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c1d2e3f4",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Hintergrund\n",
        "\n",
        "Bei der Kompilierung von Quantenschaltungen wird ein hochstufiger Quantenalgorithmus in eine physikalische Schaltung umgewandelt, die den Einschränkungen der Zielhardware Rechnung trägt. Eine effektive Kompilierung kann die Schaltungstiefe und die Gate-Anzahl erheblich reduzieren, was sich in beiden Fällen direkt auf die Qualität der Ergebnisse bei Quantencomputern der nahen Zukunft auswirkt.\n",
        "\n",
        "In diesem Tutorial werden drei Kompilierungsmethoden anhand von Hamilton-Simulationsschaltungen verglichen, die mit `PauliEvolutionGate`… erstellt wurden. Diese Schaltungen modellieren paarweise Qubit-Wechselwirkungen (wie beispielsweise die Terme „ $ZZ$ “, „ $XX$ “ und „ $YY$ “) und kommen häufig in der Quantenchemie, der Festkörperphysik und der Materialwissenschaft zum Einsatz.\n",
        "\n",
        "Die Benchmark-Schaltungen stammen aus der [Hamlib](https://github.com/SRI-International/QC-App-Oriented-Benchmarks/tree/master/qedcbench/hamlib#hamlib-simulation---benchmark-program) -Sammlung, auf die über das [Benchpress](https://github.com/Qiskit/benchpress) -Repository zugegriffen werden kann. Hamlib stellt eine standardisierte Sammlung repräsentativer Hamilton-Operatoren bereit, wodurch sich Kompilierungsstrategien anhand realistischer Simulations-Workloads vergleichen lassen.\n",
        "\n",
        "<span id=\"compilation-methods-overview\" />\n",
        "\n",
        "### Übersicht über die Kompilierungsmethoden\n",
        "\n",
        "<span id=\"qiskit-transpiler-with-sabre\" />\n",
        "\n",
        "#### Qiskit-Transpiler mit SABRE\n",
        "\n",
        "Der Qiskit-Transpiler nutzt den SABRE-Algorithmus (SWAP-basierte heuristische Suche nach dem Prinzip „ BidiREctional “) zur Optimierung des Schaltungslayouts und des Routings. SABRE konzentriert sich darauf, die Anzahl der SWAP-Gates und deren Auswirkungen auf die Schaltungstiefe zu minimieren, wobei die Einschränkungen hinsichtlich der Hardware-Konnektivität berücksichtigt werden. Es handelt sich um eine universell einsetzbare Methode, die ein gutes Gleichgewicht zwischen Leistung und Kompilierungszeit bietet. Weitere Einzelheiten finden Sie unter [\\[1\\]](https://arxiv.org/abs/2409.08368). Die Vorteile und die Erkundung der Parameter von SABRE werden in einem separaten [Tutorial](/docs/tutorials/transpilation-optimizations-with-sabre) ausführlich behandelt.\n",
        "\n",
        "<span id=\"ai-powered-transpiler\" />\n",
        "\n",
        "#### KI-gestützter Transpiler\n",
        "\n",
        "Der KI-gestützte Transpiler nutzt maschinelles Lernen, um durch die Analyse von Mustern in der Schaltungsstruktur und von Hardware-Einschränkungen optimale Transpilierungsstrategien vorherzusagen. Außerdem kann es den `AIPauliNetworkSynthesis` „Pass“ anwenden, der mithilfe eines auf verstärkendem Lernen basierenden Syntheseansatzes auf Schaltkreise im Pauli-Netzwerk abzielt. Weitere Informationen finden Sie unter [\\[2\\]](https://arxiv.org/abs/2405.13196) und [\\[3\\]](https://arxiv.org/abs/2503.14448).\n",
        "\n",
        "<span id=\"rustiq-plugin\" />\n",
        "\n",
        "#### Rustiq-Plugin\n",
        "\n",
        "Das Rustiq-Plugin bietet fortschrittliche Synthesetechniken speziell für `PauliEvolutionGate` Operationen, die Pauli-Rotationen darstellen, wie sie in der Trotter-Dynamik häufig verwendet werden. Es wurde entwickelt, um Schaltkreisdekompositionen mit geringer Tiefe für Hamilton-Simulations-Workloads zu erzeugen. Weitere Einzelheiten finden Sie in [\\[4\\]](https://arxiv.org/abs/2404.03280).\n",
        "\n",
        "<span id=\"key-metrics\" />\n",
        "\n",
        "### Schlüsselmetriken\n",
        "\n",
        "Wir vergleichen die drei Methoden anhand der folgenden Kennzahlen:\n",
        "\n",
        "* **Zwei-Qubit-Tiefe** : Die Tiefe der Schaltung, wobei nur Zwei-Qubit-Gatter gezählt werden. Dies ist oft der Engpass, der die Wiedergabetreue auf echter Hardware beeinträchtigt.\n",
        "* **Schaltungsgröße (Gesamtanzahl der Gatter)** : Die Gesamtzahl der Gatter in der transpilierten Schaltung.\n",
        "* **Laufzeit** : Die tatsächliche Dauer der Transpilation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d1e2f3a4",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Anforderungen\n",
        "\n",
        "Bevor Sie mit diesem Tutorial beginnen, sollten Sie sicherstellen, dass Sie Folgendes installiert haben:\n",
        "\n",
        "* Qiskit SDK v2.0 oder höher, mit [Visual](/docs/api/qiskit/visualization) isierungsunterstützung\n",
        "* Qiskit Runtime v0.22 oder später (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer (`pip install qiskit-aer`)\n",
        "* Qiskit IBM Transpiler (`pip install qiskit-ibm-transpiler`)\n",
        "* Qiskit AI Transpiler lokaler Modus (`pip install qiskit_ibm_ai_local_transpiler`)\n",
        "* Networkx (`pip install networkx`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1f2a3b4",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Einrichtung\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "f1a2b3c4",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit.circuit.library import PauliEvolutionGate\n",
        "from qiskit_ibm_transpiler import generate_ai_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel, depolarizing_error\n",
        "from collections import Counter\n",
        "from statistics import mean, stdev\n",
        "from scipy.sparse import SparseEfficiencyWarning\n",
        "import time\n",
        "import warnings\n",
        "import matplotlib.pyplot as plt\n",
        "import matplotlib.ticker as ticker\n",
        "import numpy as np\n",
        "import json\n",
        "import requests\n",
        "import logging\n",
        "\n",
        "# Suppress noisy loggers and warnings\n",
        "logging.getLogger(\n",
        "    \"qiskit_ibm_transpiler.wrappers.ai_local_synthesis\"\n",
        ").setLevel(logging.ERROR)\n",
        "warnings.filterwarnings(\"ignore\", category=FutureWarning)\n",
        "warnings.filterwarnings(\"ignore\", category=SparseEfficiencyWarning)\n",
        "\n",
        "seed = 42  # Seed for reproducibility"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a2b3c4d5",
      "metadata": {},
      "source": [
        "<span id=\"connect-to-a-backend\" />\n",
        "\n",
        "### Mit einem Backend verbinden\n",
        "\n",
        "Wählen Sie ein Backend aus, das sowohl für die Beispiele im kleinen als auch im großen Maßstab verwendet werden soll. Das Backend legt die Kopplungskarte und die Basisgatter fest, auf die der Transpiler abzielt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b2c3d4e5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Using backend: ibm_pittsburgh\n"
          ]
        }
      ],
      "source": [
        "# QiskitRuntimeService.save_account(channel=\"ibm_quantum_platform\",\n",
        "# token=\"<YOUR-API-KEY>\", overwrite=True, set_as_default=True)\n",
        "service = QiskitRuntimeService(channel=\"ibm_quantum_platform\")\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "print(f\"Using backend: {backend.name}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c2d3e4f5",
      "metadata": {},
      "source": [
        "<span id=\"define-pass-managers\" />\n",
        "\n",
        "### Pass-Manager definieren\n",
        "\n",
        "Richten Sie die drei Kompilierungsmethoden ein.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "d2e3f4a5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# SABRE pass manager (Qiskit default at optimization level 3)\n",
        "pm_sabre = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=backend, seed_transpiler=seed\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "e2f3a4b5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "e14d6bb64d3e4a399a645a5437a4a1cb",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "Fetching 127 files:   0%|          | 0/127 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# AI transpiler pass manager (local mode)\n",
        "pm_ai = generate_ai_pass_manager(\n",
        "    backend=backend, optimization_level=3, ai_optimization_level=3\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "f2a3b4c5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Rustiq pass manager for PauliEvolutionGate synthesis\n",
        "hls_config = HLSConfig(\n",
        "    PauliEvolution=[\n",
        "        (\n",
        "            \"rustiq\",\n",
        "            {\n",
        "                \"nshuffles\": 400,\n",
        "                \"upto_phase\": True,\n",
        "                \"fix_clifford\": True,\n",
        "                \"preserve_order\": False,\n",
        "                \"metric\": \"depth\",\n",
        "            },\n",
        "        )\n",
        "    ]\n",
        ")\n",
        "pm_rustiq = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    hls_config=hls_config,\n",
        "    seed_transpiler=seed,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a3b4c5d6",
      "metadata": {},
      "source": [
        "<span id=\"define-helper-functions\" />\n",
        "\n",
        "### Hilfsfunktionen definieren\n",
        "\n",
        "Die folgende Funktion transpiliert eine Liste von Schaltkreisen unter Verwendung eines vorgegebenen Pass-Managers und erfasst für jeden Schaltkreis die wichtigsten Kennzahlen (Zwei-Qubit-Tiefe, Schaltkreisgröße und Laufzeit).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "b3c4d5e6",
      "metadata": {},
      "outputs": [],
      "source": [
        "def capture_transpilation_metrics(\n",
        "    results, pass_manager, circuits, method_name\n",
        "):\n",
        "    \"\"\"\n",
        "    Transpile circuits and append one metrics record per circuit to\n",
        "    ``results``.\n",
        "\n",
        "    Args:\n",
        "        results (list): List of dicts to append the metrics records to.\n",
        "        pass_manager: Pass manager used for transpilation.\n",
        "        circuits (list): List of quantum circuits to transpile.\n",
        "        method_name (str): Name of the transpilation method.\n",
        "\n",
        "    Returns:\n",
        "        list: List of transpiled circuits.\n",
        "    \"\"\"\n",
        "    transpiled_circuits = []\n",
        "\n",
        "    for i, qc in enumerate(circuits):\n",
        "        start_time = time.time()\n",
        "        transpiled_qc = pass_manager.run(qc)\n",
        "        end_time = time.time()\n",
        "\n",
        "        # Decompose swaps for consistency across methods\n",
        "        transpiled_qc = transpiled_qc.decompose(gates_to_decompose=[\"swap\"])\n",
        "\n",
        "        transpilation_time = end_time - start_time\n",
        "        two_qubit_depth = transpiled_qc.depth(\n",
        "            lambda x: x.operation.num_qubits == 2\n",
        "        )\n",
        "        circuit_size = transpiled_qc.size()\n",
        "\n",
        "        results.append(\n",
        "            {\n",
        "                \"method\": method_name,\n",
        "                \"qc_name\": qc.name,\n",
        "                \"qc_index\": i,\n",
        "                \"num_qubits\": qc.num_qubits,\n",
        "                \"two_qubit_depth\": two_qubit_depth,\n",
        "                \"size\": circuit_size,\n",
        "                \"runtime\": transpilation_time,\n",
        "            }\n",
        "        )\n",
        "        transpiled_circuits.append(transpiled_qc)\n",
        "        print(\n",
        "            f\"[{method_name}] Circuit {i} ({qc.name}): \"\n",
        "            f\"2Q depth={two_qubit_depth}, size={circuit_size}, \"\n",
        "            f\"time={transpilation_time:.2f}s\"\n",
        "        )\n",
        "\n",
        "    return transpiled_circuits"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "summary_table_fn",
      "metadata": {},
      "outputs": [],
      "source": [
        "def _method_order(results):\n",
        "    \"\"\"Return the distinct method names in their first-seen order.\"\"\"\n",
        "    order = []\n",
        "    for r in results:\n",
        "        if r[\"method\"] not in order:\n",
        "            order.append(r[\"method\"])\n",
        "    return order\n",
        "\n",
        "\n",
        "def print_summary_table(results):\n",
        "    \"\"\"\n",
        "    Print the mean and standard deviation of each metric per compilation\n",
        "    method, followed by the mean percent improvement relative to SABRE.\n",
        "    \"\"\"\n",
        "    metrics = [\n",
        "        (\"two_qubit_depth\", \"2Q Depth\"),\n",
        "        (\"size\", \"Gate Count\"),\n",
        "        (\"runtime\", \"Runtime (s)\"),\n",
        "    ]\n",
        "    methods = _method_order(results)\n",
        "    by_method = {m: [r for r in results if r[\"method\"] == m] for m in methods}\n",
        "    sabre_by_index = {r[\"qc_index\"]: r for r in by_method.get(\"SABRE\", [])}\n",
        "\n",
        "    col_w = 22\n",
        "    name_w = max(len(m) for m in methods)\n",
        "    header = f\"{'Method':<{name_w}}\" + \"\".join(\n",
        "        f\"  {label:>{col_w}}\" for _, label in metrics\n",
        "    )\n",
        "\n",
        "    print(\"Mean +/- std per compilation method\")\n",
        "    print(header)\n",
        "    print(\"-\" * len(header))\n",
        "    for method in methods:\n",
        "        cells = []\n",
        "        for key, _ in metrics:\n",
        "            values = [r[key] for r in by_method[method]]\n",
        "            std = stdev(values) if len(values) > 1 else 0.0\n",
        "            cells.append(f\"{mean(values):,.1f} +/- {std:,.1f}\")\n",
        "        print(\n",
        "            f\"{method:<{name_w}}\" + \"\".join(f\"  {c:>{col_w}}\" for c in cells)\n",
        "        )\n",
        "\n",
        "    others = [m for m in methods if m != \"SABRE\"]\n",
        "    if others and sabre_by_index:\n",
        "        print()\n",
        "        print(\"Mean % improvement vs SABRE (positive = better than SABRE)\")\n",
        "        print(header)\n",
        "        print(\"-\" * len(header))\n",
        "        for method in others:\n",
        "            cells = []\n",
        "            for key, _ in metrics:\n",
        "                pct = [\n",
        "                    (sabre_by_index[r[\"qc_index\"]][key] - r[key])\n",
        "                    / sabre_by_index[r[\"qc_index\"]][key]\n",
        "                    * 100\n",
        "                    for r in by_method[method]\n",
        "                    if sabre_by_index.get(r[\"qc_index\"])\n",
        "                    and sabre_by_index[r[\"qc_index\"]][key]\n",
        "                ]\n",
        "                if pct:\n",
        "                    std = stdev(pct) if len(pct) > 1 else 0.0\n",
        "                    cells.append(f\"{mean(pct):+.1f}% +/- {std:.1f}%\")\n",
        "                else:\n",
        "                    cells.append(\"n/a\")\n",
        "            print(\n",
        "                f\"{method:<{name_w}}\"\n",
        "                + \"\".join(f\"  {c:>{col_w}}\" for c in cells)\n",
        "            )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "per_circuit_table_fn",
      "metadata": {},
      "outputs": [],
      "source": [
        "def print_per_circuit_comparison(results, num_rows=5):\n",
        "    \"\"\"\n",
        "    Print a per-metric comparison of the compilation methods for the\n",
        "    first ``num_rows`` circuits (sorted by qubit count). The best\n",
        "    (lowest) value for each metric is marked with an asterisk.\n",
        "    \"\"\"\n",
        "    metrics = [\n",
        "        (\"two_qubit_depth\", \"2Q Depth\"),\n",
        "        (\"size\", \"Gate Count\"),\n",
        "        (\"runtime\", \"Runtime (s)\"),\n",
        "    ]\n",
        "    methods = _method_order(results)\n",
        "\n",
        "    by_index = {}\n",
        "    for r in results:\n",
        "        by_index.setdefault(r[\"qc_index\"], {})[r[\"method\"]] = r\n",
        "    ordered = sorted(\n",
        "        by_index.items(),\n",
        "        key=lambda kv: (next(iter(kv[1].values()))[\"num_qubits\"], kv[0]),\n",
        "    )[:num_rows]\n",
        "\n",
        "    for key, label in metrics:\n",
        "        print(f\"{label} (first {num_rows} circuits by qubit count); * = best\")\n",
        "        header = f\"{'Idx':>3}  {'Circuit':<16} {'Q':>3}\" + \"\".join(\n",
        "            f\"{m:>9}\" for m in methods\n",
        "        )\n",
        "        print(header)\n",
        "        print(\"-\" * len(header))\n",
        "        for idx, method_map in ordered:\n",
        "            any_record = next(iter(method_map.values()))\n",
        "            present = {\n",
        "                m: method_map[m][key] for m in methods if m in method_map\n",
        "            }\n",
        "            best = min(present.values())\n",
        "            line = (\n",
        "                f\"{idx:>3}  {any_record['qc_name'][:16]:<16} \"\n",
        "                f\"{any_record['num_qubits']:>3}\"\n",
        "            )\n",
        "            for m in methods:\n",
        "                value = method_map[m][key]\n",
        "                text = f\"{value:.2f}\" if key == \"runtime\" else f\"{int(value)}\"\n",
        "                if value == best:\n",
        "                    text += \"*\"\n",
        "                line += f\"{text:>9}\"\n",
        "            print(line)\n",
        "        print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c3d4e5f6",
      "metadata": {},
      "source": [
        "<span id=\"load-hamiltonian-circuits-from-hamlib\" />\n",
        "\n",
        "### Hamilton-Schaltkreise aus Hamlib laden\n",
        "\n",
        "Wir laden eine repräsentative Auswahl von Hamilton-Operatoren aus dem „Benchpress“-Repository und konstruieren `PauliEvolutionGate` Schaltkreise. Schaltkreise, deren Qubit-Anzahl die des Backends übersteigt, werden entfernt, ebenso wie Schaltkreise, deren zerlegte Größe 1.500 Gatter überschreitet (um die Transpilierungszeiten in einem vertretbaren Rahmen zu halten).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "d3e4f5a6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total Hamiltonian circuits loaded: 42\n",
            "Qubit range: 2 to 112\n"
          ]
        }
      ],
      "source": [
        "# Obtain the Hamiltonian JSON from the benchpress repository\n",
        "url = (\n",
        "    \"https://raw.githubusercontent.com/Qiskit/benchpress/\"\n",
        "    \"e7b29ef7be4cc0d70237b8fdc03edbd698908eff/\"\n",
        "    \"benchpress/hamiltonian/hamlib/100_representative.json\"\n",
        ")\n",
        "response = requests.get(url)\n",
        "response.raise_for_status()\n",
        "ham_records = json.loads(response.text)\n",
        "\n",
        "# Remove circuits that are too large for the backend\n",
        "ham_records = [\n",
        "    h for h in ham_records if h[\"ham_qubits\"] <= backend.num_qubits\n",
        "]\n",
        "\n",
        "# Build PauliEvolutionGate circuits\n",
        "qc_ham_list = []\n",
        "for h in ham_records:\n",
        "    terms = h[\"ham_hamlib_hamiltonian_terms\"]\n",
        "    coeff = h[\"ham_hamlib_hamiltonian_coefficients\"]\n",
        "    num_qubits = h[\"ham_qubits\"]\n",
        "    name = h[\"ham_problem\"]\n",
        "\n",
        "    evo_gate = PauliEvolutionGate(SparsePauliOp(terms, coeff))\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    qc.name = name\n",
        "    qc.append(evo_gate, range(num_qubits))\n",
        "    qc_ham_list.append(qc)\n",
        "\n",
        "# Remove circuits whose decomposed size exceeds 1500 gates so that\n",
        "# transpilation completes in a reasonable time frame\n",
        "qc_ham_list = [qc for qc in qc_ham_list if qc.decompose().size() <= 1500]\n",
        "\n",
        "print(f\"Total Hamiltonian circuits loaded: {len(qc_ham_list)}\")\n",
        "min_qubits = min(qc.num_qubits for qc in qc_ham_list)\n",
        "max_qubits = max(qc.num_qubits for qc in qc_ham_list)\n",
        "print(f\"Qubit range: {min_qubits} to {max_qubits}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3f4a5b6",
      "metadata": {},
      "source": [
        "Unterteilen Sie die Schaltkreise in kleine (weniger als 20 Qubits) und große (20 oder mehr Qubits) Gruppen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "f3a4b5c6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Small-scale circuits (<20 qubits): 20\n",
            "Large-scale circuits (>=20 qubits): 22\n"
          ]
        }
      ],
      "source": [
        "qc_small = [qc for qc in qc_ham_list if qc.num_qubits < 20]\n",
        "qc_large = [qc for qc in qc_ham_list if qc.num_qubits >= 20]\n",
        "\n",
        "print(f\"Small-scale circuits (<20 qubits): {len(qc_small)}\")\n",
        "print(f\"Large-scale circuits (>=20 qubits): {len(qc_large)}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4b5c6d7",
      "metadata": {},
      "source": [
        "Vorschau auf eine der kleinen Hamilton-Schaltungen vor der Transpilierung.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "b4c5d6e7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/b4c5d6e7-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# We decompose the circuit here, otherwise it would just be a PauliEvolutionGate box,\n",
        "# which isn't very informative to look at!\n",
        "qc_small[0].decompose().draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-small-scale",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-example\" />\n",
        "\n",
        "## Beispiel im kleinen Maßstab\n",
        "\n",
        "In diesem Abschnitt führen wir einen Vergleich der drei Kompilierungsmethoden anhand von Hamilton-Schaltkreisen mit weniger als 20 Qubits durch. Diese Schaltungen lassen sich schnell transpilieren und vermitteln einen klaren Überblick darüber, wie die einzelnen Methoden mit Schaltungen mittlerer Komplexität umgehen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4d5e6f7",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Schritt 1: Klassische Eingaben einem Quantenproblem zuordnen\n",
        "\n",
        "Jeder Hamilton-Operator wird als Schaltkreis `PauliEvolutionGate` kodiert. Die Schaltungen wurden bereits im Abschnitt „Setup“ anhand der Hamlib-Benchmark-Daten erstellt.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d4e5f6a7",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Schritt 2: Optimierung des Problems für die Ausführung auf Quantenhardware\n",
        "\n",
        "Wir transpilieren alle kleinen Schaltkreise unter Verwendung der drei Pass-Manager und erfassen anschließend die Metriken.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "e4f5a6b7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[SABRE] Circuit 0 (all-vib-bh): 2Q depth=3, size=30, time=2.09s\n",
            "[SABRE] Circuit 1 (all-vib-c2h): 2Q depth=18, size=111, time=0.01s\n",
            "[SABRE] Circuit 2 (all-vib-o3): 2Q depth=6, size=58, time=0.00s\n",
            "[SABRE] Circuit 3 (all-vib-c2h): 2Q depth=2, size=37, time=0.01s\n",
            "[SABRE] Circuit 4 (graph-gnp_k-2): 2Q depth=24, size=126, time=0.01s\n",
            "[SABRE] Circuit 5 (LiH): 2Q depth=66, size=285, time=0.01s\n",
            "[SABRE] Circuit 6 (all-vib-fccf): 2Q depth=66, size=339, time=0.01s\n",
            "[SABRE] Circuit 7 (all-vib-ch2): 2Q depth=88, size=413, time=0.01s\n",
            "[SABRE] Circuit 8 (all-vib-f2): 2Q depth=180, size=1000, time=0.02s\n",
            "[SABRE] Circuit 9 (all-vib-bhf2): 2Q depth=18, size=223, time=0.03s\n",
            "[SABRE] Circuit 10 (graph-gnp_k-4): 2Q depth=122, size=675, time=0.02s\n",
            "[SABRE] Circuit 11 (Be2): 2Q depth=343, size=1628, time=0.03s\n",
            "[SABRE] Circuit 12 (all-vib-fccf): 2Q depth=14, size=134, time=0.00s\n",
            "[SABRE] Circuit 13 (uf20-ham): 2Q depth=50, size=341, time=0.01s\n",
            "[SABRE] Circuit 14 (TSP_Ncity-4): 2Q depth=118, size=615, time=0.01s\n",
            "[SABRE] Circuit 15 (graph-complete_bipart): 2Q depth=232, size=1420, time=0.03s\n",
            "[SABRE] Circuit 16 (all-vib-cyclo_propene): 2Q depth=18, size=354, time=0.93s\n",
            "[SABRE] Circuit 17 (all-vib-hno): 2Q depth=6, size=174, time=0.14s\n",
            "[SABRE] Circuit 18 (all-vib-fccf): 2Q depth=30, size=286, time=0.01s\n",
            "[SABRE] Circuit 19 (tfim): 2Q depth=31, size=232, time=0.03s\n",
            "[AI] Circuit 0 (all-vib-bh): 2Q depth=3, size=30, time=0.01s\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "cf50b939bf4141bcbc610275a514d6fd",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "Fetching 4 files:   0%|          | 0/4 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[AI] Circuit 1 (all-vib-c2h): 2Q depth=18, size=101, time=0.18s\n",
            "[AI] Circuit 2 (all-vib-o3): 2Q depth=6, size=58, time=0.01s\n",
            "[AI] Circuit 3 (all-vib-c2h): 2Q depth=2, size=37, time=0.01s\n",
            "[AI] Circuit 4 (graph-gnp_k-2): 2Q depth=24, size=133, time=0.07s\n",
            "[AI] Circuit 5 (LiH): 2Q depth=62, size=267, time=8.00s\n",
            "[AI] Circuit 6 (all-vib-fccf): 2Q depth=65, size=300, time=0.18s\n",
            "[AI] Circuit 7 (all-vib-ch2): 2Q depth=79, size=353, time=0.16s\n",
            "[AI] Circuit 8 (all-vib-f2): 2Q depth=176, size=998, time=0.43s\n",
            "[AI] Circuit 9 (all-vib-bhf2): 2Q depth=18, size=194, time=0.11s\n",
            "[AI] Circuit 10 (graph-gnp_k-4): 2Q depth=114, size=668, time=0.18s\n",
            "[AI] Circuit 11 (Be2): 2Q depth=292, size=1382, time=0.88s\n",
            "[AI] Circuit 12 (all-vib-fccf): 2Q depth=14, size=134, time=0.01s\n",
            "[AI] Circuit 13 (uf20-ham): 2Q depth=40, size=330, time=0.16s\n",
            "[AI] Circuit 14 (TSP_Ncity-4): 2Q depth=96, size=600, time=0.29s\n",
            "[AI] Circuit 15 (graph-complete_bipart): 2Q depth=231, size=1531, time=0.46s\n",
            "[AI] Circuit 16 (all-vib-cyclo_propene): 2Q depth=18, size=309, time=0.25s\n",
            "[AI] Circuit 17 (all-vib-hno): 2Q depth=10, size=198, time=0.15s\n",
            "[AI] Circuit 18 (all-vib-fccf): 2Q depth=34, size=402, time=0.02s\n",
            "[AI] Circuit 19 (tfim): 2Q depth=44, size=311, time=0.15s\n",
            "[Rustiq] Circuit 0 (all-vib-bh): 2Q depth=3, size=30, time=0.01s\n",
            "[Rustiq] Circuit 1 (all-vib-c2h): 2Q depth=13, size=69, time=0.00s\n",
            "[Rustiq] Circuit 2 (all-vib-o3): 2Q depth=13, size=82, time=0.01s\n",
            "[Rustiq] Circuit 3 (all-vib-c2h): 2Q depth=2, size=40, time=0.01s\n",
            "[Rustiq] Circuit 4 (graph-gnp_k-2): 2Q depth=31, size=132, time=0.01s\n",
            "[Rustiq] Circuit 5 (LiH): 2Q depth=59, size=285, time=0.01s\n",
            "[Rustiq] Circuit 6 (all-vib-fccf): 2Q depth=34, size=193, time=0.00s\n",
            "[Rustiq] Circuit 7 (all-vib-ch2): 2Q depth=49, size=302, time=0.01s\n",
            "[Rustiq] Circuit 8 (all-vib-f2): 2Q depth=141, size=807, time=0.02s\n",
            "[Rustiq] Circuit 9 (all-vib-bhf2): 2Q depth=13, size=146, time=0.02s\n",
            "[Rustiq] Circuit 10 (graph-gnp_k-4): 2Q depth=129, size=683, time=0.02s\n",
            "[Rustiq] Circuit 11 (Be2): 2Q depth=220, size=1101, time=0.02s\n",
            "[Rustiq] Circuit 12 (all-vib-fccf): 2Q depth=53, size=333, time=0.01s\n",
            "[Rustiq] Circuit 13 (uf20-ham): 2Q depth=63, size=425, time=0.01s\n",
            "[Rustiq] Circuit 14 (TSP_Ncity-4): 2Q depth=123, size=767, time=0.02s\n",
            "[Rustiq] Circuit 15 (graph-complete_bipart): 2Q depth=309, size=2107, time=0.05s\n",
            "[Rustiq] Circuit 16 (all-vib-cyclo_propene): 2Q depth=16, size=283, time=0.32s\n",
            "[Rustiq] Circuit 17 (all-vib-hno): 2Q depth=19, size=291, time=0.32s\n",
            "[Rustiq] Circuit 18 (all-vib-fccf): 2Q depth=44, size=546, time=0.02s\n",
            "[Rustiq] Circuit 19 (tfim): 2Q depth=24, size=416, time=0.01s\n"
          ]
        }
      ],
      "source": [
        "results_small = []\n",
        "\n",
        "tqc_sabre_small = capture_transpilation_metrics(\n",
        "    results_small, pm_sabre, qc_small, \"SABRE\"\n",
        ")\n",
        "tqc_ai_small = capture_transpilation_metrics(\n",
        "    results_small, pm_ai, qc_small, \"AI\"\n",
        ")\n",
        "tqc_rustiq_small = capture_transpilation_metrics(\n",
        "    results_small, pm_rustiq, qc_small, \"Rustiq\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f4a5b6c7",
      "metadata": {},
      "source": [
        "Die folgende Tabelle fasst den Durchschnittswert und die Standardabweichung jeder Kennzahl für alle Kleinschaltungen zusammen und gibt zudem die prozentuale Verbesserung im Vergleich zu SABRE an. Da die Größe der Schaltungen stark variiert, liefert die Standardabweichung wichtige Informationen für die Interpretation der Durchschnittswerte.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "a5b6c7d8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mean +/- std per compilation method\n",
            "Method                2Q Depth              Gate Count             Runtime (s)\n",
            "------------------------------------------------------------------------------\n",
            "SABRE            71.8 +/- 89.6         424.1 +/- 446.0             0.2 +/- 0.5\n",
            "AI               67.3 +/- 80.2         416.8 +/- 426.7             0.6 +/- 1.8\n",
            "Rustiq           67.9 +/- 80.0         451.9 +/- 484.7             0.0 +/- 0.1\n",
            "\n",
            "Mean % improvement vs SABRE (positive = better than SABRE)\n",
            "Method                2Q Depth              Gate Count             Runtime (s)\n",
            "------------------------------------------------------------------------------\n",
            "AI             -2.1% +/- 19.8%         -0.6% +/- 14.7%   -5635.1% +/- 20725.2%\n",
            "Rustiq        -25.3% +/- 85.4%        -16.3% +/- 50.4%         -7.0% +/- 60.6%\n"
          ]
        }
      ],
      "source": [
        "print_summary_table(results_small)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "per_circuit_small_md",
      "metadata": {},
      "source": [
        "Die Tabelle „Pro Schaltung“ zeigt, wie die einzelnen Methoden bei den einzelnen Schaltungen im Vergleich abschneiden. Der beste Wert für jede Kennzahl ist mit einem Sternchen gekennzeichnet. Beachten Sie, dass bei den einfachsten Schaltungen alle drei Methoden oft zum gleichen Ergebnis führen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "per_circuit_small_code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2Q Depth (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-bh         2       3*       3*       3*\n",
            "  1  all-vib-c2h        3       18       18      13*\n",
            "  2  all-vib-o3         4       6*       6*       13\n",
            "  3  all-vib-c2h        4       2*       2*       2*\n",
            "  4  graph-gnp_k-2      4      24*      24*       31\n",
            "  5  LiH                4       66       62      59*\n",
            "  6  all-vib-fccf       4       66       65      34*\n",
            "  7  all-vib-ch2        4       88       79      49*\n",
            "\n",
            "Gate Count (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-bh         2      30*      30*      30*\n",
            "  1  all-vib-c2h        3      111      101      69*\n",
            "  2  all-vib-o3         4      58*      58*       82\n",
            "  3  all-vib-c2h        4      37*      37*       40\n",
            "  4  graph-gnp_k-2      4     126*      133      132\n",
            "  5  LiH                4      285     267*      285\n",
            "  6  all-vib-fccf       4      339      300     193*\n",
            "  7  all-vib-ch2        4      413      353     302*\n",
            "\n",
            "Runtime (s) (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-bh         2     2.09     0.01    0.01*\n",
            "  1  all-vib-c2h        3     0.01     0.18    0.00*\n",
            "  2  all-vib-o3         4    0.00*     0.01     0.01\n",
            "  3  all-vib-c2h        4     0.01     0.01    0.01*\n",
            "  4  graph-gnp_k-2      4    0.01*     0.07     0.01\n",
            "  5  LiH                4    0.01*     8.00     0.01\n",
            "  6  all-vib-fccf       4     0.01     0.18    0.00*\n",
            "  7  all-vib-ch2        4     0.01     0.16    0.01*\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print_per_circuit_comparison(results_small, num_rows=8)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b5c6d7e8",
      "metadata": {},
      "source": [
        "<span id=\"visualize-results\" />\n",
        "\n",
        "#### Ergebnisse visualisieren\n",
        "\n",
        "Die folgenden Diagramme vergleichen die drei Methoden anhand der einzelnen Kennzahlen auf Schaltkreisebene. Die Schaltkreise sind nach der Anzahl der Qubits sortiert und auf der x-Achse mit einem Index gekennzeichnet, da mehrere Schaltkreise dieselbe Anzahl an Qubits aufweisen können.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "c5d6e7f8",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_transpilation_comparison(results, title_prefix):\n",
        "    \"\"\"\n",
        "    Create a three-panel figure comparing compilation methods on\n",
        "    two-qubit depth, circuit size, and runtime.\n",
        "\n",
        "    Circuits are sorted by qubit count and plotted by circuit index.\n",
        "    \"\"\"\n",
        "    methods = _method_order(results)\n",
        "    palette = {\"SABRE\": \"#1f77b4\", \"AI\": \"#ff7f0e\", \"Rustiq\": \"#2ca02c\"}\n",
        "    markers = {\"SABRE\": \"o\", \"AI\": \"^\", \"Rustiq\": \"s\"}\n",
        "\n",
        "    # Order circuits by qubit count (then index) and map to plot positions\n",
        "    ref = sorted(\n",
        "        [r for r in results if r[\"method\"] == methods[0]],\n",
        "        key=lambda r: (r[\"num_qubits\"], r[\"qc_index\"]),\n",
        "    )\n",
        "    pos_map = {r[\"qc_index\"]: pos for pos, r in enumerate(ref)}\n",
        "    tick_positions = [pos_map[r[\"qc_index\"]] for r in ref]\n",
        "    tick_labels = [\n",
        "        f\"{pos_map[r['qc_index']]} ({r['num_qubits']}q)\" for r in ref\n",
        "    ]\n",
        "\n",
        "    metrics = [\n",
        "        (\"two_qubit_depth\", \"Two-Qubit Depth\"),\n",
        "        (\"size\", \"Total Gate Count (Circuit Size)\"),\n",
        "        (\"runtime\", \"Transpilation Runtime (s)\"),\n",
        "    ]\n",
        "\n",
        "    fig, axes = plt.subplots(1, 3, figsize=(20, 5.5))\n",
        "    fig.suptitle(title_prefix, fontsize=15, fontweight=\"bold\", y=1.02)\n",
        "\n",
        "    for ax, (metric, ylabel) in zip(axes, metrics):\n",
        "        for method in methods:\n",
        "            subset = sorted(\n",
        "                [r for r in results if r[\"method\"] == method],\n",
        "                key=lambda r: pos_map[r[\"qc_index\"]],\n",
        "            )\n",
        "            ax.plot(\n",
        "                [pos_map[r[\"qc_index\"]] for r in subset],\n",
        "                [r[metric] for r in subset],\n",
        "                marker=markers.get(method, \"o\"),\n",
        "                label=method,\n",
        "                color=palette.get(method, None),\n",
        "                linewidth=1.5,\n",
        "                markersize=6,\n",
        "                alpha=0.85,\n",
        "            )\n",
        "        ax.set_xlabel(\"Circuit Index (num qubits)\", fontsize=11)\n",
        "        ax.set_ylabel(ylabel, fontsize=11)\n",
        "        ax.legend(frameon=True, fontsize=9)\n",
        "        ax.grid(True, linestyle=\"--\", alpha=0.4)\n",
        "        step = max(1, len(tick_positions) // 15)\n",
        "        ax.set_xticks(tick_positions[::step])\n",
        "        ax.set_xticklabels(\n",
        "            [tick_labels[i] for i in range(0, len(tick_labels), step)],\n",
        "            fontsize=7,\n",
        "            rotation=45,\n",
        "            ha=\"right\",\n",
        "        )\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "pct_improvement_plot_fn",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_pct_improvement_vs_sabre(results, title_prefix):\n",
        "    \"\"\"\n",
        "    Plot the per-circuit percent improvement of each non-SABRE method\n",
        "    relative to SABRE, for each metric. A positive value means the\n",
        "    method improved on SABRE; negative means SABRE was better.\n",
        "    \"\"\"\n",
        "    metrics = [\n",
        "        (\"two_qubit_depth\", \"2Q Depth\"),\n",
        "        (\"size\", \"Gate Count\"),\n",
        "        (\"runtime\", \"Runtime\"),\n",
        "    ]\n",
        "    palette = {\"AI\": \"#ff7f0e\", \"Rustiq\": \"#2ca02c\"}\n",
        "    markers = {\"AI\": \"^\", \"Rustiq\": \"s\"}\n",
        "\n",
        "    methods = _method_order(results)\n",
        "    sabre = sorted(\n",
        "        [r for r in results if r[\"method\"] == \"SABRE\"],\n",
        "        key=lambda r: (r[\"num_qubits\"], r[\"qc_index\"]),\n",
        "    )\n",
        "    other_methods = [m for m in methods if m != \"SABRE\"]\n",
        "\n",
        "    tick_positions = list(range(len(sabre)))\n",
        "    tick_labels = [\n",
        "        f\"{i} ({sabre[i]['num_qubits']}q)\" for i in range(len(sabre))\n",
        "    ]\n",
        "\n",
        "    fig, axes = plt.subplots(1, 3, figsize=(20, 5.5))\n",
        "    fig.suptitle(\n",
        "        f\"{title_prefix}: % Improvement over SABRE\",\n",
        "        fontsize=15,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "\n",
        "    for ax, (metric, label) in zip(axes, metrics):\n",
        "        ax.axhline(0, color=\"#1f77b4\", linewidth=2, label=\"SABRE (baseline)\")\n",
        "        for method in other_methods:\n",
        "            data = sorted(\n",
        "                [r for r in results if r[\"method\"] == method],\n",
        "                key=lambda r: (r[\"num_qubits\"], r[\"qc_index\"]),\n",
        "            )\n",
        "            pct = [\n",
        "                (sabre[i][metric] - data[i][metric]) / sabre[i][metric] * 100\n",
        "                for i in range(len(sabre))\n",
        "            ]\n",
        "            ax.plot(\n",
        "                tick_positions,\n",
        "                pct,\n",
        "                marker=markers.get(method, \"o\"),\n",
        "                label=method,\n",
        "                color=palette.get(method, None),\n",
        "                linewidth=1.5,\n",
        "                markersize=6,\n",
        "                alpha=0.85,\n",
        "            )\n",
        "        ax.set_xlabel(\"Circuit Index (num qubits)\", fontsize=11)\n",
        "        ax.set_ylabel(f\"% Improvement ({label})\", fontsize=11)\n",
        "        ax.legend(frameon=True, fontsize=9)\n",
        "        ax.grid(True, linestyle=\"--\", alpha=0.4)\n",
        "        step = max(1, len(tick_positions) // 15)\n",
        "        ax.set_xticks(tick_positions[::step])\n",
        "        ax.set_xticklabels(\n",
        "            [tick_labels[i] for i in range(0, len(tick_labels), step)],\n",
        "            fontsize=7,\n",
        "            rotation=45,\n",
        "            ha=\"right\",\n",
        "        )\n",
        "        ylims = ax.get_ylim()\n",
        "        ax.axhspan(0, max(ylims[1], 1), alpha=0.04, color=\"green\")\n",
        "        ax.axhspan(min(ylims[0], -1), 0, alpha=0.04, color=\"red\")\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "d5e6f7a8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/d5e6f7a8-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_transpilation_comparison(\n",
        "    results_small,\n",
        "    \"Small-Scale Hamiltonian Circuits: Compilation Comparison\",\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "pct_improvement_small",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/pct_improvement_small-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_pct_improvement_vs_sabre(\n",
        "    results_small,\n",
        "    \"Small-Scale Hamiltonian Circuits\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d2a29d04",
      "metadata": {},
      "source": [
        "In diesem Maßstab schneiden alle drei Passmanager gut ab, und ihre durchschnittlichen Ergebnisse liegen nahe beieinander. Dies liegt vor allem daran, dass kleine Schaltungen nur begrenzten Spielraum für weitere Optimierungen bieten, sodass die Methoden tendenziell zu ähnlichen Lösungen konvergieren.\n",
        "\n",
        "In diesem Beispiel liefert Rustiq die unterschiedlichsten Ergebnisse, wobei sowohl bei der Zwei-Qubit-Tiefe als auch bei der Gatteranzahl die größten Ausreißer zu verzeichnen sind. Diese Variabilität führt zwar dazu, dass Rustiq manchmal hinterherhinkt, bedeutet aber auch, dass Rustiq gelegentlich bessere Lösungen findet als die beiden anderen Methoden. Der KI-Transpiler liefert im Vergleich zu SABRE und Rustiq stabilere Ergebnisse und liegt auf den meisten Rennstrecken dicht an der Spitze, ohne dass es viele Ausreißer gibt.\n",
        "\n",
        "Was die Laufzeit angeht, sind sowohl SABRE als auch Rustiq schnell, während der KI-gestützte Transpiler auf bestimmten Rennstrecken spürbar langsamer ist.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e5f6a7b8",
      "metadata": {},
      "source": [
        "<span id=\"best-performing-method-by-metric\" />\n",
        "\n",
        "#### Die nach der jeweiligen Kennzahl leistungsstärkste Methode\n",
        "\n",
        "Die nachstehende Grafik zeigt, wie oft die jeweilige Methode bei jeder Kennzahl den besten (niedrigsten) Wert erzielt hat. Es kann zu Gleichständen kommen: Bei einfacheren Schaltkreisen können mehrere Methoden dieselbe optimale Zwei-Qubit-Tiefe oder Gate-Anzahl erreichen. Bei einem Gleichstand werden alle Methoden, die den gleichen Wert aufweisen, berücksichtigt, sodass die Prozentsätze für eine bestimmte Kennzahl in der Summe mehr als 100 % ergeben können.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "f5a6b7c8",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_best_method_bars(results, metrics_list=None):\n",
        "    \"\"\"\n",
        "    Plot a grouped bar chart showing the percentage of circuits\n",
        "    where each method achieved the best (lowest) value for each metric.\n",
        "\n",
        "    Ties are counted for all tied methods, so percentages per metric\n",
        "    can sum to more than 100%.\n",
        "    \"\"\"\n",
        "    if metrics_list is None:\n",
        "        metrics_list = [\"two_qubit_depth\", \"size\", \"runtime\"]\n",
        "\n",
        "    labels = {\n",
        "        \"two_qubit_depth\": \"2Q Depth\",\n",
        "        \"size\": \"Gate Count\",\n",
        "        \"runtime\": \"Runtime\",\n",
        "    }\n",
        "    methods = _method_order(results)\n",
        "    palette = {\"SABRE\": \"#1f77b4\", \"AI\": \"#ff7f0e\", \"Rustiq\": \"#2ca02c\"}\n",
        "\n",
        "    by_index = {}\n",
        "    for r in results:\n",
        "        by_index.setdefault(r[\"qc_index\"], []).append(r)\n",
        "    n_circuits = len(by_index)\n",
        "\n",
        "    win_data = {m: [] for m in methods}\n",
        "    tie_counts = []\n",
        "    metric_labels = []\n",
        "\n",
        "    for metric in metrics_list:\n",
        "        metric_labels.append(\n",
        "            labels.get(metric, metric.replace(\"_\", \" \").title())\n",
        "        )\n",
        "        counts = Counter()\n",
        "        ties = 0\n",
        "        for group in by_index.values():\n",
        "            min_val = min(r[metric] for r in group)\n",
        "            best = [r[\"method\"] for r in group if r[metric] == min_val]\n",
        "            if len(best) > 1:\n",
        "                ties += 1\n",
        "            counts.update(best)\n",
        "        tie_counts.append(ties)\n",
        "        for m in methods:\n",
        "            win_data[m].append(counts.get(m, 0) / n_circuits * 100)\n",
        "\n",
        "    x = np.arange(len(metric_labels))\n",
        "    width = 0.22\n",
        "    fig, ax = plt.subplots(figsize=(8, 5))\n",
        "\n",
        "    for i, method in enumerate(methods):\n",
        "        bars = ax.bar(\n",
        "            x + i * width,\n",
        "            win_data[method],\n",
        "            width,\n",
        "            label=method,\n",
        "            color=palette.get(method, None),\n",
        "            edgecolor=\"black\",\n",
        "            linewidth=0.5,\n",
        "        )\n",
        "        for bar in bars:\n",
        "            height = bar.get_height()\n",
        "            if height > 0:\n",
        "                ax.text(\n",
        "                    bar.get_x() + bar.get_width() / 2,\n",
        "                    height + 1.5,\n",
        "                    f\"{height:.0f}%\",\n",
        "                    ha=\"center\",\n",
        "                    va=\"bottom\",\n",
        "                    fontsize=9,\n",
        "                )\n",
        "\n",
        "    # Annotate tie counts below each metric label\n",
        "    for j, ties in enumerate(tie_counts):\n",
        "        if ties > 0:\n",
        "            ax.text(\n",
        "                x[j] + width,\n",
        "                -8,\n",
        "                f\"({ties} tie{'s' if ties != 1 else ''})\",\n",
        "                ha=\"center\",\n",
        "                va=\"top\",\n",
        "                fontsize=8,\n",
        "                color=\"gray\",\n",
        "            )\n",
        "\n",
        "    ax.set_xticks(x + width)\n",
        "    ax.set_xticklabels(metric_labels, fontsize=11)\n",
        "    ax.set_ylabel(\"Circuits with best value (%)\", fontsize=11)\n",
        "    ax.set_title(\n",
        "        \"Best-Performing Method by Metric (ties counted for all tied methods)\",\n",
        "        fontsize=12,\n",
        "        fontweight=\"bold\",\n",
        "    )\n",
        "    ax.legend(frameon=True, fontsize=10)\n",
        "    ax.set_ylim(-12, 120)\n",
        "    ax.yaxis.set_major_formatter(ticker.PercentFormatter())\n",
        "    ax.grid(axis=\"y\", linestyle=\"--\", alpha=0.4)\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "a6b7c8d9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/a6b7c8d9-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_best_method_bars(results_small)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30687d7b",
      "metadata": {},
      "source": [
        "In diesem Beispiel zeigen die drei Methoden bei den kleinen Schaltungen eine sehr ähnliche Leistung. Bei zwei Qubits, gemessen an der Tiefe und der Anzahl der Gatter, ist der Anteil der Schaltungen, bei denen die jeweilige Methode am besten abschneidet, nahezu gleich (etwa 35–55 %), und bei vielen Schaltungen kommt es zu einem Unentschieden, da die einfachsten Schaltungen oft eine einzige optimale Lösung haben, die von mehreren Methoden gefunden wird. Der deutlichste Unterschied liegt in der Laufzeit: SABRE und Rustiq sind jeweils auf etwa der Hälfte der Schaltkreise am schnellsten, während der KI-gestützte Transpiler nur selten der Schnellste ist. Betrachtet man alle drei Kennzahlen zusammen, hat Rustiq insgesamt einen leichten Vorsprung: Es ist der häufigste Gewinner bei der 2-Qubit-Tiefe und bleibt auch bei der Gatteranzahl und der Laufzeit wettbewerbsfähig.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6c7d8e9",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Schritt 3: Mit „ Qiskit primitives “ ausführen\n",
        "\n",
        "Um zu untersuchen, wie sich die Qualität der Transpilierung auf die Ausführung unter Rauschbedingungen auswirkt, verwenden wir eine **Spiegel** -Schaltungstechnik. Für jede transpilierte Schaltung $U$ fügen wir deren Inverse $U^\\dagger$ an, sodass die kombinierte Schaltung $U^\\dagger U$ theoretisch die Identitätsschaltung ist. Ausgehend vom Zustand „ $|0\\rangle$ “ würde eine perfekte (rauschfreie) Ausführung mit einer Wahrscheinlichkeit von 1 die Bitstring aus lauter Nullen zurückgeben.\n",
        "\n",
        "In der Praxis summieren sich die Gatterfehler über die gesamte Schaltung hinweg, sodass die Wahrscheinlichkeit, dass „ $|0\\rangle^{\\otimes n}$ “ wiederhergestellt wird, sinkt. Ein Kompilierungsverfahren, das eine flachere Schaltung mit weniger Logikgatter erzeugt, führt zu weniger Rauschen.\n",
        "\n",
        "Der Ansatz mit Spiegelschaltungen ist bestechend einfach und lässt sich auf Schaltungen beliebiger Größe skalieren, da die erwartete Ausgabe stets „ $|0\\rangle^{\\otimes n}$ “ ist und keine klassische Simulation des idealen Zustands erforderlich ist. Beachten Sie jedoch die folgenden Einschränkungen: Die Spiegelschaltung ist ein Näherungsmodell der tatsächlichen Schaltung (nicht die Schaltung selbst), sie verdoppelt die Anzahl der Gatter (was den Einfluss von Rauschen übertrieben darstellt) und sie kann bestimmte Fehler unterschätzen, wenn sich das Rauschen symmetrisch über die Spiegelgrenze hinweg aufhebt.\n",
        "\n",
        "Wir wählen den Schaltungsindex 6 aus der Menge der kleinen Schaltungen aus und führen die Spiegel-Schaltungen auf einem Aer-Simulator mit einem einfachen Modell für depolarisierendes Rauschen durch.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "c6d7e8f9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Test circuit: all-vib-fccf, 4 qubits\n",
            "\n",
            "Transpilation metrics for circuit index 6:\n",
            "  SABRE     2Q depth=   66  size=   339\n",
            "  AI        2Q depth=   65  size=   300\n",
            "  Rustiq    2Q depth=   34  size=   193\n"
          ]
        }
      ],
      "source": [
        "# Select circuit index 6 from the small-scale transpiled circuits\n",
        "test_idx = 6\n",
        "test_circuit = qc_small[test_idx]\n",
        "print(f\"Test circuit: {test_circuit.name}, {test_circuit.num_qubits} qubits\")\n",
        "\n",
        "# Get the transpiled versions\n",
        "tqc_methods_small = {\n",
        "    \"SABRE\": tqc_sabre_small[test_idx],\n",
        "    \"AI\": tqc_ai_small[test_idx],\n",
        "    \"Rustiq\": tqc_rustiq_small[test_idx],\n",
        "}\n",
        "\n",
        "# Show transpilation metrics for this circuit\n",
        "print(f\"\\nTranspilation metrics for circuit index {test_idx}:\")\n",
        "for method, tqc in tqc_methods_small.items():\n",
        "    depth_2q = tqc.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    size = tqc.size()\n",
        "    print(f\"  {method:8s}  2Q depth={depth_2q:5d}  size={size:6d}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d6e7f8a9",
      "metadata": {},
      "source": [
        "Erstellen Sie die Spiegelungsschaltungen (siehe $U^\\dagger$ ), ordnen Sie die Qubit-Indizes so um, dass sie zusammenhängend sind, damit der Simulator nur die aktiven Qubits verarbeitet, und führen Sie die Berechnung auf einem verrauschten Aer-Simulator durch.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "e6f7a8b9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SABRE     P(|00...0>) = 0.7796  (7796/10000)\n",
            "AI        P(|00...0>) = 0.8073  (8073/10000)\n",
            "Rustiq    P(|00...0>) = 0.8923  (8923/10000)\n"
          ]
        }
      ],
      "source": [
        "def remap_to_contiguous(tqc):\n",
        "    \"\"\"Remap a transpiled circuit to use contiguous qubit indices.\n",
        "\n",
        "    Transpiled circuits target specific physical qubits (e.g., qubit 45, 67)\n",
        "    on a large backend. This remaps them to 0, 1, 2, ... so Aer only\n",
        "    simulates the active qubits.\n",
        "    \"\"\"\n",
        "    active = sorted(\n",
        "        {tqc.find_bit(q).index for inst in tqc.data for q in inst.qubits}\n",
        "    )\n",
        "    qubit_map = {old: new for new, old in enumerate(active)}\n",
        "    new_qc = QuantumCircuit(len(active))\n",
        "    for inst in tqc.data:\n",
        "        old_indices = [tqc.find_bit(q).index for q in inst.qubits]\n",
        "        new_qc.append(inst.operation, [qubit_map[i] for i in old_indices])\n",
        "    return new_qc\n",
        "\n",
        "\n",
        "def build_mirror_circuit(tqc):\n",
        "    \"\"\"Build a mirror circuit: U followed by U-dagger, with measurements.\n",
        "\n",
        "    The combined circuit U-dagger @ U should be the identity, so measuring\n",
        "    all zeros indicates a noise-free execution.\n",
        "    \"\"\"\n",
        "    tqc_compact = remap_to_contiguous(tqc)\n",
        "    mirror = tqc_compact.compose(tqc_compact.inverse())\n",
        "    mirror.measure_all()\n",
        "    return mirror\n",
        "\n",
        "\n",
        "# Build a simple depolarizing noise model\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_all_qubit_quantum_error(\n",
        "    depolarizing_error(0.001, 1),\n",
        "    [\"sx\", \"x\", \"rz\"],  # ~0.1% per 1Q gate\n",
        ")\n",
        "noise_model.add_all_qubit_quantum_error(\n",
        "    depolarizing_error(0.01, 2),\n",
        "    [\"cx\", \"ecr\"],  # ~1% per 2Q gate\n",
        ")\n",
        "\n",
        "aer_sim = AerSimulator(noise_model=noise_model)\n",
        "\n",
        "shots = 10000\n",
        "fidelities = {}\n",
        "\n",
        "for method, tqc in tqc_methods_small.items():\n",
        "    mirror = build_mirror_circuit(tqc)\n",
        "\n",
        "    sampler = SamplerV2(mode=aer_sim)\n",
        "    job = sampler.run([mirror], shots=shots)\n",
        "    result = job.result()\n",
        "    counts = result[0].data.meas.get_counts()\n",
        "\n",
        "    # Fidelity = fraction of all-zeros (error-free) outcomes\n",
        "    n_qubits = mirror.num_qubits - mirror.num_clbits  # active qubits\n",
        "    all_zeros = \"0\" * mirror.num_qubits\n",
        "    fidelity = counts.get(all_zeros, 0) / shots\n",
        "    fidelities[method] = fidelity\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {fidelity:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots})\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "small_step4_plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/small_step4_plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def plot_mirror_results(tqc_methods, fidelities, circuit_name):\n",
        "    \"\"\"\n",
        "    Plot a three-panel comparison: fidelity, 2Q depth,\n",
        "    and gate count for each compilation method.\n",
        "    \"\"\"\n",
        "    methods = list(tqc_methods.keys())\n",
        "    palette = {\"SABRE\": \"#1f77b4\", \"AI\": \"#ff7f0e\", \"Rustiq\": \"#2ca02c\"}\n",
        "    colors = [palette.get(m, \"gray\") for m in methods]\n",
        "\n",
        "    fidelity_vals = [fidelities[m] for m in methods]\n",
        "    depth_vals = [\n",
        "        tqc_methods[m].depth(lambda x: x.operation.num_qubits == 2)\n",
        "        for m in methods\n",
        "    ]\n",
        "    size_vals = [tqc_methods[m].size() for m in methods]\n",
        "\n",
        "    fig, axes = plt.subplots(1, 3, figsize=(16, 5))\n",
        "    fig.suptitle(\n",
        "        f\"Mirror Circuit Results: {circuit_name}\",\n",
        "        fontsize=14,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "\n",
        "    def _annotate_bars(ax, bars, values, fmt=\"{}\"):\n",
        "        ymax = ax.get_ylim()[1]\n",
        "        for bar, val in zip(bars, values):\n",
        "            label = fmt.format(val)\n",
        "            y = val + ymax * 0.03\n",
        "            ax.text(\n",
        "                bar.get_x() + bar.get_width() / 2,\n",
        "                y,\n",
        "                label,\n",
        "                ha=\"center\",\n",
        "                va=\"bottom\",\n",
        "                fontsize=10,\n",
        "                fontweight=\"bold\",\n",
        "            )\n",
        "\n",
        "    # Panel 1: Survival Probability\n",
        "    bars = axes[0].bar(\n",
        "        methods, fidelity_vals, color=colors, edgecolor=\"black\", linewidth=0.5\n",
        "    )\n",
        "    axes[0].set_ylabel(\"Fidelity  P(|00...0>)\", fontsize=11)\n",
        "    axes[0].set_title(\"Fidelity (higher is better)\", fontsize=12)\n",
        "    axes[0].set_ylim(\n",
        "        0, max(fidelity_vals) * 1.18 if max(fidelity_vals) > 0 else 1.0\n",
        "    )\n",
        "    axes[0].grid(axis=\"y\", linestyle=\"--\", alpha=0.4)\n",
        "    _annotate_bars(axes[0], bars, fidelity_vals, fmt=\"{:.4f}\")\n",
        "\n",
        "    # Panel 2: Two-Qubit Depth\n",
        "    bars = axes[1].bar(\n",
        "        methods, depth_vals, color=colors, edgecolor=\"black\", linewidth=0.5\n",
        "    )\n",
        "    axes[1].set_ylabel(\"Two-Qubit Depth\", fontsize=11)\n",
        "    axes[1].set_title(\"2Q Depth (lower is better)\", fontsize=12)\n",
        "    axes[1].set_ylim(0, max(depth_vals) * 1.18)\n",
        "    axes[1].grid(axis=\"y\", linestyle=\"--\", alpha=0.4)\n",
        "    _annotate_bars(axes[1], bars, depth_vals)\n",
        "\n",
        "    # Panel 3: Gate Count\n",
        "    bars = axes[2].bar(\n",
        "        methods, size_vals, color=colors, edgecolor=\"black\", linewidth=0.5\n",
        "    )\n",
        "    axes[2].set_ylabel(\"Total Gate Count\", fontsize=11)\n",
        "    axes[2].set_title(\"Gate Count (lower is better)\", fontsize=12)\n",
        "    axes[2].set_ylim(0, max(size_vals) * 1.18)\n",
        "    axes[2].grid(axis=\"y\", linestyle=\"--\", alpha=0.4)\n",
        "    _annotate_bars(axes[2], bars, size_vals)\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "plot_mirror_results(tqc_methods_small, fidelities, test_circuit.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "small_mirror_commentary",
      "metadata": {},
      "source": [
        "<span id=\"observations\" />\n",
        "\n",
        "#### Beobachtungen\n",
        "\n",
        "Die Methode mit der geringsten Zwei-Qubit-Tiefe und der geringsten Anzahl an Gatter erreicht die höchste Fidelität, was mit der Erwartung übereinstimmt, dass kürzere Schaltungen weniger Rauschen akkumulieren. Selbst geringfügige Unterschiede in der Tiefe und der Gate-Anzahl führen im Rahmen des depolarisierenden Rauschmodells zu messbaren Unterschieden in der Wiedergabetreue.\n",
        "\n",
        "Beachten Sie bitte, dass sich diese Ergebnisse auf einen einzelnen Stromkreis beziehen. Die relative Rangfolge der Methoden kann sich je nach Struktur des Hamilton-Operators von Schaltung zu Schaltung ändern.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-large-scale",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Beispiel für groß angelegte Hardware\n",
        "\n",
        "In diesem Abschnitt führen wir einen Vergleich derselben drei Kompilierungsmethoden an Hamilton-Schaltkreisen mit 20 oder mehr Qubits durch. Diese Schaltungen spiegeln die praktischen Arbeitslasten bei der Hamiltonian-Simulation besser wider und dienen dazu, zu testen, wie sich die einzelnen Methoden hinsichtlich Schaltungsqualität und Kompilierungszeit skalieren lassen.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6a7b8c9",
      "metadata": {},
      "source": [
        "<span id=\"steps-1-4-combined\" />\n",
        "\n",
        "### Schritte 1–4 zusammengefasst\n",
        "\n",
        "Der Arbeitsablauf folgt derselben Struktur wie das Beispiel im kleinen Maßstab. Wir transpilieren alle groß angelegten Schaltkreise mit den jeweiligen Methoden, erfassen Metriken und übermitteln einen Spiegel-Schaltkreis an echte Quantenhardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "a7b8c9d0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[SABRE] Circuit 0 (all-vib-hc3h2cn): 2Q depth=2, size=258, time=0.16s\n",
            "[SABRE] Circuit 1 (ham-graph-gnp_k-5): 2Q depth=345, size=4036, time=0.08s\n",
            "[SABRE] Circuit 2 (TSP_Ncity-5): 2Q depth=187, size=2045, time=0.04s\n",
            "[SABRE] Circuit 3 (tfim): 2Q depth=100, size=489, time=0.21s\n",
            "[SABRE] Circuit 4 (all-vib-h2co): 2Q depth=30, size=570, time=0.18s\n",
            "[SABRE] Circuit 5 (uuf100-ham): 2Q depth=414, size=4779, time=0.09s\n",
            "[SABRE] Circuit 6 (uuf100-ham): 2Q depth=523, size=5667, time=0.11s\n",
            "[SABRE] Circuit 7 (graph-gnp_k-4): 2Q depth=3028, size=24885, time=0.39s\n",
            "[SABRE] Circuit 8 (uf100-ham): 2Q depth=700, size=8271, time=0.15s\n",
            "[SABRE] Circuit 9 (uf100-ham): 2Q depth=698, size=8957, time=0.15s\n",
            "[SABRE] Circuit 10 (TSP_Ncity-7): 2Q depth=432, size=6353, time=0.12s\n",
            "[SABRE] Circuit 11 (all-vib-cyclo_propene): 2Q depth=30, size=1144, time=0.20s\n",
            "[SABRE] Circuit 12 (TSP_Ncity-8): 2Q depth=704, size=10287, time=0.18s\n",
            "[SABRE] Circuit 13 (uf100-ham): 2Q depth=2454, size=30195, time=0.46s\n",
            "[SABRE] Circuit 14 (tfim): 2Q depth=245, size=3670, time=0.08s\n",
            "[SABRE] Circuit 15 (flat100-ham): 2Q depth=154, size=3836, time=0.12s\n",
            "[SABRE] Circuit 16 (graph-regular_reg-4): 2Q depth=863, size=14063, time=0.22s\n",
            "[SABRE] Circuit 17 (tfim): 2Q depth=581, size=8810, time=0.15s\n",
            "[SABRE] Circuit 18 (FH_D-1): 2Q depth=1704, size=9528, time=0.35s\n",
            "[SABRE] Circuit 19 (TSP_Ncity-10): 2Q depth=1091, size=22041, time=0.38s\n",
            "[SABRE] Circuit 20 (TSP_Ncity-10): 2Q depth=1091, size=22005, time=0.38s\n",
            "[SABRE] Circuit 21 (ham-unary-color02-queen13_13_k-4): 2Q depth=224, size=8321, time=0.17s\n",
            "[AI] Circuit 0 (all-vib-hc3h2cn): 2Q depth=2, size=258, time=0.17s\n",
            "[AI] Circuit 1 (ham-graph-gnp_k-5): 2Q depth=323, size=4418, time=3.13s\n",
            "[AI] Circuit 2 (TSP_Ncity-5): 2Q depth=161, size=2229, time=1.47s\n",
            "[AI] Circuit 3 (tfim): 2Q depth=20, size=402, time=0.34s\n",
            "[AI] Circuit 4 (all-vib-h2co): 2Q depth=38, size=661, time=0.19s\n",
            "[AI] Circuit 5 (uuf100-ham): 2Q depth=391, size=5130, time=3.27s\n",
            "[AI] Circuit 6 (uuf100-ham): 2Q depth=463, size=6095, time=4.23s\n",
            "[AI] Circuit 7 (graph-gnp_k-4): 2Q depth=3207, size=25641, time=15.15s\n",
            "[AI] Circuit 8 (uf100-ham): 2Q depth=637, size=8267, time=5.87s\n",
            "[AI] Circuit 9 (uf100-ham): 2Q depth=632, size=9330, time=7.29s\n",
            "[AI] Circuit 10 (TSP_Ncity-7): 2Q depth=452, size=7418, time=6.02s\n",
            "[AI] Circuit 11 (all-vib-cyclo_propene): 2Q depth=38, size=1323, time=0.27s\n",
            "[AI] Circuit 12 (TSP_Ncity-8): 2Q depth=609, size=11131, time=10.07s\n",
            "[AI] Circuit 13 (uf100-ham): 2Q depth=2251, size=31128, time=38.77s\n",
            "[AI] Circuit 14 (tfim): 2Q depth=165, size=3460, time=1.64s\n",
            "[AI] Circuit 15 (flat100-ham): 2Q depth=91, size=3497, time=2.49s\n",
            "[AI] Circuit 16 (graph-regular_reg-4): 2Q depth=664, size=15256, time=12.35s\n",
            "[AI] Circuit 17 (tfim): 2Q depth=583, size=9157, time=6.28s\n",
            "[AI] Circuit 18 (FH_D-1): 2Q depth=1193, size=7754, time=4.54s\n",
            "[AI] Circuit 19 (TSP_Ncity-10): 2Q depth=1134, size=22577, time=25.64s\n",
            "[AI] Circuit 20 (TSP_Ncity-10): 2Q depth=1172, size=23851, time=28.97s\n",
            "[AI] Circuit 21 (ham-unary-color02-queen13_13_k-4): 2Q depth=219, size=8600, time=8.85s\n",
            "[Rustiq] Circuit 0 (all-vib-hc3h2cn): 2Q depth=2, size=257, time=0.16s\n",
            "[Rustiq] Circuit 1 (ham-graph-gnp_k-5): 2Q depth=640, size=5831, time=0.13s\n",
            "[Rustiq] Circuit 2 (TSP_Ncity-5): 2Q depth=408, size=3985, time=0.08s\n",
            "[Rustiq] Circuit 3 (tfim): 2Q depth=31, size=688, time=0.07s\n",
            "[Rustiq] Circuit 4 (all-vib-h2co): 2Q depth=65, size=1058, time=2.91s\n",
            "[Rustiq] Circuit 5 (uuf100-ham): 2Q depth=633, size=6757, time=0.14s\n",
            "[Rustiq] Circuit 6 (uuf100-ham): 2Q depth=795, size=8495, time=0.17s\n",
            "[Rustiq] Circuit 7 (graph-gnp_k-4): 2Q depth=13768, size=139793, time=2.92s\n",
            "[Rustiq] Circuit 8 (uf100-ham): 2Q depth=1099, size=11878, time=0.25s\n",
            "[Rustiq] Circuit 9 (uf100-ham): 2Q depth=911, size=11111, time=0.22s\n",
            "[Rustiq] Circuit 10 (TSP_Ncity-7): 2Q depth=1183, size=13197, time=0.27s\n",
            "[Rustiq] Circuit 11 (all-vib-cyclo_propene): 2Q depth=67, size=2491, time=13.56s\n",
            "[Rustiq] Circuit 12 (TSP_Ncity-8): 2Q depth=1615, size=21358, time=0.48s\n",
            "[Rustiq] Circuit 13 (uf100-ham): 2Q depth=2920, size=40465, time=0.91s\n",
            "[Rustiq] Circuit 14 (tfim): 2Q depth=489, size=6552, time=0.15s\n",
            "[Rustiq] Circuit 15 (flat100-ham): 2Q depth=378, size=5906, time=0.14s\n",
            "[Rustiq] Circuit 16 (graph-regular_reg-4): 2Q depth=12163, size=168679, time=2.94s\n",
            "[Rustiq] Circuit 17 (tfim): 2Q depth=1208, size=17042, time=0.36s\n",
            "[Rustiq] Circuit 18 (FH_D-1): 2Q depth=1061, size=24000, time=0.47s\n",
            "[Rustiq] Circuit 19 (TSP_Ncity-10): 2Q depth=2565, size=41340, time=1.38s\n",
            "[Rustiq] Circuit 20 (TSP_Ncity-10): 2Q depth=2565, size=41275, time=1.38s\n",
            "[Rustiq] Circuit 21 (ham-unary-color02-queen13_13_k-4): 2Q depth=808, size=17548, time=0.42s\n"
          ]
        }
      ],
      "source": [
        "results_large = []\n",
        "\n",
        "tqc_sabre_large = capture_transpilation_metrics(\n",
        "    results_large, pm_sabre, qc_large, \"SABRE\"\n",
        ")\n",
        "tqc_ai_large = capture_transpilation_metrics(\n",
        "    results_large, pm_ai, qc_large, \"AI\"\n",
        ")\n",
        "tqc_rustiq_large = capture_transpilation_metrics(\n",
        "    results_large, pm_rustiq, qc_large, \"Rustiq\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "b7c8d9e0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mean +/- std per compilation method\n",
            "Method                2Q Depth              Gate Count             Runtime (s)\n",
            "------------------------------------------------------------------------------\n",
            "SABRE          709.1 +/- 783.8     9,100.5 +/- 8,493.1             0.2 +/- 0.1\n",
            "AI             656.6 +/- 777.5     9,435.6 +/- 8,853.0            8.5 +/- 10.2\n",
            "Rustiq     2,062.5 +/- 3,631.1   26,804.8 +/- 43,403.1             1.3 +/- 2.9\n",
            "\n",
            "Mean % improvement vs SABRE (positive = better than SABRE)\n",
            "Method                2Q Depth              Gate Count             Runtime (s)\n",
            "------------------------------------------------------------------------------\n",
            "AI             +9.6% +/- 22.8%          -3.4% +/- 9.4%    -3620.0% +/- 2405.5%\n",
            "Rustiq      -154.5% +/- 273.9%      -137.1% +/- 233.2%     -527.0% +/- 1405.5%\n"
          ]
        }
      ],
      "source": [
        "print_summary_table(results_large)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "per_circuit_large_code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2Q Depth (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-hc3h2cn   24       2*       2*       2*\n",
            "  1  ham-graph-gnp_k-  24      345     323*      640\n",
            "  2  TSP_Ncity-5       25      187     161*      408\n",
            "  3  tfim              26      100      20*       31\n",
            "  4  all-vib-h2co      32      30*       38       65\n",
            "  5  uuf100-ham        40      414     391*      633\n",
            "  6  uuf100-ham        40      523     463*      795\n",
            "  7  graph-gnp_k-4     40    3028*     3207    13768\n",
            "\n",
            "Gate Count (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-hc3h2cn   24      258      258     257*\n",
            "  1  ham-graph-gnp_k-  24    4036*     4418     5831\n",
            "  2  TSP_Ncity-5       25    2045*     2229     3985\n",
            "  3  tfim              26      489     402*      688\n",
            "  4  all-vib-h2co      32     570*      661     1058\n",
            "  5  uuf100-ham        40    4779*     5130     6757\n",
            "  6  uuf100-ham        40    5667*     6095     8495\n",
            "  7  graph-gnp_k-4     40   24885*    25641   139793\n",
            "\n",
            "Runtime (s) (first 8 circuits by qubit count); * = best\n",
            "Idx  Circuit            Q    SABRE       AI   Rustiq\n",
            "----------------------------------------------------\n",
            "  0  all-vib-hc3h2cn   24     0.16     0.17    0.16*\n",
            "  1  ham-graph-gnp_k-  24    0.08*     3.13     0.13\n",
            "  2  TSP_Ncity-5       25    0.04*     1.47     0.08\n",
            "  3  tfim              26     0.21     0.34    0.07*\n",
            "  4  all-vib-h2co      32    0.18*     0.19     2.91\n",
            "  5  uuf100-ham        40    0.09*     3.27     0.14\n",
            "  6  uuf100-ham        40    0.11*     4.23     0.17\n",
            "  7  graph-gnp_k-4     40    0.39*    15.15     2.92\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print_per_circuit_comparison(results_large, num_rows=8)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "c7d8e9f0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/c7d8e9f0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_transpilation_comparison(\n",
        "    results_large,\n",
        "    \"Large-Scale Hamiltonian Circuits: Compilation Comparison\",\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "pct_improvement_large",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/pct_improvement_large-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_pct_improvement_vs_sabre(\n",
        "    results_large,\n",
        "    \"Large-Scale Hamiltonian Circuits\",\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "d7e8f9a0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/d7e8f9a0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_best_method_bars(results_large)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "f7a8b9c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Test circuit: tfim, 26 qubits\n",
            "\n",
            "Transpilation metrics for circuit index 3:\n",
            "  SABRE     2Q depth=  100  size=   489\n",
            "  AI        2Q depth=   20  size=   402\n",
            "  Rustiq    2Q depth=   31  size=   688\n"
          ]
        }
      ],
      "source": [
        "# Select circuit index 3 from the large-scale transpiled circuits\n",
        "test_idx_large = 3\n",
        "test_circuit_large = qc_large[test_idx_large]\n",
        "print(\n",
        "    f\"Test circuit: {test_circuit_large.name}, {test_circuit_large.num_qubits} qubits\"\n",
        ")\n",
        "\n",
        "tqc_methods_large = {\n",
        "    \"SABRE\": tqc_sabre_large[test_idx_large],\n",
        "    \"AI\": tqc_ai_large[test_idx_large],\n",
        "    \"Rustiq\": tqc_rustiq_large[test_idx_large],\n",
        "}\n",
        "\n",
        "print(f\"\\nTranspilation metrics for circuit index {test_idx_large}:\")\n",
        "for method, tqc in tqc_methods_large.items():\n",
        "    depth_2q = tqc.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    size = tqc.size()\n",
        "    print(f\"  {method:8s}  2Q depth={depth_2q:5d}  size={size:6d}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "3cd3afa2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "SABRE transpiled circuit:\n",
            "OrderedDict({'sx': 211, 'rz': 163, 'cz': 104, 'x': 11})\n",
            "SABRE mirror circuit count ops:\n",
            "OrderedDict({'rz': 1170, 'sx': 422, 'cz': 208, 'measure': 156, 'x': 22, 'barrier': 1})\n",
            "\n",
            "AI transpiled circuit:\n",
            "OrderedDict({'sx': 165, 'rz': 162, 'cz': 68, 'x': 7})\n",
            "AI mirror circuit count ops:\n",
            "OrderedDict({'rz': 984, 'sx': 330, 'measure': 156, 'cz': 136, 'x': 14, 'barrier': 1})\n",
            "\n",
            "Rustiq transpiled circuit:\n",
            "OrderedDict({'sx': 316, 'rz': 225, 'cz': 140, 'x': 7})\n",
            "Rustiq mirror circuit count ops:\n",
            "OrderedDict({'rz': 1714, 'sx': 632, 'cz': 280, 'measure': 156, 'x': 14, 'barrier': 1})\n"
          ]
        }
      ],
      "source": [
        "pm_mirror = generate_preset_pass_manager(\n",
        "    optimization_level=0, backend=backend\n",
        ")\n",
        "\n",
        "for method, tqc in tqc_methods_large.items():\n",
        "    # print the count ops for each circuit\n",
        "    mirror = tqc.copy()\n",
        "    mirror.compose(tqc.inverse(), inplace=True)\n",
        "    mirror.measure_all()\n",
        "    mirror = pm_mirror.run(mirror)\n",
        "    print(f\"\\n{method} transpiled circuit:\")\n",
        "    print(tqc.count_ops())\n",
        "    print(f\"{method} mirror circuit count ops:\")\n",
        "    print(mirror.count_ops())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "large_hw_submit",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SABRE: submitted job d8gvgq66983c73dqe5og\n",
            "AI: submitted job d8gvgqe6983c73dqe5pg\n",
            "Rustiq: submitted job d8gvgqm6983c73dqe5q0\n"
          ]
        }
      ],
      "source": [
        "# Build mirror circuits and submit to real hardware\n",
        "# The inverse may introduce gates (e.g., sxdg) not in the backend's\n",
        "# basis gate set, so we re-transpile the mirror circuit.\n",
        "pm_mirror = generate_preset_pass_manager(\n",
        "    optimization_level=0, backend=backend\n",
        ")\n",
        "\n",
        "shots_hw = 10000\n",
        "hw_jobs = {}\n",
        "\n",
        "for method, tqc in tqc_methods_large.items():\n",
        "    mirror = tqc.copy()\n",
        "    mirror.compose(tqc.inverse(), inplace=True)\n",
        "    mirror.measure_all()\n",
        "\n",
        "    # Re-transpile at opt level 0 to decompose into basis gates\n",
        "    # without changing the layout or routing\n",
        "    mirror = pm_mirror.run(mirror)\n",
        "\n",
        "    sampler = SamplerV2(mode=backend)\n",
        "    sampler.options.environment.job_tags = [\"TUT_CMHSC\"]\n",
        "    job = sampler.run([mirror], shots=shots_hw)\n",
        "    hw_jobs[method] = job\n",
        "    print(f\"{method}: submitted job {job.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "large_hw_results",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SABRE     P(|00...0>) = 0.0005  (5/10000)\n",
            "AI        P(|00...0>) = 0.3267  (3267/10000)\n",
            "Rustiq    P(|00...0>) = 0.1845  (1845/10000)\n"
          ]
        }
      ],
      "source": [
        "# Retrieve results and compute fidelities\n",
        "fidelities_large = {}\n",
        "\n",
        "for method, job in hw_jobs.items():\n",
        "    result = job.result()\n",
        "    counts = result[0].data.meas.get_counts()\n",
        "\n",
        "    n_qubits = backend.num_qubits\n",
        "    all_zeros = \"0\" * n_qubits\n",
        "    fidelity = counts.get(all_zeros, 0) / shots_hw\n",
        "    fidelities_large[method] = fidelity\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {fidelity:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots_hw})\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "large_hw_plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/compilation-methods-for-hamiltonian-simulation-circuits/extracted-outputs/large_hw_plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_mirror_results(\n",
        "    tqc_methods_large, fidelities_large, test_circuit_large.name\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-analysis",
      "metadata": {},
      "source": [
        "<span id=\"analysis-of-compilation-results\" />\n",
        "\n",
        "## Auswertung der Kompilierungsergebnisse\n",
        "\n",
        "Die oben aufgeführten Benchmarks vergleichen SABRE, den KI-gestützten Transpiler, und Rustiq anhand von Hamilton-Simulationsschaltungen aus der Hamlib-Sammlung sowohl im kleinen als auch im großen Maßstab.\n",
        "\n",
        "<span id=\"two-qubit-depth-and-gate-count\" />\n",
        "\n",
        "### Tiefe und Anzahl der Gatter bei zwei Qubits\n",
        "\n",
        "Im großen Maßstab sind SABRE und der KI-gestützte Transpiler die beiden leistungsstärksten Lösungen, wobei jede bei einer anderen Kennzahl die Nase vorn hat. Wie *aus* dem Diagramm der Leistungsmetriken hervorgeht, weist SABRE bei der überwiegenden Mehrheit der Schaltungen die geringste Gate-Anzahl auf und ist bei fast allen Schaltungen die schnellste Methode. Dies steht im Einklang mit einer Heuristik, die darauf ausgelegt ist, die Anzahl der eingefügten SWAP-Gates zu minimieren, sowie mit den jüngsten Optimierungen des Layouts und des Routings. Der KI-gestützte Transpiler erzeugt bei den meisten Schaltkreisen die geringste Zwei-Qubit-Tiefe, was mit dem Teil seines Ziels im Rahmen des verstärkenden Lernens übereinstimmt, der auf die Schaltkreistiefe abzielt. Die Übersichtstabelle spiegelt dieselbe Aufteilung wider: SABRE weist die geringere durchschnittliche Gate-Anzahl auf, während der KI-Transpiler die geringere durchschnittliche Zwei-Qubit-Tiefe aufweist. Beide Methoden sind über den gesamten Schaltungsbereich hinweg konsistent und zuverlässig.\n",
        "\n",
        "Rustiq, das speziell für `PauliEvolutionGate` die Synthese entwickelt wurde, liefert das mit Abstand beste Ergebnis bei nur einem kleinen Teil der groß angelegten Schaltungen. Die Durchschnittswerte werden durch eine Handvoll signifikanter Ausreißer stark verzerrt, was sich in Form großer Spitzen im Vergleichsdiagramm der Kompilierung zeigt, in dem Rustiq deutlich höhere Werte bei der Tiefe und der Gate-Anzahl aufweist als die anderen Methoden. Ohne diese Ausreißer würde seine durchschnittliche Leistung deutlich näher an der von SABRE und dem KI-gestützten Transpiler liegen.\n",
        "\n",
        "Die wichtigste Erkenntnis ist, dass keine einzelne Methode auf jeder Rennstrecke dominiert. Jede Methode schneidet in bestimmten Fällen besser ab als die anderen, weshalb es sich lohnt, alle verfügbaren Werkzeuge auszuprobieren und für jede Schaltung das beste Ergebnis auszuwählen.\n",
        "\n",
        "<span id=\"runtime\" />\n",
        "\n",
        "### Laufzeit\n",
        "\n",
        "SABRE ist durchweg die schnellste Methode. Rustiq läuft in der Regel mit ähnlicher Geschwindigkeit, es kann jedoch zu Ausreißern kommen, bei denen die Kompilierung deutlich länger dauert. Dies zeigt sich besonders deutlich in den Ergebnissen für große Skalen, bei denen einige wenige Schaltkreise zu einem sprunghaften Anstieg der Laufzeit von Rustiq führen. Diese Ausreißer wirken sich stark auf die durchschnittliche Laufzeit aus, sodass der Median für Rustiq möglicherweise eine repräsentativere Kennzahl darstellt. Der KI-gestützte Transpiler ist der langsamste der drei; seine Laufzeit nimmt bei größeren und komplexeren Schaltungen deutlich zu.\n",
        "\n",
        "<span id=\"mirror-circuit-results\" />\n",
        "\n",
        "### Ergebnisse der Spiegelungsschaltung\n",
        "\n",
        "Die Experimente mit Spiegel-Schaltungen bestätigen den erwarteten Trend: Verfahren, die eine geringere Zwei-Qubit-Tiefe und weniger Gatter erfordern, erzielen unter Rauschbedingungen eine höhere Genauigkeit. Dies gilt sowohl für den verrauschten Simulator (im kleinen Maßstab) als auch für die reale Hardware (im großen Maßstab).\n",
        "\n",
        "Beachten Sie, dass jede Darstellung einer Spiegel-Schaltung eine einzelne Schaltung widerspiegelt und nicht die Gesamtheit. Das obige Hardware-Beispiel verwendet eine Schaltung mit 26 Qubits `tfim` . In diesem Fall erzielt SABRE eine deutlich höhere Zwei-Qubit-Tiefe als der KI-gestützte Transpiler und Rustiq, weshalb seine Genauigkeit entsprechend viel geringer ist. Dies ist nicht repräsentativ für die Gesamtergebnisse: Bei der gesamten Gruppe groß angelegter Schaltkreise liegt die Zwei-Qubit-Tiefe von SABRE in der Regel nahe an der des KI-gestützten Transpilers, und die beiden Methoden schneiden bei unterschiedlichen Kennzahlen jeweils besser ab (der KI-gestützte Transpiler bei der Zwei-Qubit-Tiefe, SABRE bei der Gatteranzahl und der Laufzeit). Ein einzelnes Spiegelungsergebnis testet eine verdoppelte Version einer Schaltung und nicht die gesamte Arbeitslast; daher sollte es nicht als Urteil über die Gesamtqualität der Methode gewertet werden.\n",
        "\n",
        "<span id=\"recommendations\" />\n",
        "\n",
        "### Empfehlungen\n",
        "\n",
        "Es gibt keine einheitliche, für alle Schaltungen optimale Transpilationsstrategie. Die beste Wahl hängt von der Schaltungsstruktur, dem Optimierungsziel und dem verfügbaren Zeitbudget für die Kompilierung ab:\n",
        "\n",
        "* **SABRE** ist die empfohlene Standardeinstellung. Es ist schnell und zuverlässig und liefert auf einer Vielzahl von Rennstrecken hervorragende Ergebnisse. Zur weiteren Feinabstimmung können Anwender die Anzahl der Layout- und Routing-Versuche erhöhen (siehe das [SABRE-Optimierungs-Tutorial](/docs/tutorials/transpilation-optimizations-with-sabre) ).\n",
        "* **Der KI-gestützte Transpiler** ist einen Versuch wert, wenn die Kompilierungszeit keine Rolle spielt, insbesondere wenn die Minimierung der Zwei-Qubit-Tiefe im Vordergrund steht: Bei den meisten groß angelegten Schaltkreisen in diesem Benchmark erzielte er die geringste Zwei-Qubit-Tiefe.\n",
        "* **Rustiq** wurde speziell für `PauliEvolutionGate` Schaltungen entwickelt und kann Lösungen mit sehr geringer Komplexität und geringer Gate-Anzahl finden, insbesondere bei kleineren Schaltungen. Bei größeren Schaltkreisen kann diese Methode gelegentlich zu deutlich höheren Ergebnissen führen; daher sollte sie eher als eine von mehreren zu testenden Methoden eingesetzt werden und nicht als Standardverfahren.\n",
        "\n",
        "In der Praxis empfiehlt es sich, alle verfügbaren Methoden durchzuprobieren und für jede Schaltung das beste Ergebnis auszuwählen. Der Kompilierungsaufwand für das Ausprobieren mehrerer Methoden ist gering im Vergleich zu der potenziellen Verbesserung der Ausführungsqualität auf echter Hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-next-steps",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Nächste Schritte\n",
        "\n",
        "Wenn Ihnen diese Anleitung gefallen hat, könnte Sie Folgendes interessieren:\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Empfehlungen\">\n",
        "  * [Optimierungen bei der Transpilation mit SABRE](/docs/tutorials/transpilation-optimizations-with-sabre)\n",
        "  * [Der KI-gestützte Transpiler besteht die Prüfung](/docs/guides/ai-transpiler-passes)\n",
        "  * [Ein Transpiler-Plugin erstellen](/docs/guides/create-transpiler-plugin)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-references",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referenzen\n",
        "\n",
        "\\[1] \"\"LightSABRE: Ein leichtgewichtiger und erweiterter SABRE-Algorithmus\". H. Zou, M. Treinish, K. Hartman, A. Ivrii, J. Lishman et al. [https://arxiv.org/abs/2409.08368](https://arxiv.org/abs/2409.08368)\n",
        "\n",
        "\\[2] \"Praktische und effiziente Synthese und Transpilierung von Quantenschaltungen mit Reinforcement Learning\". D. Kremer, V. Villar, H. Paik, I. Duran, I. Faro, J. Cruz-Benito et al. [https://arxiv.org/abs/2405.13196](https://arxiv.org/abs/2405.13196)\n",
        "\n",
        "\\[3] „Pauli-Netzwerkschaltungssynthese mit verstärkendem Lernen“. A: Dubal, D. Kremer, S. Martiel, V. Villar, D. Wang, J. Cruz-Benito u. a. [https://arxiv.org/abs/2503.14448](https://arxiv.org/abs/2503.14448)\n",
        "\n",
        "\\[4] „Schnellere und kürzere Synthese von Hamilton-Simulationsschaltungen“. T. Goubault de Brugiere, S. Martiel et al. [ https://arxiv.org/abs/2404.03280](https://arxiv.org/abs/2404.03280)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "hours": 1,
    "qpuSeconds": 60
  },
  "nbformat": 4,
  "nbformat_minor": 5
}