{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a1b2c3d4",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"해밀턴 시뮬레이션 회로용 컴파일 방법\"\n",
        "description: \"Hamlib의 해밀토니안 시뮬레이션 회로에 대해 SABRE, AI 기반 트랜스파일러, Rustiq의 컴파일 방식을 비교해 보십시오.\"\n",
        "---\n",
        "\n",
        "<span id=\"compilation-methods-for-hamiltonian-simulation-circuits\" />\n",
        "\n",
        "# 해밀턴 시뮬레이션 회로용 컴파일 방법\n",
        "\n",
        "*예상 소요 시간: IBM Heron 프로세서 기준 1분 미만 (참고: 이는 단지 예상치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)*\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",
        "## 학습 성과\n",
        "\n",
        "* SABRE와 함께 Qiskit 트랜스파일러를 사용하여 레이아웃 및 라우팅 최적화를 수행하는 방법\n",
        "* AI 기반 트랜스파일러를 활용하여 회로를 고도로 최적화하는 방법\n",
        "* 해밀턴 연산 회로에서 연산을 합성하기 `PauliEvolutionGate` 위해 Rustiq 플러그인을 사용하는 방법\n",
        "* 2-큐비트 깊이, 총 게이트 수 및 실행 시간을 활용하여 컴파일 방법을 벤치마킹하고 비교하는 방법\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 전제조건\n",
        "\n",
        "* [트랜스파일레이션 개념](/docs/guides/transpile)\n",
        "* [트랜스파일러 단계](/docs/guides/transpiler-stages)\n",
        "* [통과 관리자를 사용한 트랜스파일링](/docs/guides/transpile-with-pass-managers)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c1d2e3f4",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 배경\n",
        "\n",
        "양자 회로 컴파일링은 고수준 양자 알고리즘을 대상 하드웨어의 제약 조건을 준수하는 물리적 회로로 변환합니다. 효율적인 컴파일링은 회로 깊이와 게이트 수를 크게 줄일 수 있으며, 이 두 가지 요소는 모두 단기적인 양자 장치에서 얻어지는 결과의 품질에 직접적인 영향을 미칩니다.\n",
        "\n",
        "`PauliEvolutionGate`이 튜토리얼에서는 로 구축된 해밀토니안 시뮬레이션 회로에 대해 세 가지 컴파일 방법을 벤치마킹합니다. 이러한 회로는 쌍을 이루는 큐비트 간의 상호작용( $ZZ$ 항, $XX$ 항, $YY$ 항 등)을 모델링하며, 양자화학, 응집물질 물리학, 재료과학 분야에서 흔히 사용됩니다.\n",
        "\n",
        "벤치마크 회로는 [Benchpress](https://github.com/Qiskit/benchpress) 저장소를 통해 접근할 수 있는 [Hamlib](https://github.com/SRI-International/QC-App-Oriented-Benchmarks/tree/master/qedcbench/hamlib#hamlib-simulation---benchmark-program) 컬렉션에서 가져온 것입니다. Hamlib은 표준화된 대표적인 해밀토니안 집합을 제공하여, 실제 시뮬레이션 워크로드에 대한 컴파일 전략을 비교할 수 있게 해줍니다.\n",
        "\n",
        "<span id=\"compilation-methods-overview\" />\n",
        "\n",
        "### 컴파일 방법 개요\n",
        "\n",
        "<span id=\"qiskit-transpiler-with-sabre\" />\n",
        "\n",
        "#### SABRE를 지원하는 Qiskit 트랜스파일러\n",
        "\n",
        "Qiskit 트랜스파일러는 SABRE(SWAP 기반 BidiREctional 휴리스틱 탐색) 알고리즘을 사용하여 회로 레이아웃과 라우팅을 최적화합니다. SABRE는 하드웨어 연결 제약 조건을 준수하면서 SWAP 게이트 수와 이로 인한 회로 깊이 증가를 최소화하는 데 중점을 둡니다. 이 방법은 성능과 컴파일 시간 사이에서 적절한 균형을 제공하는 범용적인 방법입니다. 자세한 내용은 [\\[1\\]](https://arxiv.org/abs/2409.08368) 을 참조하십시오. SABRE의 장점과 매개변수 탐색에 대해서는 별도의 [튜](/docs/tutorials/transpilation-optimizations-with-sabre) 토리얼에서 심도 있게 다루고 있습니다.\n",
        "\n",
        "<span id=\"ai-powered-transpiler\" />\n",
        "\n",
        "#### AI 기반 트랜스파일러\n",
        "\n",
        "이 AI 기반 트랜스파일러는 기계 학습을 활용하여 회로 구조의 패턴과 하드웨어 제약 조건을 분석함으로써 최적의 트랜스파일링 전략을 예측합니다. 또한 강화 학습 기반의 합성 접근법을 활용해 파울리 네트워크 회로를 대상으로 하는 ‘패스(pass)’를 `AIPauliNetworkSynthesis` 적용할 수도 있습니다. 자세한 내용은 [\\[2\\]](https://arxiv.org/abs/2405.13196) 와 [\\[3\\]](https://arxiv.org/abs/2503.14448) 을 참조하십시오.\n",
        "\n",
        "<span id=\"rustiq-plugin\" />\n",
        "\n",
        "#### Rustiq 플러그인\n",
        "\n",
        "Rustiq 플러그인은 트로터화 역학에서 흔히 사용되는 파울리 회전을 나타내는 연산에 `PauliEvolutionGate` 특화된 고급 합성 기법을 제공합니다. 이 방법은 해밀턴 연산 시뮬레이션 워크로드를 위해 깊이 낮은 회로 분해를 생성하도록 설계되었습니다. 자세한 내용은 [\\[4\\]를](https://arxiv.org/abs/2404.03280) 참조하십시오.\n",
        "\n",
        "<span id=\"key-metrics\" />\n",
        "\n",
        "### 키 메트릭\n",
        "\n",
        "우리는 다음 평가 지표를 바탕으로 세 가지 방법을 비교합니다:\n",
        "\n",
        "* **2-큐비트 깊이** : 2-큐비트 게이트만을 집계한 회로의 깊이. 이는 실제 하드웨어에서 정확도를 저해하는 주요 요인이 되는 경우가 많습니다.\n",
        "* **회로 크기(총 게이트 수)** : 트랜스파일링된 회로의 총 게이트 수.\n",
        "* **실행 시간** : 트랜스파일링에 소요된 실제 시간.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d1e2f3a4",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 요구사항\n",
        "\n",
        "이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:\n",
        "\n",
        "* Qiskit SDK v2.0 또는 그 이후 버전이며, [시각화 기능을](/docs/api/qiskit/visualization) 지원합니다\n",
        "* Qiskit Runtime v0.22 또는 그 이후 (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer (`pip install qiskit-aer`)\n",
        "* 키스킷 IBM 트랜스파일러 (`pip install qiskit-ibm-transpiler`)\n",
        "* 키스킷 AI 트랜스파일러 로컬 모드 (`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",
        "## 설정\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",
        "### 백엔드에 연결하기\n",
        "\n",
        "소규모 예제와 대규모 예제 모두에 사용할 백엔드를 선택하십시오. 백엔드는 트랜스파일러가 대상으로 삼는 결합 맵과 기본 게이트를 결정합니다.\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",
        "### 패스 관리자 정의\n",
        "\n",
        "세 가지 컴파일 방법을 설정하십시오.\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",
        "### 헬퍼 함수 정의하기\n",
        "\n",
        "다음 함수는 주어진 패스 매니저를 사용하여 회로 목록을 트랜스파일하고, 각 회로에 대한 주요 지표(2-큐비트 깊이, 회로 크기, 실행 시간)를 기록합니다.\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",
        "### Hamlib에서 해밀토니안 회로 불러오기\n",
        "\n",
        "Benchpress 저장소에서 대표적인 해밀토니안 집합을 불러와 회로를 구성합니다 `PauliEvolutionGate` . 백엔드의 큐비트 수를 초과하는 회로와, 분해된 크기가 1,500 게이트를 초과하는 회로는 (트랜스필레이션 시간을 적정 수준으로 유지하기 위해) 제거됩니다.\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": [
        "회로를 소규모(20 큐비트 미만) 그룹과 대규모(20 큐비트 이상) 그룹으로 나눕니다.\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": [
        "변환 처리 전에 소규모 해밀턴 회로 중 하나를 미리 살펴보세요.\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",
        "## 소규모 예시\n",
        "\n",
        "이 절에서는 20 큐비트 미만의 해밀토니안 회로를 대상으로 세 가지 컴파일링 방법에 대한 벤치마크를 수행한다. 이 회로들은 빠르게 트랜스파일되며, 각 메서드가 중간 정도의 복잡성을 가진 회로를 어떻게 처리하는지 명확하게 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4d5e6f7",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### 1단계: 고전적 입력을 양자 문제에 매핑하기\n",
        "\n",
        "각 해밀토니안은 회로로 `PauliEvolutionGate` 인코딩됩니다. 이 회로들은 Hamlib 벤치마크 데이터를 바탕으로 설정 섹션에서 이미 구축되어 있었습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d4e5f6a7",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### 2단계: 양자 하드웨어 실행을 위한 문제 최적화\n",
        "\n",
        "우리는 세 가지 패스 관리자를 각각 사용하여 모든 소규모 회로를 트랜스파일한 다음, 메트릭을 수집합니다.\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": [
        "아래 표는 모든 소규모 회로에 대한 각 지표의 평균과 표준편차, 그리고 SABRE 대비 개선율을 요약한 것입니다. 회로 크기가 매우 다양하기 때문에, 표준편차는 평균값을 해석하는 데 중요한 맥락을 제공합니다.\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": [
        "회로별 표는 개별 회로에서 각 방식의 성능을 비교한 결과를 보여줍니다. 각 지표별 최고 수치는 별표로 표시되어 있습니다. 가장 간단한 회로의 경우, 세 가지 방법 모두 종종 동일한 결과로 수렴한다는 점에 유의하십시오.\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",
        "#### 결과 시각화\n",
        "\n",
        "아래 그래프는 회로별로 각 평가 지표를 기준으로 세 가지 방법을 비교한 것입니다. 여러 회로가 동일한 큐비트 수를 가질 수 있으므로, 회로는 큐비트 수에 따라 정렬되며 x축의 인덱스로 표시됩니다.\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": [
        "이 규모에서는 세 명의 패스 매니저 모두 좋은 성과를 보였으며, 그들의 평균 성적은 서로 비슷합니다. 이는 주로 회로 규모가 작을수록 추가적인 최적화를 위한 여지가 제한적이기 때문에, 해당 방법들이 유사한 해로 수렴하는 경향이 있기 때문이다.\n",
        "\n",
        "이 예시에서 Rustiq는 가장 큰 변동성을 보이며, 2-큐비트 깊이와 게이트 수 모두에서 가장 큰 이상치를 기록합니다. 이러한 변동성 때문에 때로는 뒤처지기도 하지만, 동시에 Rustiq가 다른 두 방법보다 더 나은 해결책을 찾아내기도 한다는 뜻이기도 합니다. AI 트랜스파일러는 SABRE 및 Rustiq에 비해 결과의 안정성이 더 뛰어나며, 대부분의 회로에서 큰 편차 없이 유사한 결과를 보여줍니다.\n",
        "\n",
        "실행 속도 면에서 SABRE와 Rustiq는 모두 빠르지만, AI 기반 트랜스파일러는 특정 회로에서 눈에 띄게 느립니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e5f6a7b8",
      "metadata": {},
      "source": [
        "<span id=\"best-performing-method-by-metric\" />\n",
        "\n",
        "#### 지표별 최우수 성과 방법\n",
        "\n",
        "아래 차트는 각 지표별로 각 방법이 최상의(가장 낮은) 값을 달성한 빈도를 보여줍니다. 동등한 결과가 나올 수 있습니다: 더 단순한 회로의 경우, 여러 가지 방법이 동일한 최적의 2-큐비트 깊이 또는 게이트 수에 도달할 수 있습니다. 동점이 발생할 경우, 동점을 기록한 모든 메서드가 점수를 받기 때문에 특정 지표의 백분율 합계가 100%를 초과할 수 있습니다.\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": [
        "이 예시에서, 세 가지 방법은 소규모 회로에서 매우 유사한 성능을 보입니다. 2-큐비트 회로의 깊이와 게이트 수를 기준으로 볼 때, 각 방법이 최상의 성능을 보이는 회로의 비율은 비슷하며(대략 35\\~55%), 가장 단순한 회로의 경우 여러 방법이 동일한 최적 해를 찾아내는 경우가 많아 많은 회로에서 동률을 기록한다. 가장 뚜렷한 차이점은 실행 시간입니다. SABRE와 Rustiq는 각각 약 절반 정도의 회로에서 가장 빠른 속도를 보이는 반면, AI 기반 트랜스파일러가 가장 빠른 경우는 거의 없습니다. 세 가지 지표를 종합적으로 고려할 때, Rustiq가 전반적으로 약간 우위를 점하고 있다. 2-큐비트 깊이 부문에서는 가장 높은 승률을 기록하고 있으며, 게이트 수와 실행 시간 부문에서도 경쟁력을 유지하고 있다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6c7d8e9",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### 3단계: `Qiskit primitives` 명령어로 실행합니다\n",
        "\n",
        "트랜스필레이션 품질이 노이즈 조건 하에서 실행에 어떤 영향을 미치는지 평가하기 위해, **미러 회로** 기법을 사용합니다. 트랜스파일된 각 회로 $U$ 에 대해, 그 역회로 $U^\\dagger$ 를 뒤에 덧붙이면, 결합된 회로 $U^\\dagger U$ 는 이론적으로 항등 회로가 된다. $|0\\rangle$ 상태에서 시작할 때, 완벽한(잡음이 없는) 실행은 확률 1로 모두 0인 비트열을 반환할 것이다.\n",
        "\n",
        "실제로는 게이트 오류가 회로 전반에 걸쳐 누적되기 때문에, $|0\\rangle^{\\otimes n}$ 를 복구할 확률이 떨어집니다. 게이트 수가 적고 회로 깊이가 얕은 회로를 생성하는 합성 방식은 노이즈가 덜 발생합니다.\n",
        "\n",
        "미러 회로 방식은 예상 출력이 항상 $|0\\rangle^{\\otimes n}$ 이므로 매우 간단할 뿐만 아니라 어떤 규모의 회로에도 적용할 수 있으며, 이상적인 상태에 대한 고전적 시뮬레이션이 필요하지 않습니다. 다만, 다음 사항에 유의해야 합니다. 미러 회로는 실제 회로를 대리하는 것일 뿐(실제 회로 그 자체가 아님)이며, 게이트 수를 두 배로 늘려(이로 인해 노이즈의 영향이 과장됨) 미러 경계를 가로질러 노이즈가 대칭적으로 상쇄될 경우 특정 오류를 과소평가할 수 있습니다.\n",
        "\n",
        "소규모 집합에서 회로 인덱스 6을 선택하고, 간단한 탈편광 잡음 모델을 적용한 Aer 시뮬레이터에서 미러 회로를 실행합니다.\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": [
        "미러 회로를 구축하고( $U^\\dagger$ 를 추가), 시뮬레이터가 활성 큐비트만 처리하도록 연속적인 큐비트 인덱스로 재매핑한 다음, 노이즈가 있는 Aer 시뮬레이터에서 실행합니다.\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",
        "#### 관측값\n",
        "\n",
        "2-큐비트 깊이가 가장 낮고 게이트 수가 가장 적은 방법이 가장 높은 충실도를 달성하는데, 이는 회로 길이가 짧을수록 노이즈가 덜 축적된다는 예상과 일치한다. 탈분극 잡음 모델 하에서는 깊이와 게이트 수의 미세한 차이조차도 재현도에 측정 가능한 차이로 나타납니다.\n",
        "\n",
        "이 결과는 단일 회로에 대한 것임을 유의하시기 바랍니다. 해밀토니안 구조에 따라 회로마다 각 방법의 상대적 순위가 달라질 수 있다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-large-scale",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 대규모 하드웨어 예시\n",
        "\n",
        "이 절에서는 20개 이상의 큐비트로 구성된 해밀토니안 회로를 대상으로, 앞서 소개한 세 가지 컴파일링 방법에 대한 벤치마크를 수행합니다. 이러한 회로들은 실제 해밀턴 연산 시뮬레이션 워크로드를 더 잘 반영하며, 각 방법이 회로 품질 및 컴파일 시간 측면에서 어떻게 확장성을 보이는지 테스트합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6a7b8c9",
      "metadata": {},
      "source": [
        "<span id=\"steps-1-4-combined\" />\n",
        "\n",
        "### 1\\~4단계 통합\n",
        "\n",
        "이 워크플로는 소규모 예제와 동일한 구조를 따릅니다. 우리는 각 방법을 사용하여 모든 대규모 회로를 트랜스파일하고, 메트릭을 수집한 뒤, 미러 회로를 실제 양자 하드웨어에 제출합니다.\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",
        "## 컴파일 결과 분석\n",
        "\n",
        "위의 벤치마크는 AI 기반 트랜스파일러인 SABRE와 Rustiq를 Hamlib 컬렉션에 포함된 해밀토니안 시뮬레이션 회로에서 소규모 및 대규모로 비교한 결과입니다.\n",
        "\n",
        "<span id=\"two-qubit-depth-and-gate-count\" />\n",
        "\n",
        "### 2-큐비트 처리 깊이와 게이트 수\n",
        "\n",
        "전반적으로 볼 때, SABRE와 AI 기반 트랜스파일러가 가장 뛰어난 성능을 보였으며, 각각 서로 다른 평가 지표에서 선두를 차지했습니다. *지표* 차트에서 볼 수 있듯이, SABRE는 대다수의 회로에서 게이트 수가 가장 적게 나오며 거의 모든 회로에서 가장 빠른 방법을 보여줍니다. 이는 삽입된 SWAP 게이트를 최소화하도록 설계된 휴리스틱과, 최근 이루어진 레이아웃 및 라우팅 최적화 결과와 일치합니다. 이 AI 기반 트랜스파일러는 대부분의 회로에서 가장 낮은 2-큐비트 깊이를 산출하며, 이는 회로 깊이를 목표로 하는 강화 학습 목표의 일부와 일치한다. 요약 표에서도 동일한 경향이 나타납니다. SABRE는 평균 게이트 수가 더 적은 반면, AI 트랜스파일러는 평균 2-큐비트 깊이가 더 낮습니다. 두 방법 모두 모든 회로 범위에 걸쳐 일관되고 신뢰할 수 있습니다.\n",
        "\n",
        "합성을 위해 `PauliEvolutionGate` 특별히 설계된 Rustiq는 대규모 회로 중 극히 일부에서만 가장 뛰어난 결과를 보여줍니다. 이 방법의 평균 지표는 소수의 현저한 이상치에 의해 크게 왜곡되어 있으며, 이는 컴파일 비교 그래프에서 큰 급등 형태로 나타납니다. 이 그래프에서 Rustiq는 다른 방법들에 비해 훨씬 더 높은 심도와 게이트 수를 보여줍니다. 이러한 특이값을 제외하면, 이 알고리즘의 평균 성능은 SABRE 및 AI 기반 트랜스파일러의 성능에 훨씬 더 가까워질 것입니다.\n",
        "\n",
        "핵심적인 점은 어떤 단일 방법도 모든 회로에서 압도적인 우위를 차지하지 않는다는 것이다. 각 방법은 특정 상황에서 다른 방법들보다 뛰어난 성능을 보이기 때문에, 사용 가능한 모든 도구를 시도해 보고 각 회로에 가장 적합한 결과를 선택하는 것이 좋습니다.\n",
        "\n",
        "<span id=\"runtime\" />\n",
        "\n",
        "### 런타임\n",
        "\n",
        "SABRE는 언제나 가장 빠른 방법입니다. Rustiq는 대체로 비슷한 속도로 실행되지만, 컴파일 시간이 현저히 더 오래 걸리는 예외적인 경우가 발생할 수 있습니다. 이는 대규모 테스트 결과에서 특히 두드러지는데, 소수의 회로로 인해 Rustiq의 실행 시간이 급증하는 현상이 나타납니다. 이러한 이상값들은 평균 실행 시간에 큰 영향을 미치므로, Rustiq의 경우 중앙값이 더 대표적인 요약 지표가 될 수 있습니다. AI 기반 트랜스파일러는 세 가지 중 가장 속도가 느리며, 회로가 더 크고 복잡해질수록 실행 시간이 눈에 띄게 늘어납니다.\n",
        "\n",
        "<span id=\"mirror-circuit-results\" />\n",
        "\n",
        "### 미러 회로 결과\n",
        "\n",
        "미러 회로 실험 결과, 예상된 경향을 확인했다. 즉, 2-큐비트 깊이가 더 낮고 게이트 수가 더 적은 방식일수록 잡음 조건에서 더 높은 충실도를 달성한다. 이는 노이즈가 많은 시뮬레이터(소규모)와 실제 하드웨어(대규모) 모두에서 성립합니다.\n",
        "\n",
        "각 미러 회로 그래프는 전체가 아닌 단일 회로를 나타낸다는 점을 유의하시기 바랍니다. 위의 하드웨어 예제에서는 26-큐비트 `tfim` 회로 하나를 사용하는데, 이 경우 SABRE가 AI 기반 트랜스파일러나 Rustiq보다 훨씬 더 높은 2-큐비트 깊이를 산출하므로, 그에 따라 충실도도 훨씬 더 낮습니다. 이는 전체적인 결과를 대표하지는 않습니다. 대규모 회로 전체를 살펴보면, SABRE의 2-큐비트 깊이는 대개 AI 기반 트랜스파일러의 2-큐비트 깊이와 비슷한 수준이며, 두 방법은 각기 다른 평가 지표에서 우위를 보입니다(AI 기반 트랜스파일러는 2-큐비트 깊이에서, SABRE는 게이트 수와 실행 시간에서 우위를 보입니다). 단일 미러 결과는 전체 워크로드가 아닌 특정 회로의 두 배 규모 버전을 테스트하는 것이므로, 이를 전체적인 방법의 품질에 대한 최종 평가로 해석해서는 안 됩니다.\n",
        "\n",
        "<span id=\"recommendations\" />\n",
        "\n",
        "### 권장사항\n",
        "\n",
        "모든 회로에 적용할 수 있는 단 하나의 최상의 트랜스파일레이션 전략은 존재하지 않습니다. 가장 적합한 선택은 회로 구조, 최적화 목표, 그리고 할당된 컴파일 시간에 따라 달라집니다:\n",
        "\n",
        "* **SABRE를** 기본값으로 권장합니다. 이 제품은 빠르고 신뢰할 수 있으며, 다양한 회로에서 뛰어난 성능을 발휘합니다. 더 세밀한 조정을 위해 사용자는 레이아웃 및 라우팅 시뮬레이션 횟수를 늘릴 수 있습니다( [SABRE 최적화 튜토리얼](/docs/tutorials/transpilation-optimizations-with-sabre) 참조).\n",
        "* 컴파일 시간이 제약 요인이 아닐 때, 특히 2-큐비트 깊이를 최소화하는 것이 최우선 과제일 때는 **AI 기반 트랜스파일러를** 사용해 볼 가치가 있습니다. 이 벤치마크에서 테스트된 대부분의 대규모 회로에서 이 트랜스파일러가 가장 낮은 2-큐비트 깊이를 기록했습니다.\n",
        "* **Rustiq는** 회로 설계에 `PauliEvolutionGate` 특화되어 있으며, 특히 소규모 회로에서 매우 낮은 설계 복잡도와 적은 게이트 수를 가진 솔루션을 찾아낼 수 있습니다. 더 큰 회로의 경우 때때로 훨씬 더 큰 결과가 나올 수 있으므로, 이 방법을 기본 설정으로 삼기보다는 여러 가지 시도해 볼 방법 중 하나로 사용하는 것이 가장 좋습니다.\n",
        "\n",
        "실제로는 사용 가능한 모든 방법을 실행한 뒤, 각 회로에 대해 가장 좋은 결과를 선택하는 것이 가장 좋은 방법입니다. 실제 하드웨어에서 실행 성능이 향상될 수 있는 잠재적 이점에 비하면, 여러 방법을 시도하는 데 드는 컴파일 오버헤드는 미미한 수준입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-next-steps",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "이 튜토리얼이 도움이 되셨다면, 다음 내용에도 관심이 있으실 수 있습니다:\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * [SABRE를 활용한 트랜스파일레이션 최적화](/docs/tutorials/transpilation-optimizations-with-sabre)\n",
        "  * [AI 기반 트랜스파일러가 통과함](/docs/guides/ai-transpiler-passes)\n",
        "  * [트랜스파일러 플러그인 만들기](/docs/guides/create-transpiler-plugin)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sec-references",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## 참조\n",
        "\n",
        "\\[1] \"LightSABRE: \"가볍고 향상된 사브레 알고리즘\". 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] \"강화 학습을 통한 실용적이고 효율적인 양자 회로 합성 및 트랜스파일링\". 박사 크레머, V. 빌라, H. 백, I. 듀란, I. 파로, J. 크루즈- 베니토 외. [https://arxiv.org/abs/2405.13196](https://arxiv.org/abs/2405.13196)\n",
        "\n",
        "\\[3]. “강화 학습을 활용한 파울리 네트워크 회로 합성”. A. Dubal, D. Kremer, S. Martiel, V. Villar, D. Wang, J. Cruz-Benito 외. [https://arxiv.org/abs/2503.14448](https://arxiv.org/abs/2503.14448)\n",
        "\n",
        "\\[4] “해밀턴 시뮬레이션 회로의 더 빠르고 간결한 합성”. T. Goubault de Brugiere, S. Martiel 외 [ 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
}