{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "710d86a8-3243-4133-b7bc-093306598512",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"カスタム・トランスパイラー・パスを書く\"\n",
        "description: \"Qiskitを使用した独自のトランスパイラパスの書き方を学びます。DAG回路表現を含みます\"\n",
        "---\n",
        "\n",
        "<span id=\"write-a-custom-transpiler-pass\" />\n",
        "\n",
        "# カスタム・トランスパイラー・パスを書く\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a66bd4b-56b1-4f33-b1bf-b43dbc7c03a7",
      "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",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "32806873-3c88-48fc-94ad-9d20e0f378f8",
      "metadata": {},
      "source": [
        "Qiskit SDKでは、カスタムトランスピレーションパスを作成し、 `PassManager` オブジェクト内で実行したり、 `StagedPassManager` に追加したりすることができます。 ここでは、量子回路のノイズの多い量子ゲートに対して[パウリ・ツワーリングを](https://arxiv.org/abs/quant-ph/0606161)実行するパスの作成に焦点を当て、トランスパイラ・パスの書き方を示します。 この例ではDAGを使用している。DAGは `TransformationPass` 型のパスで操作されるオブジェクトである。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c49a2046-39b0-4e63-aa63-911845ffd315",
      "metadata": {},
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"背景：DAG表現\">\n",
        "    パスを構築する前に、Qiskitの量子回路の内部表現である[有向無サイクルグラフ（DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) ）を紹介することが重要です（概要については[このチュートリアルを](https://qiskit.org/ecosystem/rustworkx/tutorial/dags.html)参照してください）。  これらの手順を実行するには、DAGプロット関数のための [`graphviz` ライブラリを](https://graphviz.org/download/)インストールします。\n",
        "\n",
        "    Qiskitでは、トランスパイラ段階において、回路は有向非巡回グラフ（DAG）を用いて表現される。  一般的に、有向非循環グラフ（DAG）は\\*、頂点\\* （ノードとも呼ばれる）と、特定の向きで頂点のペアを*接続*する有向辺で構成される。  この表現は、個々の `DagNode` オブジェクトで構成されるオブジェクト `qiskit.dagcircuit.DAGCircuit` を使用して保存されます。  この表現が純粋なゲートリスト（ *すなわちネットリスト* ）に対して持つ利点は、演算間の情報の流れが明示的であるため、変換の決定を下しやすくなる点である。\n",
        "\n",
        "    この例では、測定結果に応じてベル状態を準備し、 $R_Z$ 回転を適用する単純な回路を作成することで、DAGを説明している。\n",
        "\n",
        "    ```python\n",
        "    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "    import numpy as np\n",
        "\n",
        "    qr = QuantumRegister(3, 'qr')\n",
        "    cr = ClassicalRegister(3, 'cr')\n",
        "    qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "    qc.h(qr[0])\n",
        "    qc.cx(qr[0], qr[1])\n",
        "    qc.measure(qr[0], cr[0])\n",
        "    with qc.if_test((cr, 2)):\n",
        "        qc.rz(np.pi/2, qr[1])\n",
        "    qc.draw(output='mpl')\n",
        "\n",
        "    ```\n",
        "\n",
        "    ![ベル状態を準備し、測定結果に応じて R\\_Z 回転を加える回路](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG_circ.avif \"回路\")\n",
        "\n",
        "    この回路のDAGを表示するには、 `qiskit.tools.visualization.dag_drawer()` 。  グラフのノードには3種類ある：量子ビット/軌道ノード（緑）、演算ノード（青）、出力ノード（赤）。  各エッジは、2つのノード間のデータの流れ（または依存関係）を示す。\n",
        "\n",
        "    ```python\n",
        "    from qiskit.converters import circuit_to_dag\n",
        "    from qiskit.visualization import dag_drawer\n",
        "\n",
        "    dag = circuit_to_dag(qc)\n",
        "    dag_drawer(dag)\n",
        "    ```\n",
        "\n",
        "    ![回路のDAGは、方向エッジで接続されたノードで構成される。 これは、量子ビットや古典的なビット、操作、データの流れ方を視覚的に表現する方法である。](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG.avif \"DAG\")\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e2e2bc6-c900-4d3b-a948-3f5d154cdea2",
      "metadata": {},
      "source": [
        "<span id=\"transpiler-passes\" />\n",
        "\n",
        "## トランスパイラ通過\n",
        "\n",
        "トランスパイラのパスは、または [`AnalysisPass`](../api/qiskit/qiskit.transpiler.AnalysisPass) に分類されます [`TransformationPass`](../api/qiskit/qiskit.transpiler.TransformationPass)。 パスは一般的に、 [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) および（解析パスによって決定されたプロパティを格納するための辞書のようなオブジェクト） `property_set`と連携して動作します。 分析パスは、DAGとその `property_set`.の両方で機能します。  彼らはDAGを変更することはできませんが、.を変更することはできます `property_set`。  これに対し、トランスフォーメーション・パスはDAGを変更するものであり、DAGを読み取ることはできるが（書き込みはできない） `property_set`。  例えば、変換パスでは回路を[そのISA](/docs/guides/transpile#instruction-set-architecture) に変換したり、ルーティングパスを実行して必要な場所にSWAPゲートを挿入したりします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8ead728-b2b7-47b9-b3b1-f3578b594ffe",
      "metadata": {},
      "source": [
        "<span id=\"create-a-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## トランスパイラパス `PauliTwirl` を作成する\n",
        "\n",
        "以下の例では、パウリ・ツワールを追加するトランスパイラー・パスを構築している。 [パウリ・ツワーリングは](https://arxiv.org/abs/quant-ph/0606161)、量子ビットがどのようにノイズの多いチャネルを経験するかをランダムにするエラー抑制戦略であり、この例では2量子ビットゲートを想定している（1量子ビットゲートよりもはるかにエラーが発生しやすいため）。 パウリの回転は2量子ビットのゲートの動作には影響しない。 それらは、2量子ビットゲートの*前* （左側）に適用されたものが、2量子ビットゲートの*後* （右側）に適用されたものによって打ち消されるように選ばれる。 この意味で、2量子ビットの演算は同じだが、その方法は異なる。 パウリ・ツワーリングの利点のひとつは、コヒーレント誤差を確率的誤差に変えることで、より平均化することで改善できることだ。\n",
        "\n",
        "Transpilerは [DAGに](../api/qiskit/qiskit.dagcircuit.DAGCircuit)作用するので、オーバーライドする重要なメソッドは `.run()`、DAGを入力として受け取る。 このようにポーリスのペアを初期化することで、各2量子ビットゲートの動作が保持される。 これはヘルパーメソッド `build_twirl_set` を使って行われる。ヘルパーメソッドは、（ `pauli_basis(2)` から得られるような）各2量子ビットパウリを調べ、演算を保持するもう1つのパウリを見つける。\n",
        "\n",
        "DAG から、 `op_nodes()` メソッドを使用して、そのすべてのノードを返す。 DAGは、量子ビット上で途切れることなく実行されるノードのシーケンスであるランを収集するためにも使用できる。 これらは、 `collect_1q_runs` で1量子ビットラン、 `collect_2q_runs` で2量子ビットラン、 `collect_runs` で命令名がネームリストにあるノードのランとして収集できる。  `DAGCircuit` には、グラフを検索したり走査したりするための多くのメソッドがある。  よく使われる方法の1つは、 `topological_op_nodes`、依存関係の順序でノードを提供する。 `bfs_successors` などの他の方法は、主にノードがDAG上の後続の操作とどのように相互作用するかを決定するために使用される。\n",
        "\n",
        "この例では、命令を表す各ノードを、ミニDAGとして構築されたサブサーキットで置き換えたい。 ミニDAGには2量子ビットの量子レジスタが追加されている。  オペレーションは、 `apply_operation_back` を使ってミニDAGに追加される。これは、 `Instruction` をミニDAGの出力に配置する（一方、 `apply_operation_front` はミニDAGの入力に配置する）。 このノードは、 `substitute_node_with_dag` を使ってミニDAGで代用され、DAG内の `CXGate` と `ECRGate` の各インスタンス（ IBM® バックエンドの2量子ビット基底ゲートに対応）に対してプロセスが続けられる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "80546e59-dcd8-4b61-88b5-00b220409f6d",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, Gate\n",
        "from qiskit.circuit.library import CXGate, ECRGate\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.quantum_info import Operator, pauli_basis\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "from typing import Iterable, Optional"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6bb6ff72-43dd-4f8c-a67c-b43af2548b2a",
      "metadata": {},
      "outputs": [],
      "source": [
        "class PauliTwirl(TransformationPass):\n",
        "    \"\"\"Add Pauli twirls to two-qubit gates.\"\"\"\n",
        "\n",
        "    def __init__(\n",
        "        self,\n",
        "        gates_to_twirl: Optional[Iterable[Gate]] = None,\n",
        "    ):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            gates_to_twirl: Names of gates to twirl. The default behavior is to twirl all\n",
        "                two-qubit basis gates, `cx` and `ecr` for IBM backends.\n",
        "        \"\"\"\n",
        "        if gates_to_twirl is None:\n",
        "            gates_to_twirl = [CXGate(), ECRGate()]\n",
        "        self.gates_to_twirl = gates_to_twirl\n",
        "        self.build_twirl_set()\n",
        "        super().__init__()\n",
        "\n",
        "    def build_twirl_set(self):\n",
        "        \"\"\"\n",
        "        Build a set of Paulis to twirl for each gate and store internally as .twirl_set.\n",
        "        \"\"\"\n",
        "        self.twirl_set = {}\n",
        "\n",
        "        # iterate through gates to be twirled\n",
        "        for twirl_gate in self.gates_to_twirl:\n",
        "            twirl_list = []\n",
        "\n",
        "            # iterate through Paulis on left of gate to twirl\n",
        "            for pauli_left in pauli_basis(2):\n",
        "                # iterate through Paulis on right of gate to twirl\n",
        "                for pauli_right in pauli_basis(2):\n",
        "                    # save pairs that produce identical operation as gate to twirl\n",
        "                    if (Operator(pauli_left) @ Operator(twirl_gate)).equiv(\n",
        "                        Operator(twirl_gate) @ pauli_right\n",
        "                    ):\n",
        "                        twirl_list.append((pauli_left, pauli_right))\n",
        "\n",
        "            self.twirl_set[twirl_gate.name] = twirl_list\n",
        "\n",
        "    def run(\n",
        "        self,\n",
        "        dag: DAGCircuit,\n",
        "    ) -> DAGCircuit:\n",
        "        # collect all nodes in DAG and proceed if it is to be twirled\n",
        "        twirling_gate_classes = tuple(\n",
        "            gate.base_class for gate in self.gates_to_twirl\n",
        "        )\n",
        "        for node in dag.op_nodes():\n",
        "            if not isinstance(node.op, twirling_gate_classes):\n",
        "                continue\n",
        "\n",
        "            # random integer to select Pauli twirl pair\n",
        "            pauli_index = np.random.randint(\n",
        "                0, len(self.twirl_set[node.op.name])\n",
        "            )\n",
        "            twirl_pair = self.twirl_set[node.op.name][pauli_index]\n",
        "\n",
        "            # instantiate mini_dag and attach quantum register\n",
        "            mini_dag = DAGCircuit()\n",
        "            register = QuantumRegister(2)\n",
        "            mini_dag.add_qreg(register)\n",
        "\n",
        "            # apply left Pauli, gate to twirl, and right Pauli to empty mini-DAG\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[0].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "            mini_dag.apply_operation_back(node.op, [register[0], register[1]])\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[1].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "\n",
        "            # substitute gate to twirl node with twirling mini-DAG\n",
        "            dag.substitute_node_with_dag(node, mini_dag)\n",
        "\n",
        "        return dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da136beb-d1b2-4f68-8274-386e80a49860",
      "metadata": {},
      "source": [
        "<span id=\"use-the-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## トランスパイラパス `PauliTwirl` を使用する\n",
        "\n",
        "以下のコードは、上記で作成したパスを使用して回路をトランスパイルします。 と `ecr``cx` ゲートからなる単純な回路を考えよ。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "9123905d-b4cb-4ae9-9695-4ad77e70bdab",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/9123905d-b4cb-4ae9-9695-4ad77e70bdab-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.cx(0, 1)\n",
        "qc.ecr(1, 2)\n",
        "qc.ecr(1, 0)\n",
        "qc.cx(2, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f112c2af-c99a-4733-8118-4786e2dfdfd3",
      "metadata": {},
      "source": [
        "カスタム・パスを適用するには、 `PauliTwirl` パスを使ってパス・マネージャーを構築し、50 回路で実行します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "ea884cd2-2446-4b2d-a0f7-82ef574b11ee",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm = PassManager([PauliTwirl()])\n",
        "twirled_qcs = [pm.run(qc) for _ in range(50)]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3d4d921e-1a43-4f9a-bc30-6c64092d8f6b",
      "metadata": {},
      "source": [
        "各2量子ビットのゲートは現在、2つのポーリに挟まれている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "e2515cf3-f8d9-4281-9673-d5a955d7aab9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/e2515cf3-f8d9-4281-9673-d5a955d7aab9-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "twirled_qcs[-1].draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41cccfba-8b65-401c-9d30-66396a3fe3a1",
      "metadata": {},
      "source": [
        "`qiskit.quantum_info` 、 `Operator` ：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "0f8b4ca1-4205-4b71-941d-0852eebbe917",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "np.True_"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.all([Operator(twirled_qc).equiv(qc) for twirled_qc in twirled_qcs])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d680854-13f8-4ccd-9be1-595edb4f942c",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  * 独自のパスを書く代わりに `generate_preset_passmanager` 関数を使う方法を学ぶには、 [Transpilation のデフォルト設定と構成オプションの](defaults-and-configuration-options)トピックから始めてください。\n",
        "  * [トランスパイラ設定の比較](/docs/guides/circuit-transpilation-settings)ガイドをお試しください。\n",
        "  * [トランスパイラ API ドキュメント](/docs/api/qiskit/transpiler)を確認してください。\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": 2
}