{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "meta-header",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Qiskit AI搭載トランスパイラーの紹介\"\n",
        "description: \"AIを活用したトランスパイラーが、ミラー回路を用いた標準的なトランスパイレーションとどのように異なるかについて解説します。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize fontweight steelblue AITI */}\n",
        "\n",
        "<span id=\"qiskit-ai-powered-transpiler-introduction\" />\n",
        "\n",
        "# Qiskit AI搭載トランスパイラーの紹介\n",
        "\n",
        "*所要時間の目安： IBM Heron で 5 分（注：これはあくまで目安です。 （実行時間は状況によって異なる場合があります。）*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "learning-outcomes",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "このチュートリアルを学習した後、ユーザーは以下の点を理解できるようになります：\n",
        "\n",
        "* 標準のトランスパイラーの代替として、AI搭載トランスパイラー（`generate_ai_pass_manager`）を使用する方法\n",
        "* AIを活用したトランスパイラーとデフォルトのトランスパイラーを、2量子ビットの深さ、ゲート数、およびトランスパイレーション時間の観点から比較した結果\n",
        "* ミラー回路を用いて、ハードウェア実行を通じてトランスパイレーションの品質を評価する方法\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "このチュートリアルを進める前に、以下のトピックについてあらかじめ理解しておいていただくことをお勧めします：\n",
        "\n",
        "* [回路のトランスパイル](/docs/guides/transpile)\n",
        "* [プリセット・パスマネージャーの設定](/docs/guides/transpile-with-pass-managers)\n",
        "* [AIを活用したトランスパイラーが合格](/docs/guides/ai-transpiler-passes)\n",
        "\n",
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "**QiskitのAIを活用したトランスパイラー** は、機械学習に基づくトランスパイレーション・パスを導入しており、SABREなどの従来のヒューリスティック手法よりも、より短く、ハードウェア効率の高い回路を生成することができます。 回路が短いほどノイズの蓄積が少なくなり、これにより実際の量子ハードウェア上での結果の品質が直接向上します。\n",
        "\n",
        "このチュートリアルでは、2つのトランスパイル戦略を比較します：\n",
        "\n",
        "| 戦略        | API                                                                            |\n",
        "| --------- | ------------------------------------------------------------------------------ |\n",
        "| **デフォルト** | `generate_preset_pass_manager(optimization_level=3, ...)`                      |\n",
        "| **AI**    | `generate_ai_pass_manager(optimization_level=1, ai_optimization_level=3, ...)` |\n",
        "\n",
        "各戦略について、3つの指標を測定しています。それは、 **2量子ビットゲートの深さ**、 **総ゲート数**、および**トランスパイレーションの実行時間です**。\n",
        "\n",
        "<span id=\"ai-powered-transpiler-benchmarks\" />\n",
        "\n",
        "### AIを活用したトランスパイラーのベンチマーク\n",
        "\n",
        "ベンチマークテストにおいて、AIを活用したトランスパイラーは、標準のQiskitトランスパイラーと比較して、一貫してより浅く、高品質な回路を生成した。 [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager)これらのテストでは、Qiskitのデフォルトのパスマネージャー戦略を使用し、次のように設定しました。 このデフォルトの戦略は多くの場合有効ですが、規模が大きい、あるいは複雑な回路ではうまく機能しないことがあります。 対照的に、 IBM Quantum® ハードウェアの「heavy-hex」トポロジーへトランスパイルした場合、AIを活用したパスでは、大規模回路（100クビット以上）において、2クビットゲート数を平均24％削減し、回路の深さを36％削減することに成功した。 これらのベンチマークに関する詳細については、こちらの[ブログ](https://www.ibm.com/quantum/blog/qiskit-performance)をご覧ください。\n",
        "\n",
        "![AIを活用したトランスパイラーのベンチマーク](https://quantum.cloud.ibm.com/docs/images/tutorials/ai-transpiler-introduction/ai-transpiler-benchmarks.avif)\n",
        "\n",
        "このチュートリアルでは、AIパスがもたらす主なメリットと、従来の方法との違いについて解説します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "requirements",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskit SDK v2.0 またはそれ以降のバージョンで、 [可視化](/docs/api/qiskit/visualization)機能をサポートしたもの\n",
        "* Qiskit Runtime (`pip install qiskit-ibm-runtime`) v0.22 以降\n",
        "* Qiskitの IBM トランスパイラー（AIローカルモード対応） (`pip install 'qiskit-ibm-transpiler[ai-local-mode]'`)\n",
        "* Qiskit Aer (`pip install qiskit-aer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "setup-header",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "setup-code",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.circuit.random import random_circuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit_ibm_transpiler import generate_ai_pass_manager\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel, depolarizing_error\n",
        "import matplotlib.pyplot as plt\n",
        "from statistics import mean, stdev\n",
        "import time\n",
        "import logging\n",
        "\n",
        "seed = 42\n",
        "\n",
        "\n",
        "def transpile_with_metrics(pass_manager, circuit):\n",
        "    \"\"\"Transpile a circuit and return the result along with key metrics.\"\"\"\n",
        "    start = time.time()\n",
        "    qc_out = pass_manager.run(circuit)\n",
        "    elapsed = time.time() - start\n",
        "\n",
        "    depth_2q = qc_out.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    gate_count = qc_out.size()\n",
        "\n",
        "    return qc_out, {\n",
        "        \"depth_2q\": depth_2q,\n",
        "        \"gate_count\": gate_count,\n",
        "        \"time_s\": round(elapsed, 3),\n",
        "    }\n",
        "\n",
        "\n",
        "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",
        "    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, simulate=True):\n",
        "    \"\"\"Build a mirror circuit: U followed by U-dagger, with measurements.\n",
        "\n",
        "    The expected output is always |0...0>, so measuring the survival\n",
        "    probability reveals how much noise each transpilation strategy adds.\n",
        "\n",
        "    Args:\n",
        "        tqc: A transpiled circuit.\n",
        "        simulate: If True (default), remap to contiguous qubits so Aer\n",
        "            only simulates the active qubits. If False, keep the full\n",
        "            physical layout for hardware execution.\"\"\"\n",
        "    if simulate:\n",
        "        tqc = remap_to_contiguous(tqc)\n",
        "    mirror = tqc.compose(tqc.inverse())\n",
        "    mirror.measure_all()\n",
        "    return mirror\n",
        "\n",
        "\n",
        "def print_summary(results):\n",
        "    \"\"\"Print a summary of each metric as mean +/- stdev across all circuits,\n",
        "    along with the mean percentage improvement of AI over Default.\"\"\"\n",
        "    metrics = [\n",
        "        (\"Depth 2Q\", \"Depth 2Q (Default)\", \"Depth 2Q (AI)\"),\n",
        "        (\"Gate Count\", \"Gate Count (Default)\", \"Gate Count (AI)\"),\n",
        "        (\"Time (s)\", \"Time (Default)\", \"Time (AI)\"),\n",
        "    ]\n",
        "    header = (\n",
        "        f\"{'Metric':<12}{'Default (mean +/- std)':>24}\"\n",
        "        f\"{'AI (mean +/- std)':>22}{'AI % improvement':>22}\"\n",
        "    )\n",
        "    print(header)\n",
        "    print(\"-\" * len(header))\n",
        "    for label, col_def, col_ai in metrics:\n",
        "        defaults = [r[col_def] for r in results]\n",
        "        ais = [r[col_ai] for r in results]\n",
        "        pct = [(d - a) / d * 100 for d, a in zip(defaults, ais)]\n",
        "        default_str = f\"{mean(defaults):.1f} +/- {stdev(defaults):.1f}\"\n",
        "        ai_str = f\"{mean(ais):.1f} +/- {stdev(ais):.1f}\"\n",
        "        pct_str = f\"{mean(pct):+.1f}% +/- {stdev(pct):.1f}%\"\n",
        "        print(f\"{label:<12}{default_str:>24}{ai_str:>22}{pct_str:>22}\")\n",
        "\n",
        "\n",
        "def plot_metrics_and_pct(results, title_prefix):\n",
        "    \"\"\"Plot metric comparisons and percentage improvement of AI over Default.\"\"\"\n",
        "    qubits = [r[\"Qubits\"] for r in results]\n",
        "    metrics = [\n",
        "        (\"Depth 2Q (Default)\", \"Depth 2Q (AI)\", \"Two-Qubit Depth\"),\n",
        "        (\"Gate Count (Default)\", \"Gate Count (AI)\", \"Gate Count\"),\n",
        "        (\"Time (Default)\", \"Time (AI)\", \"Transpilation Time\"),\n",
        "    ]\n",
        "\n",
        "    # Row 1: raw metric comparison\n",
        "    fig, axs = plt.subplots(1, 3, figsize=(21, 5))\n",
        "    fig.suptitle(\n",
        "        f\"{title_prefix}: Metric Comparison\",\n",
        "        fontsize=15,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "    for ax, (col_def, col_ai, label) in zip(axs, metrics):\n",
        "        ax.plot(qubits, [r[col_def] for r in results], \"o-\", label=\"Default\")\n",
        "        ax.plot(qubits, [r[col_ai] for r in results], \"s-\", label=\"AI\")\n",
        "        ax.set_title(label)\n",
        "        ax.set_xlabel(\"Number of Qubits\")\n",
        "        ax.set_ylabel(label)\n",
        "        ax.legend()\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "    # Row 2: percentage improvement\n",
        "    fig, axs = plt.subplots(1, 3, figsize=(21, 5))\n",
        "    fig.suptitle(\n",
        "        f\"{title_prefix}: % Improvement of AI over Default\",\n",
        "        fontsize=15,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "    for ax, (col_def, col_ai, label) in zip(axs, metrics):\n",
        "        pct = [(r[col_def] - r[col_ai]) / r[col_def] * 100 for r in results]\n",
        "        ax.axhline(\n",
        "            0, color=\"#1f77b4\", linewidth=2, label=\"Default (baseline)\"\n",
        "        )\n",
        "        ax.plot(qubits, pct, \"s-\", color=\"#ff7f0e\", label=\"AI\")\n",
        "        ax.fill_between(qubits, 0, pct, alpha=0.15, color=\"#ff7f0e\")\n",
        "        ax.set_title(label)\n",
        "        ax.set_xlabel(\"Number of Qubits\")\n",
        "        ax.set_ylabel(\"% Improvement\")\n",
        "        ax.legend()\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "# Suppress verbose AI-powered transpiler logs\n",
        "logging.getLogger(\n",
        "    \"qiskit_ibm_transpiler.wrappers.ai_local_synthesis\"\n",
        ").setLevel(logging.WARNING)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-header",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 小規模シミュレータの例\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step1-header",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題にマッピングする\n",
        "\n",
        "深さ4のランダムな回路を20個生成し、そのクビット数は6から25の範囲となる。 これらの回路は、トランスパイラ戦略を比較するためのテストケースとして活用します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "sim-step1-code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Created 20 circuits with qubit counts from 6 to 25\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step1-code-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_circuits_sim = 20\n",
        "depth_sim = 4\n",
        "qubit_range_sim = list(range(6, 26))\n",
        "\n",
        "circuits_sim = [\n",
        "    # We have only two qubit gates, as those test how well the\n",
        "    # transpiler can optimize the circuit.\n",
        "    random_circuit(\n",
        "        num_qubits=n,\n",
        "        depth=depth_sim,\n",
        "        max_operands=2,\n",
        "        num_operand_distribution={2: 1},\n",
        "        seed=seed + i,\n",
        "    )\n",
        "    for i, n in enumerate(qubit_range_sim)\n",
        "]\n",
        "\n",
        "print(\n",
        "    f\"Created {len(circuits_sim)} circuits with qubit counts \"\n",
        "    f\"from {qubit_range_sim[0]} to {qubit_range_sim[-1]}\"\n",
        ")\n",
        "circuits_sim[0].draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-header",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ2：量子ハードウェア実行に向けた問題の最適化\n",
        "\n",
        "選択したバックエンド用のデフォルト（SABRE）パスマネージャーを構築します。 どちらのトランスパイレーション戦略も、バックエンドの完全な結合マップを対象としています。 シミュレーションステップでは、トランスパイルされた各回路をアクティブな量子ビットのみに再ラベル付けするため `remap_to_contiguous` 、Aerはデバイス全体ではなく、それらの量子ビットのみをシミュレートすることになり、局所シミュレーションはその後も処理可能な範囲に収まる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "sim-step2-backend",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    min_num_qubits=100, operational=True, simulator=False\n",
        ")\n",
        "\n",
        "\n",
        "pm_default_sim = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    seed_transpiler=seed,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "sim-step2-transpile",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "bc06de12e386408abf67166416c2d1a0",
              "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": [
            "Metric        Default (mean +/- std)     AI (mean +/- std)      AI % improvement\n",
            "--------------------------------------------------------------------------------\n",
            "Depth 2Q               33.0 +/- 12.9          26.4 +/- 8.0      +15.8% +/- 17.6%\n",
            "Gate Count           522.0 +/- 266.0       560.5 +/- 279.1        -9.0% +/- 9.0%\n",
            "Time (s)                 0.0 +/- 0.0           0.2 +/- 0.1    -893.6% +/- 362.9%\n"
          ]
        }
      ],
      "source": [
        "results_sim = []\n",
        "\n",
        "for i, qc in enumerate(circuits_sim):\n",
        "    n = qubit_range_sim[i]\n",
        "\n",
        "    qc_default, m_default = transpile_with_metrics(pm_default_sim, qc)\n",
        "\n",
        "    # Create a fresh AI pass manager each iteration to avoid stale layout state\n",
        "    pm_ai = generate_ai_pass_manager(\n",
        "        optimization_level=1,\n",
        "        ai_optimization_level=3,\n",
        "        backend=backend,\n",
        "    )\n",
        "    qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)\n",
        "\n",
        "    results_sim.append(\n",
        "        {\n",
        "            \"Qubits\": n,\n",
        "            \"Depth 2Q (Default)\": m_default[\"depth_2q\"],\n",
        "            \"Depth 2Q (AI)\": m_ai[\"depth_2q\"],\n",
        "            \"Gate Count (Default)\": m_default[\"gate_count\"],\n",
        "            \"Gate Count (AI)\": m_ai[\"gate_count\"],\n",
        "            \"Time (Default)\": m_default[\"time_s\"],\n",
        "            \"Time (AI)\": m_ai[\"time_s\"],\n",
        "        }\n",
        "    )\n",
        "\n",
        "print_summary(results_sim)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-table-note",
      "metadata": {},
      "source": [
        "この要約表には、全20の回路における各指標の平均値と標準偏差、およびデフォルト設定と比較したAI搭載トランスパイラーの平均改善率（パーセント）が示されています。 正の値は、AIを活用したトランスパイラーの方がより良い結果を出したことを示し、負の値はデフォルトの方が優れていたことを示します。\n",
        "\n",
        "この小規模な例では、AIを活用したトランスパイラーは、平均して2量子ビットの深さを約16％低減していますが、その代償としてゲート数が約9％増加しています。 これは、2つの戦略のどちらを選ぶかという際に生じる重要なトレードオフを浮き彫りにしています。つまり、AIを活用したトランスパイラーは深さの削減（2量子ビットゲートの連続した層の数を減らすこと）を優先するのに対し、デフォルトのトランスパイラー（SABRE）は総ゲート数の最小化（SWAPの挿入回数を減らすこと）を優先するのです。 用途によっては、ある指標がもう一方の指標よりも重要になる場合があります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "sim-step2-plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step2-plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step2-plot-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_metrics_and_pct(results_sim, \"Small-Scale Random Circuits\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-analysis",
      "metadata": {},
      "source": [
        "**2量子ビット深度：** AIを活用したトランスパイラーは、一般的に2量子ビット深度が低い回路を生成します。 深度は、AIルーティングモデルが最適化するように学習された主要な指標の一つであり、その改善効果はほとんどの回路規模で確認できますが、個々の回路においてはSABREが同等の性能を示すか、あるいはそれを上回っています。\n",
        "\n",
        "**ゲート数：** この規模では両者の結果は拮抗しており、全体としてはSABREがわずかにリードしている。 SABREのルーティングヒューリスティックは、挿入されるSWAPゲートの数を最小限に抑えるように設計されており、これによりゲート数が直接削減されます。 回路の規模が小さい場合、その差はさほど大きくありません。\n",
        "\n",
        "**トランスパイレーション時間：** SABREの実行時間は量子ビット数にかかわらずほぼ一定であるため、この規模では回路の大きさがトランスパイレーション時間に与える影響はほとんどない。 SABREの中核となるルーティングロジックは高度に最適化されています（その大部分はRustで実装されています）。 AIを活用したトランスパイラーは、処理に明らかに時間がかかり、回路の規模に応じて処理時間も増加しますが、絶対的な処理時間はインタラクティブな使用には十分な範囲内に収まっています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step3-header",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ3: `Qiskit primitives`を使用して実行する\n",
        "\n",
        "トランスピレーションが回路の忠実度に与える影響を評価するため、10量子ビットのケースに基づいてミラー回路を構築し、単純なノイズモデルを用いてAerシミュレータ上で実行する。 ミラー回路の期待出力は常に全ビットがゼロのビット列であるため、 $|0\\rangle^{\\otimes n}$ が測定される確率は、各トランスピレーション戦略が忠実度をどの程度維持できているかを示す指標となります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "sim-step3-code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default: depth 84, gates 280\n",
            "AI:      depth 91, gates 343\n"
          ]
        }
      ],
      "source": [
        "# Use the 10-qubit circuit (index where qubits == 10)\n",
        "idx_10q = qubit_range_sim.index(10)\n",
        "\n",
        "qc_10q = circuits_sim[idx_10q]\n",
        "qc_default_10q, _ = transpile_with_metrics(pm_default_sim, qc_10q)\n",
        "\n",
        "pm_ai = generate_ai_pass_manager(\n",
        "    optimization_level=1,\n",
        "    ai_optimization_level=3,\n",
        "    backend=backend,\n",
        ")\n",
        "qc_ai_10q, _ = transpile_with_metrics(pm_ai, qc_10q)\n",
        "\n",
        "tqc_methods = {\n",
        "    \"Default\": qc_default_10q,\n",
        "    \"AI\": qc_ai_10q,\n",
        "}\n",
        "\n",
        "print(\n",
        "    f\"Default: depth {qc_default_10q.depth()}, gates {qc_default_10q.size()}\"\n",
        ")\n",
        "print(f\"AI:      depth {qc_ai_10q.depth()}, gates {qc_ai_10q.size()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "sim-step3-run",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default   P(|00...0>) = 0.8460  (8460/10000)\n",
            "AI        P(|00...0>) = 0.8121  (8121/10000)\n"
          ]
        }
      ],
      "source": [
        "# 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",
        "survival_probs = {}\n",
        "\n",
        "for method, tqc in tqc_methods.items():\n",
        "    mirror = build_mirror_circuit(tqc, simulate=True)\n",
        "\n",
        "    sampler = SamplerV2(mode=aer_sim)\n",
        "    job = sampler.run([mirror], shots=shots)\n",
        "    counts = job.result()[0].data.meas.get_counts()\n",
        "\n",
        "    all_zeros = \"0\" * mirror.num_qubits\n",
        "    survival = counts.get(all_zeros, 0) / shots\n",
        "    survival_probs[method] = survival\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {survival:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots})\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step3-analysis",
      "metadata": {},
      "source": [
        "両方のミラー回路について、単純な偏光消去ノイズモデルを用いてAerシミュレータでシミュレーションを行いました。 「生存確率」とは、ビット列がすべてゼロとなるショットが占める割合として定義され、各トランスパイレーション戦略がどの程度のノイズをもたらすかを定量的に示す指標である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step4-header",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、結果を希望の古典形式で返す\n",
        "\n",
        "両方のランから、すべてゼロのビット列が観測される確率を算出する。 生存確率が高いほど忠実度が高いことを示しており、つまり、トランスパイレーションによって生じたノイズが少なかったことを意味します。 以下のグラフは、補数である 1 - P(|0...0>) を示しています。下棒があるほど忠実度が高く、誤差のわずかな違いもより見やすくなります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "sim-step4-code",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step4-code-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.\n",
        "# A lower bar means the transpilation introduced less noise.\n",
        "error_probs = {method: 1 - p for method, p in survival_probs.items()}\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(6, 4))\n",
        "ax.bar(\n",
        "    error_probs.keys(),\n",
        "    error_probs.values(),\n",
        "    color=[\"steelblue\", \"coral\"],\n",
        ")\n",
        "ax.set_ylabel(\"1 - P(|0...0>)\")\n",
        "ax.set_title(\"Mirror Circuit Error (10-qubit, Aer Simulator)\")\n",
        "ax.set_ylim(0, 1)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step4-analysis",
      "metadata": {},
      "source": [
        "このケースでは、デフォルトのトランスパイラーがこの特定の10キュービットのインスタンスに対して、より浅く、かつより小さな回路を生成したため、その忠実度が高いと予想される。 回路ごとの結果はまちまちです。上記のまとめ表が示すように、AIを活用したトランスパイラーの利点は、個々の回路すべてにおいてではなく、平均して2量子ビットの深さが低いという点にあります。 どちらの戦略がより高い忠実度をもたらすかは、各指標における差異の大きさ、ハードウェアのノイズ特性、および回路の構造によって異なります。 均一な脱分極ノイズモデルのもとでは、蓄積エラーに対して、深さのみよりもゲート総数がより直接的な影響を与えることがよくあります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-header",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 大規模なハードウェアの例\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-steps-header",
      "metadata": {},
      "source": [
        "<span id=\"steps-1-4\" />\n",
        "\n",
        "### 手順 1～4\n",
        "\n",
        "ここでは、これらすべての詳細が、より大規模な明確なワークフローとして統合され、実際の量子ハードウェア上で実行されます。\n",
        "\n",
        "以下のコードは、深さ8のランダムな回路を25個生成します。クビット数は26から50の範囲です。 その後、これらの回路は両方の戦略を用いてトランスパイルされ、同じメトリクスが収集されます。 次に、26量子ビットのケースに基づいてミラー回路を構築し、実際のバックエンドに送信します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "hw-step1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Created 25 circuits with qubit counts from 26 to 50\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "num_circuits_hw = 25\n",
        "depth_hw = 8\n",
        "qubit_range_hw = list(range(26, 51))\n",
        "\n",
        "circuits_hw = [\n",
        "    # We have only two qubit gates, as those test how well the\n",
        "    # transpiler can optimize the circuit.\n",
        "    random_circuit(\n",
        "        num_qubits=n,\n",
        "        depth=depth_hw,\n",
        "        max_operands=2,\n",
        "        num_operand_distribution={2: 1},\n",
        "        seed=seed + i,\n",
        "    )\n",
        "    for i, n in enumerate(qubit_range_hw)\n",
        "]\n",
        "\n",
        "print(\n",
        "    f\"Created {len(circuits_hw)} circuits with qubit counts \"\n",
        "    f\"from {qubit_range_hw[0]} to {qubit_range_hw[-1]}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "hw-step2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Metric        Default (mean +/- std)     AI (mean +/- std)      AI % improvement\n",
            "--------------------------------------------------------------------------------\n",
            "Depth 2Q              217.4 +/- 50.4        191.0 +/- 35.6      +10.9% +/- 10.7%\n",
            "Gate Count         4513.3 +/- 1394.3     5227.1 +/- 1536.4       -16.4% +/- 5.8%\n",
            "Time (s)                 0.1 +/- 0.0           3.5 +/- 1.5   -3588.2% +/- 643.6%\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 2-------------------------\n",
        "pm_default = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    seed_transpiler=seed,\n",
        ")\n",
        "\n",
        "results_hw = []\n",
        "\n",
        "for i, qc in enumerate(circuits_hw):\n",
        "    n = qubit_range_hw[i]\n",
        "\n",
        "    qc_default, m_default = transpile_with_metrics(pm_default, qc)\n",
        "\n",
        "    # Create a fresh AI pass manager each iteration to avoid stale layout state\n",
        "    pm_ai = generate_ai_pass_manager(\n",
        "        optimization_level=1,\n",
        "        ai_optimization_level=3,\n",
        "        backend=backend,\n",
        "    )\n",
        "    qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)\n",
        "\n",
        "    results_hw.append(\n",
        "        {\n",
        "            \"Qubits\": n,\n",
        "            \"Depth 2Q (Default)\": m_default[\"depth_2q\"],\n",
        "            \"Depth 2Q (AI)\": m_ai[\"depth_2q\"],\n",
        "            \"Gate Count (Default)\": m_default[\"gate_count\"],\n",
        "            \"Gate Count (AI)\": m_ai[\"gate_count\"],\n",
        "            \"Time (Default)\": m_default[\"time_s\"],\n",
        "            \"Time (AI)\": m_ai[\"time_s\"],\n",
        "        }\n",
        "    )\n",
        "\n",
        "print_summary(results_hw)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "hw-step2-plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step2-plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step2-plot-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_metrics_and_pct(results_hw, \"Large-Scale Random Circuits\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "hw-step3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mirror circuit (Default): depth 1577, gates 9672\n",
            "Mirror circuit (AI):      depth 1235, gates 11092\n",
            "Job submitted: d8gt7vm6983c73dqbg0g\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 3-------------------------\n",
        "# Build mirror circuits from the 26-qubit case\n",
        "idx_26q = qubit_range_hw.index(26)\n",
        "\n",
        "qc_26q = circuits_hw[idx_26q]\n",
        "qc_default_26q, _ = transpile_with_metrics(pm_default, qc_26q)\n",
        "\n",
        "pm_ai = generate_ai_pass_manager(\n",
        "    optimization_level=1,\n",
        "    ai_optimization_level=3,\n",
        "    backend=backend,\n",
        ")\n",
        "qc_ai_26q, _ = transpile_with_metrics(pm_ai, qc_26q)\n",
        "\n",
        "mirror_default_hw = build_mirror_circuit(qc_default_26q, simulate=False)\n",
        "mirror_ai_hw = build_mirror_circuit(qc_ai_26q, simulate=False)\n",
        "\n",
        "# Re-transpile to basis gates (the inverse can introduce gates like sxdg)\n",
        "pm_basis = generate_preset_pass_manager(\n",
        "    optimization_level=0,\n",
        "    backend=backend,\n",
        ")\n",
        "mirror_default_hw = pm_basis.run(mirror_default_hw)\n",
        "mirror_ai_hw = pm_basis.run(mirror_ai_hw)\n",
        "\n",
        "print(\n",
        "    f\"Mirror circuit (Default): depth {mirror_default_hw.depth()}, \"\n",
        "    f\"gates {mirror_default_hw.size()}\"\n",
        ")\n",
        "print(\n",
        "    f\"Mirror circuit (AI):      depth {mirror_ai_hw.depth()}, \"\n",
        "    f\"gates {mirror_ai_hw.size()}\"\n",
        ")\n",
        "\n",
        "# Submit to real hardware\n",
        "sampler_hw = SamplerV2(mode=backend)\n",
        "sampler_hw.options.environment.job_tags = [\"TUT_AITI\"]\n",
        "\n",
        "shots_hw = 500000\n",
        "job_hw = sampler_hw.run([mirror_default_hw, mirror_ai_hw], shots=shots_hw)\n",
        "print(f\"Job submitted: {job_hw.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "hw-step4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default   P(|00...0>) = 0.0005  (239/500000)\n",
            "AI        P(|00...0>) = 0.0050  (2516/500000)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# -------------------------Step 4-------------------------\n",
        "result_hw = job_hw.result()\n",
        "\n",
        "survival_probs_hw = {}\n",
        "for i, method in enumerate([\"Default\", \"AI\"]):\n",
        "    counts = result_hw[i].data.meas.get_counts()\n",
        "    mirror = [mirror_default_hw, mirror_ai_hw][i]\n",
        "    all_zeros = \"0\" * mirror.num_qubits\n",
        "    survival = counts.get(all_zeros, 0) / shots_hw\n",
        "    survival_probs_hw[method] = survival\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {survival:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots_hw})\"\n",
        "    )\n",
        "\n",
        "# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.\n",
        "# A lower bar means the transpilation introduced less noise.\n",
        "error_probs_hw = {method: 1 - p for method, p in survival_probs_hw.items()}\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(6, 4))\n",
        "ax.bar(\n",
        "    error_probs_hw.keys(),\n",
        "    error_probs_hw.values(),\n",
        "    color=[\"steelblue\", \"coral\"],\n",
        ")\n",
        "ax.set_ylabel(\"1 - P(|0...0>)\")\n",
        "ax.set_title(f\"Mirror Circuit Error (26-qubit, {backend.name})\")\n",
        "ax.set_ylim(0, 1)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-analysis",
      "metadata": {},
      "source": [
        "<span id=\"analysis-of-results\" />\n",
        "\n",
        "### 結果の分析\n",
        "\n",
        "この大規模な結果により、小規模な例で観察された傾向が、より厳しい条件下においても裏付けられた。\n",
        "\n",
        "**2量子ビット深度：** AIを活用したトランスパイラーは、あらゆる規模の回路において、2量子ビット深度を著しく低減し続けています。 深さの最適化は、AIルーティングモデルが学習する主な目的の一つであり、その利点は、ルーティング問題がヒューリスティック手法ではより困難になる、クビット数が多い場合においてより顕著に現れる。\n",
        "\n",
        "**ゲート数：** デフォルトのトランスパイラー（SABRE）は、この範囲内のあらゆる回路規模において、一貫してゲート数の少ない回路を生成します。 SABREのヒューリスティックは、ゲート数を最小限に抑えるよう特別に設計されており、この規模ではその利点が明確かつ一貫して現れます。\n",
        "\n",
        "**トランスパイレーション時間：** スケールが大きくなるにつれて、トランスパイレーション時間の差は拡大する。 SABREの実行時間はほぼ一定であるのに対し、AIを活用したトランスパイラーの実行時間はより急激に増加している。 それにもかかわらず、AIを活用したトランスパイラーの実行環境は、ほとんどのワークフローにおいて依然として実用的な選択肢である。\n",
        "\n",
        "**ミラー回路の忠実度：** どちらの手法も、このスケールでは生存確率が1%を大幅に下回る結果となり、実用的な信号はほとんど得られない。 ゲート総数が約10,000、2量子ビットの処理深度が1,000を超える場合、ミラー回路全体で蓄積された脱分極ノイズが信号の大部分を覆い隠してしまう。 これは、ミラー回路アプローチの重要な限界を浮き彫りにしている。この手法は単純で、古典的なシミュレーションを必要としない一方で、大規模または深層の回路に対してはスケーラビリティに欠ける。そのような回路では、どちらの手法もノイズフロアに近いレベルまで押し下げられ、かろうじて残った微弱な信号は蓄積された誤差によって支配されてしまうからである。\n",
        "\n",
        "これらの結果は、AIを活用したトランスパイラの有効性を裏付けている一方で、その限界にも留意することが重要です。 このAI合成手法は、現時点では特定のカップリングマップにのみ適用可能であり、そのことがより広範な適用を制限する可能性がある。 さまざまなシナリオでの活用を検討する際には、この制約を考慮に入れる必要があります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "next-steps",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  この作品に興味を持たれた方は、以下の資料もご参照ください：\n",
        "\n",
        "  * [SABRE によるトランスパイレーションの最適化](/docs/tutorials/transpilation-optimizations-with-sabre)\n",
        "  * [ハミルトニアンシミュレーション回路の合成手法](/docs/tutorials/compilation-methods-for-hamiltonian-simulation-circuits)\n",
        "</Admonition>\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": 300
  },
  "nbformat": 4,
  "nbformat_minor": 5
}