{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "3e0865c2",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"ワークロードでポストセレクションを使用する\"\n",
        "description: \"エラー軽減戦略の一環として、ポストセレクションをどのように組み込むかを理解する\"\n",
        "---\n",
        "\n",
        "<span id=\"use-postselection-in-workloads\" />\n",
        "\n",
        "# ワークロードでポストセレクションを使用する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "23b642e2",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"パッケージ・バージョン\">\n",
        "    このページのコードは、以下の要件に基づいて開発されました。\n",
        "    これらのバージョン以降のご利用をお勧めします。\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.1\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    qiskit-addon-utils~=0.4.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b042e4d5",
      "metadata": {},
      "source": [
        "ワークロードのエラー軽減戦略を最適化する際、非マルコフ的（相関のある）ノイズ過程によって汚染されていることが分かっている測定値をフィルタリングすることが、しばしば有用である。 そのための手法の一つとして、回路の最後に後処理ステップを追加する方法がある。このステップでは、アクティブな量子ビットと隣接する「傍観者」量子ビットを測定し、各量子ビットに緩やかな回転を適用した後、再度測定を行う。 2つの測定結果が予想通り反転した量子ビットであることを確認できない場合、結果にマスクを適用してそのショットを破棄する。\n",
        "\n",
        "[Qiskitアドオンユーティリティ](https://qiskit.github.io/qiskit-addon-utils/)パッケージは、一連のトランスパイラパスと、マスクを適用するためのポストセレクション関数を提供します。 このページでは、4量子ビットのGHZ状態を例に、量子ワークロードにポストセレクションを組み込む方法について解説します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a645f8ff",
      "metadata": {},
      "source": [
        "<span id=\"create-workload\" />\n",
        "\n",
        "## CREATE WORKLOAD\n",
        "\n",
        "まず、小数点演算ゲートをサポートするバックエンドに対して実行およびトランスパイルを行うための回路を準備します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "68fa9100",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/post-selection/extracted-outputs/68fa9100-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit.circuit import QuantumCircuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "circuit = QuantumCircuit(4)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.cx(1, 2)\n",
        "circuit.cx(2, 3)\n",
        "circuit.measure_all()\n",
        "\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(use_fractional_gates=True)\n",
        "pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
        "\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "transpiled_circuit.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5adeb935",
      "metadata": {},
      "source": [
        "<span id=\"add-postselection-transpiler-passes\" />\n",
        "\n",
        "## ポストセレクション・トランスパイラ・パスを追加する\n",
        "\n",
        "次に、パッケージ [`qiskit-addon-utils`](https://qiskit.github.io/qiskit-addon-utils/index.html) 内の および [`AddSpectatorMeasures`](https://qiskit.github.io/qiskit-addon-utils/stubs/qiskit_addon_utils.noise_management.post_selection.transpiler.passes.AddPostSelectionMeasures.html) パスを [`AddPostSelectionMeasures`](https://qiskit.github.io/qiskit-addon-utils/stubs/qiskit_addon_utils.noise_management.post_selection.transpiler.passes.AddSpectatorMeasures.html) 含むプリセット・パス・マネージャーを作成します。 これにより、回路に一連の微小な角度 `RX` の回転（実質的に長い `X` ゲートを形成する）が追加され、さらに2つ目の測定セットが実行されます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "faf50950",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/post-selection/extracted-outputs/faf50950-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler import PassManager\n",
        "from qiskit_addon_utils.noise_management.post_selection import PostSelector\n",
        "from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (\n",
        "    AddPostSelectionMeasures,\n",
        "    AddSpectatorMeasures,\n",
        ")\n",
        "\n",
        "\n",
        "post_selection_pm = PassManager(\n",
        "    [\n",
        "        AddSpectatorMeasures(backend.coupling_map, add_barrier=True),\n",
        "        AddPostSelectionMeasures(x_pulse_type=\"rx\"),\n",
        "    ]\n",
        ")\n",
        "\n",
        "template_circuit_ps = post_selection_pm.run(transpiled_circuit)\n",
        "template_circuit_ps.draw(\"mpl\", fold=-1, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e0fdf29d",
      "metadata": {},
      "source": [
        "<span id=\"execute-quantum-program\" />\n",
        "\n",
        "## 量子プログラムを実行する\n",
        "\n",
        "次に、実行する回路を含むオブジェクト `QuantumProgram` を用意します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "649aef44",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: d9mqa4fbupns73e942q0\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import QuantumProgram, Executor\n",
        "\n",
        "shots = 4000\n",
        "\n",
        "program = QuantumProgram(shots=shots)\n",
        "program.append_circuit_item(template_circuit_ps)\n",
        "\n",
        "# Initialize the Executor job and run\n",
        "executor = Executor(backend)\n",
        "executor_job = executor.run(program)\n",
        "print(f\"Job ID: {executor_job.job_id()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4068dd8f",
      "metadata": {},
      "source": [
        "これで結果の解釈が可能になります。 実行結果は、いくつかのキーを持つ辞書となります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "64f52429",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "KeysView(QuantumProgramItemResult({'meas': array([[False, False, False, False],\n",
              "       [ True,  True,  True,  True],\n",
              "       [False, False, False, False],\n",
              "       ...,\n",
              "       [ True,  True,  True,  True],\n",
              "       [ True,  True,  True,  True],\n",
              "       [False, False, False, False]], shape=(4000, 4)), 'spec': array([[False, False, False, False],\n",
              "       [False, False, False, False],\n",
              "       [False, False, False, False],\n",
              "       ...,\n",
              "       [False, False, False, False],\n",
              "       [False, False, False, False],\n",
              "       [False, False, False, False]], shape=(4000, 4)), 'meas_ps': array([[ True,  True,  True,  True],\n",
              "       [False, False, False, False],\n",
              "       [ True,  True,  True,  True],\n",
              "       ...,\n",
              "       [False, False,  True, False],\n",
              "       [False, False, False, False],\n",
              "       [ True,  True,  True,  True]], shape=(4000, 4)), 'spec_ps': array([[ True,  True,  True,  True],\n",
              "       [ True,  True,  True,  True],\n",
              "       [ True,  True, False,  True],\n",
              "       ...,\n",
              "       [ True,  True,  True,  True],\n",
              "       [ True,  True,  True,  True],\n",
              "       [ True,  True,  True,  True]], shape=(4000, 4))}, metadata=ItemMetadata()))"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "executor_result = executor_job.result()[0]\n",
        "executor_result.keys()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6b460888",
      "metadata": {},
      "source": [
        "`spec_ps``spec`これらのキーは、命令 `rx` （`meas` および）実行前のアクティブ量子ビットおよびスペクテーター量子ビット、ならびに命令 `rx` （`meas_ps` および）実行後のアクティブ量子ビットおよびスペクテーター量子ビットに対応しています。 これらはそれぞれ、ショット数と量子ビット数に基づいた配列の配列です。 この場合、形状は (1000, 4) です。\n",
        "\n",
        "<span id=\"create-postselection-mask\" />\n",
        "\n",
        "## ポストセレクションマスクを作成する\n",
        "\n",
        "`qiskit-addon-utils`これらの測定値をもとに、の [`PostSelector`](https://qiskit.github.io/qiskit-addon-utils/apidocs/qiskit_addon_utils.noise_management.html#qiskit_addon_utils.noise_management.PostSelector) クラスを使用してマスクを作成できます。 このマスクはブール配列であり、各ショットは2つのポストセレクション戦略のいずれかに基づいて、または `False``True` としてマークされます。 `edge``node`最初の戦略は、量子ビットの情報を利用して測定ショットを破棄すべきかどうかを判断するものであり、2つ目の戦略は、最近接の接続情報を利用してこの判断を行うものである。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "299d460d",
      "metadata": {},
      "outputs": [],
      "source": [
        "post_selector = PostSelector.from_circuit(\n",
        "    circuit=template_circuit_ps, coupling_map=backend.coupling_map\n",
        ")\n",
        "\n",
        "mask_node = post_selector.compute_mask(executor_result, strategy=\"node\")\n",
        "mask_edge = post_selector.compute_mask(executor_result, strategy=\"edge\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "023cb624",
      "metadata": {},
      "source": [
        "ノード戦略とエッジ戦略のどちらも、しばしば異なるショットを破棄することがある。 どれでもお選びいただけます。 このノートブックではビット単位のAND演算を採用しています。これは、ノード戦略とエッジ戦略の両方で通過判定されたショットのみを保持するという、保守的な戦略です。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "5ec9bc4a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The combined mask: [ True  True False ... False  True  True]\n",
            "Percentage of the shots retained is after post selection 70.35\n"
          ]
        }
      ],
      "source": [
        "mask = mask_node & mask_edge\n",
        "print(f\"The combined mask: {mask}\")\n",
        "count_retained = 0\n",
        "\n",
        "for m in mask:\n",
        "    count_retained += m\n",
        "\n",
        "print(\n",
        "    f\"Percentage of the shots retained is after post selection \"\n",
        "    f\"{100 * count_retained / shots}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "77a9c1af",
      "metadata": {},
      "source": [
        "事後選択を行う場合と行わない場合で、確率分布を比較してください。 以下のコードスニペットは、ポストセレクションの前後における確率分布を計算するとともに、観測された分布と理想的な分布との間の距離を算出します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "43704cfc",
      "metadata": {},
      "outputs": [],
      "source": [
        "counts = {}\n",
        "counts_ps = {}\n",
        "\n",
        "\n",
        "for idx, measurement in enumerate(executor_result[\"meas\"]):\n",
        "    bitstring = \"\"\n",
        "    for bit in measurement:\n",
        "        bitstring += str(int(bit))\n",
        "\n",
        "    if bitstring in counts:\n",
        "        counts[bitstring] += 1\n",
        "    else:\n",
        "        counts[bitstring] = 1\n",
        "\n",
        "    # Compute count data for postselected shots based on the mask\n",
        "    if mask[idx]:\n",
        "        bitstring = \"\"\n",
        "        for bit in measurement:\n",
        "            bitstring += str(int(bit))\n",
        "\n",
        "        if bitstring in counts_ps:\n",
        "            counts_ps[bitstring] += 1\n",
        "        else:\n",
        "            counts_ps[bitstring] = 1\n",
        "\n",
        "for key, val in counts.items():\n",
        "    counts[key] = val / shots\n",
        "\n",
        "\n",
        "for key, val in counts_ps.items():\n",
        "    counts_ps[key] = float(val / count_retained)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "16551af2",
      "metadata": {},
      "source": [
        "事後選択が結果にどのような影響を与えたかを確認するために、理想的な確率分布と測定された確率分布との間の距離を計算してください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "b1ba31b9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Distance from ideal distribution before postselection: 0.95225\n",
            "Distance from ideal distribution before after-selection: 0.939587775408671\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/post-selection/extracted-outputs/b1ba31b9-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import itertools\n",
        "from qiskit.visualization import plot_histogram\n",
        "\n",
        "bitstrings = [\"\".join(i) for i in itertools.product(\"01\", repeat=4)]\n",
        "counts_ideal = {}\n",
        "for bitstring in bitstrings:\n",
        "    counts_ideal[bitstring] = 0.0\n",
        "counts_ideal[\"1111\"] = 0.5\n",
        "counts_ideal[\"0000\"] = 0.5\n",
        "\n",
        "\n",
        "prob_distance = 0.0\n",
        "prob_distance_ps = 0.0\n",
        "\n",
        "for bitstring in counts_ideal.keys():\n",
        "    dist = 0.0\n",
        "    dist_ps = 0.0\n",
        "    if bitstring in counts:\n",
        "        dist = abs(counts[bitstring] - counts_ideal[bitstring])\n",
        "    if bitstring in counts_ps:\n",
        "        dist_ps = abs(counts_ps[bitstring] - counts_ideal[bitstring])\n",
        "    prob_distance += dist\n",
        "    prob_distance_ps += dist_ps\n",
        "\n",
        "\n",
        "print(\n",
        "    f\"Distance from ideal distribution before postselection: \"\n",
        "    f\"{1-prob_distance*0.5}\"\n",
        ")\n",
        "print(\n",
        "    f\"Distance from ideal distribution before after-selection: \"\n",
        "    f\"{1-prob_distance_ps*0.5}\"\n",
        ")\n",
        "\n",
        "\n",
        "plot_histogram([counts, counts_ps], legend=[\"Normal\", \"Post selected\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c205afea",
      "metadata": {},
      "source": [
        "事後選択は、非マルコフ的ノイズの影響を受けた結果測定値を排除することで結果の質を大幅に向上させることができるが、それだけでは誤差低減の完全な解決策とはならない。 事後選択は、無効な測定結果を排除することで特定のエラーの影響を軽減するが、その代償としてサンプリングのオーバーヘッドが増大し、また、近未来の量子ハードウェアに存在するすべてのエラーメカニズムに対処できるわけではない。 その結果、より複雑あるいは深層の回路においては、ポストセレクションのみに依存するだけでは不十分であると考えられる。 むしろ、ポストセレクションは、測定誤差の低減、ノイズを考慮した回路コンパイル、確率的誤差相殺といった手法を補完する形で、より広範な誤差低減戦略の一環として活用される場合に最も効果的であり、精度とリソースコストのバランスを取りながら量子ワークロードの信頼性を向上させることができる。\n",
        "\n",
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  * [ノイズ学習を](/docs/guides/noise-learning)量子ワークロードに組み込む方法を理解する。\n",
        "  * 利用可能なその他の[エラー軽減および抑制](/docs/guides/error-mitigation-and-suppression-techniques)手法について確認してください。\n",
        "  * オーバーヘッドの少ないエラー検出手法として、 [時空間符号](/docs/tutorials/spacetime-codes)を活用する方法について学びましょう\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}