{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "4cb32582",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"트랜스파일러 패스에서 DAG 작업\"\n",
        "description: \"Qiskit 트랜스파일러 패스에서 양자 회로를 분석하고 변환하기 위한 유향 비순환 그래프(DAG) 활용 방법\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore subdag DAGOpNode qargs cargs dag_drawer couplinglist */}\n",
        "\n",
        "<span id=\"work-with-dags-in-transpiler-passes\" />\n",
        "\n",
        "# 트랜스파일러 패스에서 DAG 작업\n",
        "\n",
        "키스킷에서 트랜스파일레이션 단계 내에서 회로는 DAG를 사용하여 표현됩니다. 일반적으로 DAG는 정점('노드'라고도 함)과 특정 방향으로 정점 쌍을 연결하는 방향이 지정된 에지로 구성됩니다. 이 표현은 개별 `DagNode` 객체로 구성된 `qiskit.dagcircuit.DAGCircuit` 객체를 사용하여 저장됩니다. 순수한 게이트 목록(즉, 넷리스트)에 비해 이 표현의 장점은 작업 간의 정보 흐름이 명시적이어서 변환 결정을 내리기 쉽다는 것입니다.\n",
        "\n",
        "이 가이드에서는 DAG로 작업하고 이를 사용하여 커스텀 트랜스파일러 패스를 작성하는 방법을 설명합니다. 간단한 회로를 구축하고 DAG 표현을 살펴보는 것으로 시작한 다음, 기본 DAG 연산을 살펴보고 사용자 지정 `BasicMapper` 패스를 구현합니다.\n",
        "\n",
        "<span id=\"build-a-circuit-and-examine-its-dag\" />\n",
        "\n",
        "## 회로를 구축하고 그 DAG를 조사하라\n",
        "\n",
        "아래 코드 스니펫은 벨 상태를 준비하고 측정 결과에 따라 $R_Z$ 회전을 적용하는 간단한 회로를 생성하여 DAG를 설명합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "version-info-cell",
      "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.2\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "1d16892a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/1d16892a-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "from qiskit.converters import circuit_to_dag\n",
        "from qiskit.visualization import circuit_drawer\n",
        "from qiskit.visualization.dag_visualization import dag_drawer\n",
        "\n",
        "# Create circuit\n",
        "q = QuantumRegister(3, \"q\")\n",
        "c = ClassicalRegister(3, \"c\")\n",
        "circ = QuantumCircuit(q, c)\n",
        "circ.h(q[0])\n",
        "circ.cx(q[0], q[1])\n",
        "circ.measure(q[0], c[0])\n",
        "\n",
        "# Qiskit 2.0 uses if_test instead of c_if\n",
        "with circ.if_test((c, 2)):\n",
        "    circ.rz(0.5, q[1])\n",
        "\n",
        "circuit_drawer(circ, output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5971b6ed",
      "metadata": {},
      "source": [
        "DAG에는 쿼비트/클릭비트 입력 노드(녹색), 연산 노드(파란색), 출력 노드(빨간색) 등 세 가지 종류의 그래프 노드가 있습니다. 각 에지는 두 노드 간의 데이터 흐름(또는 종속성)을 나타냅니다. qiskit.tools.visualization.dag\\_drawer () 함수를 사용하여 이 회로의 DAG를 확인합니다. ( [그래프 시각화 라이브러리를](https://graphviz.org/download/) 설치하여 실행합니다.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e498faa3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/e498faa3-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Convert to DAG\n",
        "dag = circuit_to_dag(circ)\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b728136",
      "metadata": {},
      "source": [
        "<span id=\"basic-dag-operations\" />\n",
        "\n",
        "## 기본 DAG 연산\n",
        "\n",
        "아래 코드 예시는 노드 액세스, 연산 추가, 서브회로 대체 등 DAG를 사용한 일반적인 작업을 보여줍니다. 이러한 작업은 트랜스파일러 패스를 구축하기 위한 토대가 됩니다.\n",
        "\n",
        "<span id=\"get-all-operation-nodes-in-the-dag\" />\n",
        "\n",
        "## DAG 내의 모든 작업 노드 가져오기\n",
        "\n",
        "`op_nodes()` 메서드는 회로에 있는 `DAGOpNode` 객체의 이터러블 목록을 반환합니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "4f848695",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[DAGOpNode(op=Instruction(name='h', num_qubits=1, num_clbits=0, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>,), cargs=()),\n",
              " DAGOpNode(op=Instruction(name='cx', num_qubits=2, num_clbits=0, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>, <Qubit register=(3, \"q\"), index=1>), cargs=()),\n",
              " DAGOpNode(op=Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), qargs=(<Qubit register=(3, \"q\"), index=0>,), cargs=(<Clbit register=(3, \"c\"), index=0>,)),\n",
              " DAGOpNode(op=Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x7f0a4e275490>, None]), qargs=(<Qubit register=(3, \"q\"), index=1>,), cargs=(<Clbit register=(3, \"c\"), index=0>, <Clbit register=(3, \"c\"), index=1>, <Clbit register=(3, \"c\"), index=2>))]"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "dag.op_nodes()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8f2676b9",
      "metadata": {},
      "source": [
        "각 노드는 `DAGOpNode` 클래스의 인스턴스입니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "5866159f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "node name: if_else\n",
            "op: Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x7f0a4e1b0650>, None])\n",
            "qargs: (<Qubit register=(3, \"q\"), index=1>,)\n",
            "cargs: (<Clbit register=(3, \"c\"), index=0>, <Clbit register=(3, \"c\"), index=1>, <Clbit register=(3, \"c\"), index=2>)\n",
            "condition: (ClassicalRegister(3, 'c'), 2)\n"
          ]
        }
      ],
      "source": [
        "node = dag.op_nodes()[3]\n",
        "print(\"node name:\", node.name)\n",
        "print(\"op:\", node.op)\n",
        "print(\"qargs:\", node.qargs)\n",
        "print(\"cargs:\", node.cargs)\n",
        "print(\"condition:\", node.op.condition)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2560cc1",
      "metadata": {},
      "source": [
        "<span id=\"add-an-operation-to-the-back\" />\n",
        "\n",
        "## 작업 추가하기\n",
        "\n",
        "`apply_operation_back()` 메서드를 사용하여 DAGCircuit의 끝에 연산이 추가됩니다. 회로의 모든 기존 연산이 끝난 후 지정된 게이트가 지정된 큐비트에 작동하도록 추가합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "3c144b49",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/3c144b49-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import HGate\n",
        "\n",
        "dag.apply_operation_back(HGate(), qargs=[q[0]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "80af1d3d",
      "metadata": {},
      "source": [
        "<span id=\"add-an-operation-to-the-front\" />\n",
        "\n",
        "## 전면에 작전 추가\n",
        "\n",
        "`apply_operation_front()` 메서드를 사용하여 DAGCircuit의 시작 부분에 연산이 추가됩니다. 이렇게 하면 회로의 모든 기존 연산 앞에 지정된 게이트가 삽입되어 효과적으로 첫 번째 연산이 실행됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "ed80a69f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/ed80a69f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import CCXGate\n",
        "\n",
        "dag.apply_operation_front(CCXGate(), qargs=[q[0], q[1], q[2]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4bcdf5fe",
      "metadata": {},
      "source": [
        "<span id=\"substitute-a-node-with-a-subcircuit\" />\n",
        "\n",
        "## 노드를 서브회로로 대체하다\n",
        "\n",
        "DAGCircuit에서 특정 연산을 나타내는 노드는 하위 회로로 대체됩니다. 먼저, 원하는 게이트 시퀀스로 새로운 하위 DAG를 구성한 다음 `substitute_node_with_dag()` 을 사용하여 대상 노드를 이 하위 DAG로 대체하여 나머지 회로와의 연결을 유지합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "fdb3dd70",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/fdb3dd70-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit.library import CHGate, U2Gate, CXGate\n",
        "\n",
        "# Build sub-DAG\n",
        "mini_dag = DAGCircuit()\n",
        "p = QuantumRegister(2, \"p\")\n",
        "mini_dag.add_qreg(p)\n",
        "mini_dag.apply_operation_back(CHGate(), qargs=[p[1], p[0]])\n",
        "mini_dag.apply_operation_back(U2Gate(0.1, 0.2), qargs=[p[1]])\n",
        "\n",
        "# Replace CX with mini_dag\n",
        "cx_node = dag.op_nodes(op=CXGate).pop()\n",
        "dag.substitute_node_with_dag(cx_node, mini_dag, wires=[p[0], p[1]])\n",
        "dag_drawer(dag)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "028566f7",
      "metadata": {},
      "source": [
        "모든 변환이 완료되면 DAG를 일반 `QuantumCircuit` 객체로 다시 변환할 수 있습니다. 이것이 트랜스파일러 파이프라인이 작동하는 방식입니다. 회로를 가져와서 DAG 형태로 처리하고 변환된 회로를 출력으로 생성합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "786571f7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/786571f7-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.converters import dag_to_circuit\n",
        "\n",
        "new_circ = dag_to_circuit(dag)\n",
        "circuit_drawer(new_circ, output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f743bb3b",
      "metadata": {},
      "source": [
        "<span id=\"implement-a-basicmapper-pass\" />\n",
        "\n",
        "## BasicMapper 패스 구현\n",
        "\n",
        "DAG 구조는 트랜스파일러 패스를 작성하는 데 활용할 수 있습니다. 아래 예시에서는 `BasicMapper` 패스를 구현하여 큐비트 연결이 제한된 장치에 임의의 회로를 매핑합니다. 추가 지침은 [사용자 지정 트랜스파일러 패스 작성](/docs/guides/custom-transpiler-pass) 가이드를 참조하세요.\n",
        "\n",
        "패스는 `TransformationPass` 로 정의되며, 이는 회로를 수정한다는 의미입니다. 이는 DAG를 레이어별로 순회하며 각 명령어가 디바이스의 커플링 맵에 의해 부과된 제약 조건을 충족하는지 확인하는 방식으로 이루어집니다. 위반이 감지되면 스왑 경로가 결정되고 그에 따라 필요한 스왑 게이트가 삽입됩니다.\n",
        "\n",
        "트랜스파일러 패스를 만들 때 첫 번째 결정은 패스를 `TransformationPass` 에서 상속할지 `AnalysisPass` 에서 상속할지 선택하는 것입니다. 변환 패스는 회로를 수정하기 위해 설계된 반면, 분석 패스는 후속 패스에서 사용할 정보를 추출하기 위한 용도로만 사용됩니다. 그런 다음 주요 기능은 `run(dag)` 메서드에서 구현됩니다. 마지막으로 `qiskit.transpiler.passes` 모듈에 패스를 등록해야 합니다.\n",
        "\n",
        "이 특정 패스에서 DAG는 레이어별로 탐색됩니다(각 레이어에는 분리된 큐비트 집합에 작용하는 연산이 포함되어 있으므로 독립적으로 실행될 수 있음). 각 연산에 대해 커플링 맵 제약 조건이 충족되지 않으면 적절한 스왑 경로를 식별하고 필요한 스왑을 삽입하여 관련된 큐비트를 인접하게 만듭니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "8c0d7e5a",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.transpiler import Layout\n",
        "from qiskit.circuit.library import SwapGate\n",
        "\n",
        "\n",
        "class BasicSwap(TransformationPass):\n",
        "    def __init__(self, coupling_map, initial_layout=None):\n",
        "        super().__init__()\n",
        "        self.coupling_map = coupling_map\n",
        "        self.initial_layout = initial_layout\n",
        "\n",
        "    def run(self, dag):\n",
        "        new_dag = DAGCircuit()\n",
        "        for qreg in dag.qregs.values():\n",
        "            new_dag.add_qreg(qreg)\n",
        "        for creg in dag.cregs.values():\n",
        "            new_dag.add_creg(creg)\n",
        "\n",
        "        if self.initial_layout is None:\n",
        "            self.initial_layout = Layout.generate_trivial_layout(\n",
        "                *dag.qregs.values()\n",
        "            )\n",
        "\n",
        "        current_layout = self.initial_layout.copy()\n",
        "\n",
        "        for layer in dag.serial_layers():\n",
        "            subdag = layer[\"graph\"]\n",
        "            for gate in subdag.two_qubit_ops():\n",
        "                q0, q1 = gate.qargs\n",
        "                p0 = current_layout[q0]\n",
        "                p1 = current_layout[q1]\n",
        "\n",
        "                if self.coupling_map.distance(p0, p1) != 1:\n",
        "                    path = self.coupling_map.shortest_undirected_path(p0, p1)\n",
        "                    for i in range(len(path) - 2):\n",
        "                        wire1, wire2 = path[i], path[i + 1]\n",
        "                        qubit1 = current_layout[wire1]\n",
        "                        qubit2 = current_layout[wire2]\n",
        "                        new_dag.apply_operation_back(\n",
        "                            SwapGate(), qargs=[qubit1, qubit2]\n",
        "                        )\n",
        "                        current_layout.swap(wire1, wire2)\n",
        "\n",
        "            new_dag.compose(\n",
        "                subdag, qubits=current_layout.reorder_bits(new_dag.qubits)\n",
        "            )\n",
        "\n",
        "        return new_dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a95eaab",
      "metadata": {},
      "source": [
        "이제 작은 예제 회로에서 패스를 테스트할 수 있습니다. 새로 정의된 패스가 포함된 패스 관리자가 구성됩니다. 그런 다음 예제 회로를 이 패스 관리자에게 제공하면 변환된 새로운 회로가 출력으로 얻어집니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "2f35375f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/DAG-representation/extracted-outputs/2f35375f-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler import CouplingMap, PassManager\n",
        "from qiskit import QuantumRegister, QuantumCircuit\n",
        "\n",
        "q = QuantumRegister(7, \"q\")\n",
        "in_circ = QuantumCircuit(q)\n",
        "in_circ.h(q[0])\n",
        "in_circ.cx(q[0], q[4])\n",
        "in_circ.cx(q[2], q[3])\n",
        "in_circ.cx(q[6], q[1])\n",
        "in_circ.cx(q[5], q[0])\n",
        "in_circ.rz(0.1, q[2])\n",
        "in_circ.cx(q[5], q[0])\n",
        "\n",
        "coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]\n",
        "coupling_map = CouplingMap(couplinglist=coupling)\n",
        "\n",
        "pm = PassManager()\n",
        "pm.append(BasicSwap(coupling_map))\n",
        "\n",
        "out_circ = pm.run(in_circ)\n",
        "\n",
        "in_circ.draw(output=\"mpl\")\n",
        "out_circ.draw(output=\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56b80ce3",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * [사용자 정의 트랜스파일러 패스](/docs/guides/custom-transpiler-pass) 생성에 관한 가이드를 확인해 보세요\n",
        "  * [사용자 정의 백엔드를 사용하여](/docs/guides/custom-backend) 빌드하고 트랜스파일하는 방법을 알아보세요\n",
        "  * [Compare 트랜스파일러 설정](/docs/guides/circuit-transpilation-settings) 가이드를 시도해 보세요.\n",
        "  * [DAG 서킷 API](/docs/api/qiskit/dagcircuit) 문서를 검토하십시오.\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
}