{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "44d97249",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"動的回路を用いた長距離エンタングルメント\"\n",
        "description: \"このチュートリアルでは、ベル対、測定、およびフィードフォワードを用いた動的回路により長距離CNOTを実装し、直接ユニタリー法との比較を行います。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize hcords, ycords, xcords, ecolor, elinewidth, allcr, braket, frameon */}\n",
        "\n",
        "<span id=\"long-range-entanglement-with-dynamic-circuits\" />\n",
        "\n",
        "# 動的回路を用いた長距離エンタングルメント\n",
        "\n",
        "*使用時間の目安：Heron r2 プロセッサーで4分。 (注：これはあくまでも目安です。 実行時間は異なるかもしれない)。*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "57f65bca",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "このチュートリアルを完了すると、以下のことを習得できます：\n",
        "\n",
        "* 回路中間測定（MCM）と古典的フィードフォワードを用いた動的回路による長距離CNOTゲートの実装方法；\n",
        "* ユニタリーSWAPに基づく手法を用いて、同等のゲートを実装する方法；\n",
        "* 量子ビット間の距離をパラメータとしてゲート忠実度を測定し、両方のアプローチを比較する方法。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "748eee3b",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "このチュートリアルを進める前に、以下の内容についてあらかじめ理解しておいていただくことをお勧めします：\n",
        "\n",
        "* ベル状態、量子もつれ、量子ゲートなど、 [量子コンピューティングの基礎概念](/learning/courses/basics-of-quantum-information)；\n",
        "* [動的回路](/docs/guides/classical-feedforward-and-control-flow)に関する知識（回路の途中での測定および古典的なフィードフォワード）；\n",
        "* [Qiskit SDK](/docs/guides) および [IBM Quantum® Compute Service](/docs/guides/compute-services#qiskit-runtime) に関する基礎知識、ならびに [IBM Quantum](/docs/guides/cloud-setup) アカウントへのアクセス権。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b05b669f",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "離れた量子ビット間の長距離エンタングルメントは、接続性が限られたデバイスでは困難である。 このチュートリアルでは、測定ベースのプロトコルを使用して長距離制御X（LRCX）ゲートを実装することにより、動的回路がこのようなエンタングルメントを生成する方法を示します。\n",
        "\n",
        "[1における](#ref-1) Elisa Bäumerらのアプローチを踏襲し、この方法では回路途中の測定とフィードフォワードを用いて、量子ビットの分離に関係なく一定の深さのゲートを実現している。 中間的なベル・ペアを作り、それぞれのペアから1量子ビットを測定し、古典的な条件付きゲートを適用してエンタングルメントをデバイス全体に伝播させる。 これにより、長いSWAPチェーンが回避され、回路の奥行きと2量子ビットゲートエラーへの露出の両方が低減される。\n",
        "\n",
        "本ノートでは、 IBM Quantum ハードウェア向けにプロトコルを適応させ、制御点とターゲット点の距離に応じた性能をベンチマークし、ユニタリーSWAPに基づくベースラインと比較する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c6cd3174",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskit SDK v2.0 またはそれ以降、 [可視化](/docs/api/qiskit/visualization)サポート付き\n",
        "* Qiskit Runtime v0.37 以降 (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.17 以降 (`pip install qiskit-aer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39e4440a",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "5b0aa550",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
        "from qiskit.circuit.classical import expr\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.visualization import plot_circuit_layout\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    Batch,\n",
        "    SamplerV2 as Sampler,\n",
        ")\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6733ceeb",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 小規模シミュレータの例\n",
        "\n",
        "実際のQPU上で実行する前に、ノイズのないシミュレータ上で、動的回路とユニタリ回路の両方が理想的なベル状態を生成することを検証する。 IBM Quantum を `Sampler` 、バックエンドモード `AerSimulator` として、距離を6という小さな値に設定して使用しています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "28145093",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題にマッピングする\n",
        "\n",
        "ここでは、以下に示す動的回路の構成に従い、離れた2つの量子ビット間に長距離CNOTゲートを実装する（参考文献の図 1a を改変）。 [1](#ref-1) ). 重要な考え方は、 $|0\\rangle$ に初期化されたアンシラ量子ビットの「バス」を用いて、長距離ゲートテレポーテーションを仲介することである。\n",
        "\n",
        "![長距離CNOT回路](https://quantum.cloud.ibm.com/docs/images/tutorials/long-range-entanglement/dynamic_vs_unitary_long_range_illustration.avif)\n",
        "\n",
        "図に示すように、このプロセスは次のように機能する：\n",
        "\n",
        "1. コントロール量子ビットとターゲット量子ビットを中間アンシラを介して接続するベルペアのチェーンを準備する。\n",
        "2. 隣接するエンタングルされていない量子ビット間でベル測定を行い、コントロールとターゲットがベルペアを共有するまで段階的にエンタングルメントを入れ替える。\n",
        "3. このベル・ペアをゲート・テレポーテーションに使い、ローカルなCNOTを一定の深さの決定論的な長距離CNOTに変える。\n",
        "\n",
        "このアプローチでは、長いSWAPチェーンを一定の深さのプロトコルに置き換えることで、2量子ビットのゲート・エラーにさらされる機会を減らし、デバイス・サイズに応じてスケーラブルに動作させることができる。\n",
        "\n",
        "以下では、まずLRCX回路のダイナミック回路実装について説明する。 最後に、比較のためにユニタリーベースの実装も提供し、この設定におけるダイナミック回路の利点を強調する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "89597fcf",
      "metadata": {},
      "source": [
        "<span id=\"initialize-circuit\" />\n",
        "\n",
        "#### 回路の初期化\n",
        "\n",
        "まずは、比較の基準となるような単純な量子力学の問題から始めよう。 具体的には、インデックス0に制御量子ビットを持つ回路を初期化し、そこにハダマールゲートを適用する。 これにより重ね合わせ状態が生じ、これに制御X演算を適用すると、制御キュービットとターゲットキュービットの間にベル状態 $(|00\\rangle + |11\\rangle)/\\sqrt{2}$ が生成される。\n",
        "\n",
        "現段階では、長距離コントロールX（LRCX）自体はまだ建設していない。 その代わり、私たちの目標は、LRCXの役割を強調する明確で最小限の初期回路を定義することだ。 ステップ2では、LRCXがダイナミック回路を使った最適化としてどのように実装できるかを示し、その性能をユニタリー等価回路と比較する。 重要なのは、LRCXプロトコルはどんな初期回路にも適用できるということだ。 ここでは、わかりやすく説明するために、この単純なハダマードのセットアップを使用する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0446b8e8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/0446b8e8-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "distance = 6  # The distance of the CNOT gate, with the convention that a distance of zero is a nearest-neighbor CNOT.\n",
        "\n",
        "\n",
        "def initialize_circuit(distance):\n",
        "    assert distance >= 0\n",
        "    control = 0  # control qubit\n",
        "    n = distance  # number of qubits between target and control\n",
        "\n",
        "    qr = QuantumRegister(\n",
        "        n + 2, name=\"q\"\n",
        "    )  # Circuit with n qubits between control and target\n",
        "    cr = ClassicalRegister(\n",
        "        2, name=\"cr\"\n",
        "    )  # Classical register for measuring control and target qubits\n",
        "\n",
        "    k = int(n / 2)  # Number of Bell States to be used\n",
        "\n",
        "    allcr = [cr]\n",
        "    if (\n",
        "        distance > 1\n",
        "    ):  # This classical register will be used to store ZZ measurements.\n",
        "        # It is only used for long-range CX gates with distance > 1\n",
        "        c1 = ClassicalRegister(\n",
        "            k, name=\"c1\"\n",
        "        )  # Classical register needed for post processing\n",
        "        allcr.append(c1)\n",
        "    if (\n",
        "        distance > 0\n",
        "    ):  # This classical register will be used to store XX measurements.\n",
        "        # It is only used if distance > 0\n",
        "        c2 = ClassicalRegister(\n",
        "            n - k, name=\"c2\"\n",
        "        )  # Classical register needed for post processing\n",
        "        allcr.append(c2)\n",
        "\n",
        "    qc = QuantumCircuit(qr, *allcr, name=\"CNOT\")\n",
        "\n",
        "    # Apply a Hadamard gate to the control qubit such that the\n",
        "    # long-range CNOT gate will prepare a\n",
        "    # Bell state (|00> + |11>)/sqrt(2)\n",
        "    qc.h(control)\n",
        "\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc = initialize_circuit(distance)\n",
        "qc.draw(fold=-1, output=\"mpl\", scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e761cfc1",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ2：量子ハードウェア実行に向けた問題の最適化\n",
        "\n",
        "このステップでは、ダイナミック回路を使ってLRCX回路を構成する方法を示す。 その目的は、純粋なユニタリー実装に比べて深さを減らすことで、ハードウェア上での実行のために回路を最適化することである。 その利点を説明するために、動的LRCX構造とそのユニタリー等価物の両方を表示し、後で移調後の性能を比較する。 重要なことは、ここではLRCXを単純なハダマード初期化問題に適用しているが、このプロトコルは長距離CNOTが必要とされるあらゆる回路に適用できるということである。\n",
        "\n",
        "<span id=\"prepare-bell-pairs\" />\n",
        "\n",
        "#### ベルのペアを準備する\n",
        "\n",
        "まず、制御量子ビットとターゲット量子ビットの間の経路に沿って、ベル・ペアの連鎖を作ることから始める。 距離が奇数の場合、まずコントロールからその近傍にCNOTを適用する。 偶数距離の場合、このCNOTはベルペア準備ステップの後に適用される。 ベル・ペア・チェーンは、次に連続する量子ビットのペアをエンタングルし、デバイス全体で制御情報を伝送するのに必要なリソースを確立する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "4df8ebba",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/4df8ebba-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Determine where to start the Bell pair chain and add an extra CNOT when n is odd\n",
        "def check_even(n: int) -> int:\n",
        "    \"\"\"Return 1 if n is even, else 2.\"\"\"\n",
        "    return 1 if n % 2 == 0 else 2\n",
        "\n",
        "\n",
        "def prepare_bell_pairs(qc, add_barriers=True):\n",
        "    n = qc.num_qubits - 2  # number of qubits between target and control\n",
        "    k = int(n / 2)\n",
        "\n",
        "    if add_barriers:\n",
        "        qc.barrier()\n",
        "\n",
        "    x0 = check_even(n)\n",
        "    if n % 2 != 0:\n",
        "        qc.cx(0, 1)\n",
        "\n",
        "    # Create k Bell pairs\n",
        "    for i in range(k):\n",
        "        qc.h(x0 + 2 * i)\n",
        "        qc.cx(x0 + 2 * i, x0 + 2 * i + 1)\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc = prepare_bell_pairs(qc)\n",
        "qc.draw(output=\"mpl\", fold=-1, scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b80ea657",
      "metadata": {},
      "source": [
        "<span id=\"measure-neighboring-qubit-pairs-in-the-bell-basis\" />\n",
        "\n",
        "#### ベル基底で隣接する量子ビットのペアを測定する\n",
        "\n",
        "次に、 *隣接*する量子ビットをベル基底で測定する（ $XX$ と $ZZ$ の2量子ビット測定）。これにより、ターゲット量子ビットとコントロールに隣接する量子ビットの間に長距離ベル対が生成されます（次のステップでフィードフォワードにより実装されるパウリ補正まで）。 並行して、CNOTゲートをテレポートさせ、意図したターゲット量子ビットに作用させるエンタングル測定を実装する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8eed9e57",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/8eed9e57-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def measure_bell_basis(qc, add_barriers=True):\n",
        "    n = qc.num_qubits - 2  # number of qubits between target and control\n",
        "    k = int(n / 2)\n",
        "\n",
        "    if n > 1:\n",
        "        _, c1, c2 = qc.cregs\n",
        "    elif n > 0:\n",
        "        _, c2 = qc.cregs\n",
        "\n",
        "    # Determine where to start the Bell pair chain and add an extra CNOT\n",
        "    # when n is odd\n",
        "    x0 = 1 if n % 2 == 0 else 2\n",
        "\n",
        "    # Entangling layer that implements the Bell measurement\n",
        "    # (and additionally adds the CNOT to be\n",
        "    # teleported, if n is even)\n",
        "    for i in range(k + 1):\n",
        "        qc.cx(x0 - 1 + 2 * i, x0 + 2 * i)\n",
        "\n",
        "    for i in range(1, k + x0):\n",
        "        if i == 1:\n",
        "            qc.h(2 * i + 1 - x0)\n",
        "        else:\n",
        "            qc.h(2 * i + 1 - x0)\n",
        "\n",
        "    if add_barriers:\n",
        "        qc.barrier()\n",
        "\n",
        "    # Map the ZZ measurements onto classical register c1\n",
        "    for i in range(k):\n",
        "        if i == 0:\n",
        "            qc.measure(2 * i + x0, c1[i])\n",
        "        else:\n",
        "            qc.measure(2 * i + x0, c1[i])\n",
        "\n",
        "    # Map the XX measurements onto classical register c2\n",
        "    for i in range(1, k + x0):\n",
        "        if i == 1:\n",
        "            qc.measure(2 * i + 1 - x0, c2[i - 1])\n",
        "        else:\n",
        "            qc.measure(2 * i + 1 - x0, c2[i - 1])\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc = measure_bell_basis(qc)\n",
        "qc.draw(output=\"mpl\", fold=-1, scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f0d7059b",
      "metadata": {},
      "source": [
        "<span id=\"apply-feedforward-corrections-to-correct-pauli-byproduct-operators\" />\n",
        "\n",
        "#### フィードフォワード補正を適用して、パウリ副生成子演算子を補正する\n",
        "\n",
        "ベル基底の測定ではパウリ副生成物が生じるため、記録された結果を用いて補正する必要がある。 これは2つのステップで行われる。 まず、 $ZZ$ の全測定値のパリティを計算する必要がある。このパリティは、 $X$ ゲートをターゲット量子ビットに条件付きで適用するために使われる。 同様に、 $XX$ の測定値のパリティが計算され、 $Z$ ゲートを制御量子ビットに条件付きで適用するために使用される。\n",
        "\n",
        "Qiskitの新しい古典式フレームワークを使えば、これらのパリティは回路の古典処理層で直接計算できる。 各測定ビットに個別の条件ゲートのシーケンスを適用する代わりに、関連するすべての測定結果のXOR（パリティ）を表す単一の古典的な式を構築することができる。 この式は、 `if_test` 単一ブロックの条件として使用され、補正ゲートを一定の深さで適用することができる。 このアプローチは回路を単純化し、フィードフォワード補正が不必要な追加レイテンシを発生させないことを保証する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "4915791a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/4915791a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def apply_ffwd_corrections(qc):\n",
        "    control = 0  # control qubit\n",
        "    target = qc.num_qubits - 1  # target qubit\n",
        "    n = qc.num_qubits - 2  # number of qubits between target and control\n",
        "\n",
        "    k = int(n / 2)\n",
        "    x0 = check_even(n)\n",
        "\n",
        "    if n > 1:\n",
        "        _, c1, c2 = qc.cregs\n",
        "    elif n > 0:\n",
        "        _, c2 = qc.cregs\n",
        "\n",
        "    # First, let's compute the parity of all ZZ measurements\n",
        "    for i in range(k):\n",
        "        if i == 0:\n",
        "            parity_ZZ = expr.lift(\n",
        "                c1[i]\n",
        "            )  # Store the value of the first ZZ measurement in parity_ZZ\n",
        "        else:\n",
        "            parity_ZZ = expr.bit_xor(\n",
        "                c1[i], parity_ZZ\n",
        "            )  # Successively compute the parity via XOR operations\n",
        "\n",
        "    for i in range(1, k + x0):\n",
        "        if i == 1:\n",
        "            parity_XX = expr.lift(\n",
        "                c2[i - 1]\n",
        "            )  # Store the value of the first XX measurement in parity_XX\n",
        "        else:\n",
        "            parity_XX = expr.bit_xor(\n",
        "                c2[i - 1], parity_XX\n",
        "            )  # Successively compute the parity via XOR operations\n",
        "\n",
        "    if n > 0:\n",
        "        with qc.if_test(parity_XX):\n",
        "            qc.z(control)\n",
        "\n",
        "    if n > 1:\n",
        "        with qc.if_test(parity_ZZ):\n",
        "            qc.x(target)\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc = apply_ffwd_corrections(qc)\n",
        "qc.draw(output=\"mpl\", fold=-1, scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6d22740b",
      "metadata": {},
      "source": [
        "<span id=\"measure-control-and-target-qubits\" />\n",
        "\n",
        "#### 制御クビットとターゲットクビット\n",
        "\n",
        "我々は、 $XX$、 $YY$、 $ZZ$ ベースにおける制御量子ビットとターゲット量子ビットの測定を可能にするヘルパー関数を定義する。 ベル状態 $(|00\\rangle + |11\\rangle)/\\sqrt{2}$ を検証するためには、 $XX$ と $ZZ$ の期待値がともに $+1$ であることが必要である。 $YY$ の測定もここでサポートされており、忠実度を計算する際に以下で使用される。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d087d7c1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/d087d7c1-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def measure_in_basis(qc, basis=\"XX\", add_barrier=True):\n",
        "    control = 0  # control qubit\n",
        "    target = qc.num_qubits - 1  # target qubit\n",
        "\n",
        "    assert basis in [\"XX\", \"YY\", \"ZZ\"]\n",
        "\n",
        "    qc = (\n",
        "        qc.copy()\n",
        "    )  # We copy the circuit because we want to measure in different bases\n",
        "    cr = qc.cregs[0]\n",
        "\n",
        "    if add_barrier:\n",
        "        qc.barrier()\n",
        "\n",
        "    if basis == \"XX\":\n",
        "        qc.h(control)\n",
        "        qc.h(target)\n",
        "    elif basis == \"YY\":\n",
        "        qc.sdg(control)\n",
        "        qc.sdg(target)\n",
        "        qc.h(control)\n",
        "        qc.h(target)\n",
        "\n",
        "    qc.measure(control, cr[0])\n",
        "    qc.measure(target, cr[1])\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc_YY = measure_in_basis(qc.copy(), basis=\"YY\")\n",
        "qc_YY.draw(\n",
        "    output=\"mpl\", fold=-1, scale=0.5\n",
        ")  # Circuit for measuring in the YY basis"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "072f8605",
      "metadata": {},
      "source": [
        "<span id=\"put-it-all-together\" />\n",
        "\n",
        "#### すべてをまとめて\n",
        "\n",
        "上記で定義したさまざまな手順を組み合わせることで、1次元（ 1D ）の直線の両端に長距離CXゲートを作成します。 手順は以下の通りです：\n",
        "\n",
        "* $|+\\rangle$ での制御量子ビットの初期化\n",
        "* ベル・ペアの準備\n",
        "* 隣接する量子ビットペアの測定\n",
        "* MCMに依存するフィードフォワード補正の適用\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "11fc8adc",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/11fc8adc-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def lrcx(distance, prep_barrier=True, pre_measure_barrier=True):\n",
        "    qc = initialize_circuit(distance)\n",
        "    qc = prepare_bell_pairs(qc, prep_barrier)\n",
        "    qc = measure_bell_basis(qc, pre_measure_barrier)\n",
        "    qc = apply_ffwd_corrections(qc)\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc = lrcx(distance)\n",
        "# Apply the measurement in the XX, YY, and ZZ bases\n",
        "qc_XX, qc_YY, qc_ZZ = [\n",
        "    measure_in_basis(qc, basis=basis) for basis in [\"XX\", \"YY\", \"ZZ\"]\n",
        "]\n",
        "\n",
        "qc_YY.draw(\n",
        "    output=\"mpl\", fold=-1, scale=0.5\n",
        ")  # Circuit for measuring in the YY basis"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2b1f3f70",
      "metadata": {},
      "source": [
        "<span id=\"unitary-based-implementation-swapping-the-qubits-to-the-middle\" />\n",
        "\n",
        "#### 単一基底に基づく実装で量子ビットを中央に交換する\n",
        "\n",
        "比較のため、まず、最近接接続とユニタリーゲートを用いて長距離CNOTゲートを実装した場合について検討する。 次の図の左側は、n個のn-量子ビットからなる 1D チェーンを跨ぐ長距離CNOTゲートの回路であり、この回路では隣接量子ビット間の接続のみが考慮されている。 中央には、局所的なCNOTゲートを用いて実装可能な等価なユニタリー分解があり、回路の深さは $O(n)$ である。\n",
        "\n",
        "![長距離CNOT回路](https://quantum.cloud.ibm.com/docs/images/tutorials/long-range-entanglement/dynamic_vs_unitary_long_range_illustration.avif)\n",
        "\n",
        "中央の回路は、次のように実装できます：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3f816591",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cnot_unitary(distance):\n",
        "    \"\"\"Generate a long range CNOT gate using local CNOTs on a 1D\n",
        "    chain of qubits subject to n\n",
        "    nearest-neighbor connections only.\n",
        "\n",
        "\n",
        "    Args:\n",
        "        distance (int) : The distance of the CNOT gate,\n",
        "        with the convention that\n",
        "        a distance of 0 is a nearest-neighbor CNOT.\n",
        "\n",
        "    Returns:\n",
        "        QuantumCircuit: A Quantum Circuit implementing a\n",
        "        long-range CNOT gate\n",
        "        between qubit 0 and qubit distance+1\n",
        "    \"\"\"\n",
        "    assert distance >= 0\n",
        "    n = distance  # number of qubits between target and control\n",
        "\n",
        "    qr = QuantumRegister(\n",
        "        n + 2, name=\"q\"\n",
        "    )  # Circuit with n qubits between control and target\n",
        "    cr = ClassicalRegister(\n",
        "        2, name=\"cr\"\n",
        "    )  # Classical register for measuring control and target qubits\n",
        "\n",
        "    qc = QuantumCircuit(qr, cr, name=\"CNOT_unitary\")\n",
        "\n",
        "    control_qubit = 0\n",
        "\n",
        "    qc.h(control_qubit)  # Prepare the control qubit in the |+> state\n",
        "\n",
        "    k = int(n / 2)\n",
        "    qc.barrier()\n",
        "    for i in range(control_qubit, control_qubit + k):\n",
        "        qc.cx(i, i + 1)\n",
        "        qc.cx(i + 1, i)\n",
        "        qc.cx(-i - 1, -i - 2)\n",
        "        qc.cx(-i - 2, -i - 1)\n",
        "    if n % 2 == 1:\n",
        "        qc.cx(k + 2, k + 1)\n",
        "        qc.cx(k + 1, k + 2)\n",
        "    qc.barrier()\n",
        "    qc.cx(k, k + 1)\n",
        "    for i in range(control_qubit, control_qubit + k):\n",
        "        qc.cx(k - i, k - 1 - i)\n",
        "        qc.cx(k - 1 - i, k - i)\n",
        "        qc.cx(k + i + 1, k + i + 2)\n",
        "        qc.cx(k + i + 2, k + i + 1)\n",
        "    if n % 2 == 1:\n",
        "        qc.cx(-2, -1)\n",
        "        qc.cx(-1, -2)\n",
        "\n",
        "    return qc\n",
        "\n",
        "\n",
        "qc_uni = cnot_unitary(distance)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c0c99c20",
      "metadata": {},
      "source": [
        "それでは、前述の動的回路と同様に、 $XX$、 $YY$、および $ZZ$ の各ベースで測定を行う回路を組み立てましょう。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b899e143",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/b899e143-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Apply the measurement in the XX, YY, and ZZ bases\n",
        "qc_uni_XX, qc_uni_YY, qc_uni_ZZ = [\n",
        "    measure_in_basis(qc_uni, basis=basis) for basis in [\"XX\", \"YY\", \"ZZ\"]\n",
        "]\n",
        "\n",
        "qc_uni_YY.draw(\n",
        "    output=\"mpl\", fold=-1, scale=0.5\n",
        ")  # Circuit for measuring in the YY basis"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "81e55064",
      "metadata": {},
      "source": [
        "`distance=6`小規模な例について、動的回路とユニタリー回路の両方を構築したので、次にそれらをトランスパイルし、まずはノイズのないシミュレータ上で実行する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "091e9537",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "aer_backend = AerSimulator()\n",
        "pm_sim = generate_preset_pass_manager(\n",
        "    optimization_level=0, backend=aer_backend\n",
        ")\n",
        "\n",
        "# Dynamic circuits\n",
        "isa_sim_dyn = pm_sim.run([qc_XX, qc_YY, qc_ZZ])\n",
        "\n",
        "# Unitary circuits\n",
        "isa_sim_uni = pm_sim.run([qc_uni_XX, qc_uni_YY, qc_uni_ZZ])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe2fce0e",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ3: `Qiskit primitives`を使用して実行する\n",
        "\n",
        "これで、ノイズのないシミュレータ・バックエンド上で実験を実行できるようになりました。 回路の実行には、バックエンドモードとして「 AerSimulator 」を設定した Qiskit Runtime サンプラーを使用しています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "689c9a46",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler_sim = Sampler(mode=aer_backend)\n",
        "sim_job = sampler_sim.run(isa_sim_dyn + isa_sim_uni)\n",
        "sim_results = sim_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5287f612",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、結果を希望の古典形式で返す\n",
        "\n",
        "実験が正常に完了した後、測定データを後処理して、有意義な指標を抽出します。\n",
        "このステップでは、以下の作業を行います：\n",
        "\n",
        "* 長距離CXのパフォーマンスを評価するための品質指標を定義する。\n",
        "* 生の測定結果からパウリ演算子の期待値を計算する。\n",
        "* これらを使って、生成されたベル状態の忠実度を計算する。\n",
        "\n",
        "ノイズのないシミュレーションにおいて、構築された回路について、忠実度指標が $1$ であることを検証する。 実際のQPUを用いた実験において、この分析により、動的回路がユニタリーなベースライン実装と比較してどの程度の性能を発揮しているかが明確に把握できるだろう。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ba303da",
      "metadata": {},
      "source": [
        "<span id=\"quality-metrics\" />\n",
        "\n",
        "#### 品質メトリック\n",
        "\n",
        "長距離CXプロトコルの成功を評価するため、出力状態が理想的なベル状態にどれだけ近いかを測定する。 これを定量化する便利な方法は、パウリ演算子の期待値を用いて状態の忠実度を計算することである。 $\\braket{XX}$、 $\\braket{YY}$、および $\\braket{ZZ}$ が分かれば、制御状態およびターゲット状態におけるベル状態の忠実度を計算することができる。具体的には、\n",
        "\n",
        "$ F = \\frac{1}{4} (1 + \\braket{XX} - \\braket{YY} + \\braket{ZZ})$\n",
        "\n",
        "生の測定データからこれらの期待値を計算するために、ヘルパー関数のセットを定義する：\n",
        "\n",
        "* **`compute_ZZ_expectation`**: $Z$、2量子ビットのパウリ演算子の期待値を計算します。\n",
        "* **`compute_fidelity`**: $XX$, $YY$, $ZZ$ の期待値を上記の忠実度式に組み合わせる。\n",
        "* **`get_counts_from_bitarray`**:バックエンドの結果オブジェクトからカウントを抽出するユーティリティ。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "5645a9be",
      "metadata": {},
      "outputs": [],
      "source": [
        "def compute_ZZ_expectation(counts):\n",
        "    total = sum(counts.values())\n",
        "    expectation = 0\n",
        "    for bitstring, count in counts.items():\n",
        "        # Ensure bitstring is 2 bits\n",
        "        z1 = (-1) ** (int(bitstring[-1]))\n",
        "        z2 = (-1) ** (int(bitstring[-2]))\n",
        "        expectation += z1 * z2 * count\n",
        "    return expectation / total\n",
        "\n",
        "\n",
        "def compute_fidelity(counts_xx, counts_yy, counts_zz):\n",
        "    xx, yy, zz = [\n",
        "        compute_ZZ_expectation(c) for c in [counts_xx, counts_yy, counts_zz]\n",
        "    ]\n",
        "    return 1 / 4 * (1 + xx - yy + zz)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "ade0c4e6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Dynamic fidelity (distance=6): 1.0000\n",
            "Unitary fidelity (distance=6): 1.0000\n"
          ]
        }
      ],
      "source": [
        "# Dynamic fidelity\n",
        "counts_xx = sim_results[0].data.cr.get_counts()\n",
        "counts_yy = sim_results[1].data.cr.get_counts()\n",
        "counts_zz = sim_results[2].data.cr.get_counts()\n",
        "fidelity_dyn = compute_fidelity(counts_xx, counts_yy, counts_zz)\n",
        "\n",
        "# Unitary fidelity\n",
        "counts_xx = sim_results[3].data.cr.get_counts()\n",
        "counts_yy = sim_results[4].data.cr.get_counts()\n",
        "counts_zz = sim_results[5].data.cr.get_counts()\n",
        "fidelity_uni = compute_fidelity(counts_xx, counts_yy, counts_zz)\n",
        "\n",
        "print(f\"Dynamic fidelity (distance={distance}): {fidelity_dyn:.4f}\")\n",
        "print(f\"Unitary fidelity (distance={distance}): {fidelity_uni:.4f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aaa66ebb",
      "metadata": {},
      "source": [
        "ノイズのないシミュレーションでは予想通り、動的回路とユニタリー回路の両方における忠実度は $1$ となる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9ac23eb2",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 大規模なハードウェアの例\n",
        "\n",
        "ここで、これらすべての詳細を統合して、より大規模な単一のワークフローを作成し、それを実際の量子ハードウェア上で実行します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad4224f2",
      "metadata": {},
      "source": [
        "<span id=\"generate-circuits-for-different-distances\" />\n",
        "\n",
        "### 異なる距離用の回路を生成する\n",
        "\n",
        "現在、最大60キュービットの距離にわたる長距離CX回路を生成しています。 各距離について、 $XX$、 $YY$、および $ZZ$ の基底で測定を行う回路を構築し、これらは後でフィデリティを計算するために使用される。\n",
        "\n",
        "距離のリストには短距離と長距離の両方が含まれ、 `distance = 0` は最近接CXに対応する。 これらの同じ距離は、後で比較のために対応するユニタリー回路を生成するためにも使われる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "72c70b11",
      "metadata": {},
      "outputs": [],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "distances = [\n",
        "    0,\n",
        "    1,\n",
        "    2,\n",
        "    3,\n",
        "    6,\n",
        "    11,\n",
        "    16,\n",
        "    21,\n",
        "    28,\n",
        "    35,\n",
        "    44,\n",
        "    55,\n",
        "    60,\n",
        "]  # Distances for long range CX. distance of 0 is a nearest-neighbor CX\n",
        "distances.sort()\n",
        "assert min(distances) >= 0\n",
        "basis_list = [\"XX\", \"YY\", \"ZZ\"]\n",
        "\n",
        "# Dynamic circuits\n",
        "circuits_dyn = []\n",
        "for distance in distances:\n",
        "    for basis in basis_list:\n",
        "        circuits_dyn.append(\n",
        "            measure_in_basis(lrcx(distance, prep_barrier=False), basis=basis)\n",
        "        )\n",
        "print(f\"Number of circuits: {len(circuits_dyn)}\")\n",
        "\n",
        "# Unitary circuits\n",
        "circuits_uni = []\n",
        "for distance in distances:\n",
        "    for basis in basis_list:\n",
        "        circuits_uni.append(\n",
        "            measure_in_basis(cnot_unitary(distance), basis=basis)\n",
        "        )\n",
        "\n",
        "print(f\"Number of circuits: {len(circuits_uni)}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "698132a5",
      "metadata": {},
      "source": [
        "ダイナミック回路とユニタリー回路の両方が、さまざまな距離で使えるようになった。 まず、バックエンド・デバイスを選択する必要がある。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "e0476bef",
      "metadata": {},
      "outputs": [],
      "source": [
        "# -------------------------Step 2-------------------------\n",
        "# Set up access to IBM Quantum devices\n",
        "from qiskit.circuit import IfElseOp\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=156\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dad36db5",
      "metadata": {},
      "source": [
        "次のステップでは、バックエンドが `if_else` 命令をサポートしていることを確認する。これは、新しいバージョンのダイナミック回路に必要な命令である。 この機能はまだアーリーアクセスの段階なので、 `IfElseOp` がまだ利用可能でない場合は、明示的にバックエンドターゲットに追加する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "66805cb4",
      "metadata": {},
      "outputs": [],
      "source": [
        "if \"if_else\" not in backend.target.operation_names:\n",
        "    backend.target.add_instruction(IfElseOp, name=\"if_else\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f15cf5e8",
      "metadata": {},
      "source": [
        "<span id=\"use-layer-fidelity-string-for-selecting-1d-chain\" />\n",
        "\n",
        "#### 1D チェーンの選択にはLayer Fidelity文字列を使用してください\n",
        "\n",
        "動的回路とユニタリー回路の性能を 1D チェーンで比較したいので、レイヤー忠実度ストリングを使用して、デバイスから最適な量子ビットのチェーンの線形トポロジーを選択する。 これにより、両タイプの回路が同じ接続制約の下でトランスパイルされ、その性能を公平に比較することができる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "258e3fa1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[11, 12, 13, 14, 15, 19, 35, 34, 33, 39, 53, 54, 55, 59, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 76, 81, 82, 83, 84, 85, 86, 87, 97, 107, 108, 109, 110, 111, 98, 91, 92, 93, 94, 95, 99, 115, 114, 113, 119, 133, 132, 131, 138, 151, 150, 149, 148]\n"
          ]
        }
      ],
      "source": [
        "# This selects best qubits for longest distance and uses\n",
        "# the same control for all lengths\n",
        "lf_qubits = backend.properties().to_dict()[\n",
        "    \"general_qlists\"\n",
        "]  # best linear chain qubits\n",
        "chosen_layouts = {\n",
        "    distance: [\n",
        "        val[\"qubits\"]\n",
        "        for val in lf_qubits\n",
        "        if val[\"name\"] == f\"lf_{distances[-1] + 2}\"\n",
        "    ][0][: distance + 2]\n",
        "    for distance in distances\n",
        "}\n",
        "print(chosen_layouts[max(distances)])  # best qubits at each distance"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5886f5c9",
      "metadata": {},
      "outputs": [],
      "source": [
        "isa_circuits_dyn = []\n",
        "isa_circuits_uni = []\n",
        "\n",
        "# Using the same initial layouts for both circuits for better\n",
        "# apples to apples comparison\n",
        "for qc in circuits_dyn:\n",
        "    pm = generate_preset_pass_manager(\n",
        "        optimization_level=1,\n",
        "        backend=backend,\n",
        "        initial_layout=chosen_layouts[qc.num_qubits - 2],\n",
        "    )\n",
        "    isa_circuits_dyn.append(pm.run(qc))\n",
        "\n",
        "for qc in circuits_uni:\n",
        "    pm = generate_preset_pass_manager(\n",
        "        optimization_level=1,\n",
        "        backend=backend,\n",
        "        initial_layout=chosen_layouts[qc.num_qubits - 2],\n",
        "    )\n",
        "    isa_circuits_uni.append(pm.run(qc))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c77c3fd3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2Q depth: 2\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/c77c3fd3-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\n",
        "    f\"2Q depth: \"\n",
        "    f\"{isa_circuits_dyn[14].depth(lambda x: x.operation.num_qubits == 2)}\"\n",
        ")\n",
        "isa_circuits_dyn[14].draw(\"mpl\", fold=-1, idle_wires=0)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7e5fc240",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2Q depth: 13\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/7e5fc240-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\n",
        "    f\"2Q depth: \"\n",
        "    f\"{isa_circuits_uni[14].depth(lambda x: x.operation.num_qubits == 2)}\"\n",
        ")\n",
        "isa_circuits_uni[14].draw(\"mpl\", fold=-1, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6995ce7",
      "metadata": {},
      "source": [
        "<span id=\"visualize-qubits-used-for-the-lrcx-circuit\" />\n",
        "\n",
        "### LRCX回路に使用される量子ビットを可視化する\n",
        "\n",
        "このセクションでは、LRCX回路がどのようにハードウェアにマッピングされるかを検証する。 まず、回路で使用されている物理的な量子ビットを可視化することから始め、次にレイアウトにおける制御とターゲットの距離が演算回数にどのような影響を与えるかを研究する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2d090f8a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/2d090f8a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 30,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Note: the qubit coordinates must be hard-coded.\n",
        "# The backend API does not currently provide this information directly.\n",
        "# If using a different backend, you will need to\n",
        "# adjust the coordinates accordingly,\n",
        "# or set the qubit_coordinates = None to use the default layout coordinates.\n",
        "\n",
        "\n",
        "def _heron_coords_r2():\n",
        "    \"\"\"Generate coordinates for the Heron layout in R2. Note\"\"\"\n",
        "    cord_map = np.array(\n",
        "        [\n",
        "            [\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                1,\n",
        "                5,\n",
        "                9,\n",
        "                13,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "                3,\n",
        "                7,\n",
        "                11,\n",
        "                15,\n",
        "                0,\n",
        "                1,\n",
        "                2,\n",
        "                3,\n",
        "                4,\n",
        "                5,\n",
        "                6,\n",
        "                7,\n",
        "                8,\n",
        "                9,\n",
        "                10,\n",
        "                11,\n",
        "                12,\n",
        "                13,\n",
        "                14,\n",
        "                15,\n",
        "            ],\n",
        "            -1\n",
        "            * np.array([j for i in range(15) for j in [i] * [16, 4][i % 2]]),\n",
        "        ],\n",
        "        dtype=int,\n",
        "    )\n",
        "\n",
        "    hcords = []\n",
        "    ycords = cord_map[0]\n",
        "    xcords = cord_map[1]\n",
        "    for i in range(156):\n",
        "        hcords.append([xcords[i] + 1, np.abs(ycords[i]) + 1])\n",
        "\n",
        "    return hcords\n",
        "\n",
        "\n",
        "# Visualize the active qubits in the circuit layout\n",
        "plot_circuit_layout(\n",
        "    circuit=isa_circuits_uni[-1],\n",
        "    backend=backend,\n",
        "    view=\"physical\",\n",
        "    qubit_coordinates=_heron_coords_r2(),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4d75038a",
      "metadata": {},
      "source": [
        "次に、実際のバックエンド上で実験を実行します。 また、バッチ処理を活用して、複数の試行にわたって実験を効率的に実行しています。 反復実験を行うことで、ユニタリー法とダイナミック法の比較をより正確に行うための平均値を算出できるほか、実行ごとの偏差を比較することで、それらの変動性を定量化することができる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "e6f7811d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# -------------------------Step 3-------------------------\n",
        "num_trials = 10\n",
        "jobs_uni = []\n",
        "jobs_dyn = []\n",
        "with Batch(backend=backend) as batch:\n",
        "    sampler = Sampler(mode=batch)\n",
        "    sampler.options.environment.job_tags = [\"TUT_LRE\"]\n",
        "    for _ in range(num_trials):\n",
        "        jobs_uni.append(sampler.run(isa_circuits_uni, shots=1024))\n",
        "        jobs_dyn.append(sampler.run(isa_circuits_dyn, shots=1024))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "388b6a87",
      "metadata": {},
      "source": [
        "動的な長距離CX回路の忠実度を計算する。 各距離について、 $\\braket{XX}$、 $\\braket{YY}$、および $\\braket{ZZ}$ の各ベースにおける測定結果を抽出する。 これらの結果は、以前に定義したヘルパー関数を用いて統合され、 $F = \\tfrac{1}{4} \\big( 1 + \\langle XX \\rangle - \\langle YY \\rangle + \\langle ZZ \\rangle \\big)$ に基づいてフィデリティが算出される。これにより、各距離における動的に実行されたプロトコルの観測されたフィデリティが得られる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "10245513",
      "metadata": {},
      "outputs": [],
      "source": [
        "# -------------------------Step 4-------------------------\n",
        "fidelities_dyn = []\n",
        "\n",
        "# loop over trials\n",
        "for job in jobs_dyn:\n",
        "    result_dyn = job.result()\n",
        "    trial_fidelities = []\n",
        "    # loop over all distances\n",
        "    for ind, dist in enumerate(distances):\n",
        "        counts_xx = result_dyn[ind * 3].data.cr.get_counts()\n",
        "        counts_yy = result_dyn[ind * 3 + 1].data.cr.get_counts()\n",
        "        counts_zz = result_dyn[ind * 3 + 2].data.cr.get_counts()\n",
        "        trial_fidelities.append(\n",
        "            compute_fidelity(counts_xx, counts_yy, counts_zz)\n",
        "        )\n",
        "    fidelities_dyn.append(trial_fidelities)\n",
        "# average over trials for each distance\n",
        "avg_fidelities_dyn = np.mean(fidelities_dyn, axis=0)\n",
        "std_fidelities_dyn = np.std(fidelities_dyn, axis=0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dabcde16",
      "metadata": {},
      "source": [
        "ここでユニタリー長距離CX回路の忠実度を計算するが、これは上記のダイナミック回路の場合と同じ方法である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "decaf83a",
      "metadata": {},
      "outputs": [],
      "source": [
        "fidelities_uni = []\n",
        "\n",
        "# loop over trials\n",
        "for job in jobs_uni:\n",
        "    result_uni = job.result()\n",
        "    trial_fidelities = []\n",
        "    # loop over all distances\n",
        "    for ind, dist in enumerate(distances):\n",
        "        counts_xx = result_uni[ind * 3].data.cr.get_counts()\n",
        "        counts_yy = result_uni[ind * 3 + 1].data.cr.get_counts()\n",
        "        counts_zz = result_uni[ind * 3 + 2].data.cr.get_counts()\n",
        "        trial_fidelities.append(\n",
        "            compute_fidelity(counts_xx, counts_yy, counts_zz)\n",
        "        )\n",
        "    fidelities_uni.append(trial_fidelities)\n",
        "# average over trials for each distance\n",
        "avg_fidelities_uni = np.mean(fidelities_uni, axis=0)\n",
        "std_fidelities_uni = np.std(fidelities_uni, axis=0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9dadc4e",
      "metadata": {},
      "source": [
        "<span id=\"plot-the-results\" />\n",
        "\n",
        "### 結果をプロットする\n",
        "\n",
        "結果を視覚的に把握できるよう、以下の図では、各手法について、もつれた量子ビット間の距離を変化させた際に測定された推定ゲート忠実度をプロットしています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "724da22d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/724da22d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "fig, ax = plt.subplots()\n",
        "\n",
        "# Unitary with error bars\n",
        "ax.errorbar(\n",
        "    distances,\n",
        "    avg_fidelities_uni,\n",
        "    yerr=std_fidelities_uni,\n",
        "    fmt=\"o-.\",\n",
        "    color=\"c\",\n",
        "    ecolor=\"c\",\n",
        "    elinewidth=1,\n",
        "    capsize=4,\n",
        "    label=\"Unitary\",\n",
        ")\n",
        "# Dynamic with error bars\n",
        "ax.errorbar(\n",
        "    distances,\n",
        "    avg_fidelities_dyn,\n",
        "    yerr=std_fidelities_dyn,\n",
        "    fmt=\"o-.\",\n",
        "    color=\"m\",\n",
        "    ecolor=\"m\",\n",
        "    elinewidth=1,\n",
        "    capsize=4,\n",
        "    label=\"Dynamic\",\n",
        ")\n",
        "# Random gate baseline\n",
        "ax.axhline(y=1 / 4, linestyle=\"--\", color=\"gray\", label=\"Random gate\")\n",
        "\n",
        "legend = ax.legend(frameon=True)\n",
        "for text in legend.get_texts():\n",
        "    text.set_color(\"black\")\n",
        "legend.get_frame().set_facecolor(\"white\")\n",
        "legend.get_frame().set_edgecolor(\"black\")\n",
        "ax.set_title(\n",
        "    \"Bell State Fidelity vs Control–Target Separation\", color=\"black\"\n",
        ")\n",
        "ax.set_xlabel(\"Distance\", color=\"black\")\n",
        "ax.set_ylabel(\"Bell state fidelity\", color=\"black\")\n",
        "ax.grid(linestyle=\":\", linewidth=0.6, alpha=0.4, color=\"gray\")\n",
        "ax.set_ylim((0.2, 1))\n",
        "ax.set_facecolor(\"white\")\n",
        "fig.patch.set_facecolor(\"white\")\n",
        "for spine in ax.spines.values():\n",
        "    spine.set_visible(True)\n",
        "    spine.set_color(\"black\")\n",
        "ax.tick_params(axis=\"x\", colors=\"black\")\n",
        "ax.tick_params(axis=\"y\", colors=\"black\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bb2545e7",
      "metadata": {},
      "source": [
        "上記の忠実度プロットから、LRCXは一貫して直接ユニタリー実装を上回らなかった。 実際、コントロールとターゲットの距離が短い場合、ユニタリー回路の方が高い忠実度を達成した。 しかし、セパレーションが大きくなると、ダイナミック回路はユニタリー実装よりも優れた忠実度を達成し始める。 動的回路は、長いSWAPチェーンを回避することで回路の深さを減らすが、回路途中の測定、古典的なフィードフォワード、制御パスの遅延によって、さらに回路時間がかかる。 レイテンシーが増加すると、デコヒーレンスと読み出しエラーが増加し、短距離では深度の節約を上回る可能性がある。\n",
        "\n",
        "とはいえ、ダイナミック・アプローチがユニタリー・アプローチを凌駕するクロスオーバー・ポイントが観察される。 ユニタリー回路の深さは量子ビット間の距離に応じて直線的に成長するが、ダイナミック回路の深さは一定である。\n",
        "\n",
        "**キーポイント:**\n",
        "\n",
        "* **ダイナミック回路の直接的な利点：** 現在の主な動機は、 *2量子ビットの深さを*減らすことであり、必ずしも忠実度を向上させることではない。\n",
        "* **今日、忠実度が悪化する理由：** 特にコントロールとターゲットの分離が小さい場合、測定と古典演算による回路時間の増加が支配的となることが多い。\n",
        "* **将来に向けて：** ハードウェアが改良され、特に読み出しの高速化、古典的な制御レイテンシの短縮、回路途中のオーバーヘッドの削減が進めば、これらの深さと時間の短縮が、測定可能な忠実度の向上につながることが期待される。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3dcff343",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/long-range-entanglement/extracted-outputs/3dcff343-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Compute metrics for each distance, skipping the basis circuits since\n",
        "# they are identical for each distance\n",
        "depths_2q_dyn = [\n",
        "    c.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    for c in isa_circuits_dyn[::3]\n",
        "]\n",
        "meas_dyn = [\n",
        "    sum(1 for instr in c.data if instr.operation.name == \"measure\")\n",
        "    for c in isa_circuits_dyn[::3]\n",
        "]\n",
        "\n",
        "depths_2q_uni = [\n",
        "    c.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    for c in isa_circuits_uni[::3]\n",
        "]\n",
        "meas_uni = [\n",
        "    sum(1 for instr in c.data if instr.operation.name == \"measure\")\n",
        "    for c in isa_circuits_uni[::3]\n",
        "]\n",
        "\n",
        "fig, axes = plt.subplots(1, 2, figsize=(12, 5))\n",
        "\n",
        "axes[0].plot(\n",
        "    distances, depths_2q_uni, \"o-.\", color=\"c\", label=\"Unitary (2Q depth)\"\n",
        ")\n",
        "axes[0].plot(\n",
        "    distances, depths_2q_dyn, \"o-.\", color=\"m\", label=\"Dynamic (2Q depth)\"\n",
        ")\n",
        "axes[0].set_xlabel(\"Number of qubits between control and target\")\n",
        "axes[0].set_ylabel(\"Two-qubit depth\")\n",
        "axes[0].grid(True, linestyle=\":\", linewidth=0.6, alpha=0.4)\n",
        "axes[0].legend()\n",
        "\n",
        "axes[1].plot(\n",
        "    distances, meas_uni, \"o-.\", color=\"c\", label=\"Unitary (# measurements)\"\n",
        ")\n",
        "axes[1].plot(\n",
        "    distances, meas_dyn, \"o-.\", color=\"m\", label=\"Dynamic (# measurements)\"\n",
        ")\n",
        "axes[1].set_xlabel(\"Number of qubits between control and target\")\n",
        "axes[1].set_ylabel(\"Number of measurements\")\n",
        "axes[1].grid(True, linestyle=\":\", linewidth=0.6, alpha=0.4)\n",
        "axes[1].legend()\n",
        "\n",
        "fig.suptitle(\"Scaling of Unitary vs Dynamic LRCX with Distance\", fontsize=12)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "55326bf8",
      "metadata": {},
      "source": [
        "この2量子ビットの深さのプロットは、ダイナミック回路で実装されたLRCXの主な利点を強調している。 一方、ユニタリー実装では、SWAPチェーンが必要なため、距離に応じて線形に成長する。 深さは2量子ビット演算の論理スケーリングを捉え、測定回数は動的回路の追加オーバーヘッドを反映する。 これらの測定は並列に実行されるため効率的だが、現在のハードウェアでは固定コストがかかる。\n",
        "\n",
        "今日、忠実度が悪化する理由：特にコントロールとターゲットの分離が小さい場合、測定と古典演算による回路時間の増加が支配的となることが多い。 例えば、Heron r2 プロセッサの平均読み出し長は2,280 nsであるのに対し、 2Q ゲート長はわずか68 nsである。\n",
        "\n",
        "測定と古典的なレイテンシが改善されるにつれて、ダイナミック回路の一定深さと一定測定のスケーリングが、より大規模な回路で明確な忠実度と実行時間の利点をもたらすことが期待される。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dae8ad4a",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "この作品に興味を持たれた方は、以下の資料もご参照ください：\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  * [カット・ベル対を用いた動的回路のベンチマーク](/docs/tutorials/edc-cut-bell-pair-benchmarking)\n",
        "  * [動的回路を用いたキック付きアイジング・ハミルトニアンのシミュレーション](/docs/tutorials/dc-hex-ising)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cc5af2f9",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## 参照\n",
        "\n",
        "<a id=\"ref-1\" />\n",
        "\n",
        "\\[1] ダイナミック回路を用いた効率的な長距離エンタングルメント, 著 *Elisa Bäumer, Vinay Tripathi, Derek S. Wang, Patrick Rall, Edward H. Chen, Swarnadeep Majumder, Alireza Seif, Zlatko K. Minev*. IBM クァンタム、（2023年）。\n",
        "[https://arxiv.org/abs/2308.13065](https://arxiv.org/abs/2308.13065)\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": 240
  },
  "nbformat": 4,
  "nbformat_minor": 5
}