{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b793601b-95bc-4d36-adfc-c9fc34ce45cd",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"트랜스파일러 단계\"\n",
        "description: \"Qiskit의 양자 회로 트랜스파일레이션 파이프라인의 기본 단계.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize */}\n",
        "\n",
        "<span id=\"transpiler-stages\" />\n",
        "\n",
        "# 트랜스파일러 단계\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a38c84a-eed2-4fa4-9823-3d544e572398",
      "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": "markdown",
      "id": "9f2ecc4b-e6a3-418c-8a65-a9f3ac98c3dc",
      "metadata": {},
      "source": [
        "이 페이지는 키스킷 SDK에서 미리 빌드된 트랜슬레이션 파이프라인의 단계를 설명합니다. 6단계가 있습니다:\n",
        "\n",
        "1. `init`\n",
        "2. `layout`\n",
        "3. `routing`\n",
        "4. `translation`\n",
        "5. `optimization`\n",
        "6. `scheduling`\n",
        "\n",
        "함수는 [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager#qiskit.transpiler.generate_preset_pass_manager) 함수는 이러한 단계로 구성된 사전 설정된 [스테이지 패스 관리자를](/docs/api/qiskit/qiskit.transpiler.StagedPassManager) 생성합니다. 각 단계를 구성하는 구체적인 패스는 `generate_preset_pass_manager` 에 전달되는 인수에 따라 달라집니다. `optimization_level` 은 반드시 지정해야 하는 위치 인자로, 0, 1, 2 또는 3이 될 수 있는 정수입니다. 값이 클수록 최적화가 더 무겁지만 비용이 많이 든다는 의미입니다( [번역 기본값 및 구성 옵션](defaults-and-configuration-options) 참조).\n",
        "\n",
        "서킷을 트랜스파일하는 권장 방법은 [패스 관리자를 사용한 트랜스파일에](transpile-with-pass-managers) 설명된 대로 미리 설정된 스테이지 패스 관리자를 생성한 다음 해당 패스 관리자를 서킷에서 실행하는 것입니다. 그러나 더 간단하지만 사용자 지정이 어려운 대안은 [`transpile`](/docs/api/qiskit/compiler#qiskit.compiler.transpile) 함수를 사용하는 것입니다. 이 함수는 회로를 직접 인수로 받습니다. `generate_preset_pass_manager` 에서와 마찬가지로 사용되는 특정 트랜스파일러 패스는 `transpile` 에 전달된 `optimization_level` 과 같은 인수에 따라 달라집니다. 실제로 내부적으로 `transpile` 함수는 `generate_preset_pass_manager` 을 호출하여 사전 설정된 스테이지 패스 관리자를 생성하고 이를 회로에서 실행합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18140654-10ff-40c5-ab75-4d19b8a7f5dd",
      "metadata": {},
      "source": [
        "<span id=\"init-stage\" />\n",
        "\n",
        "## 초기화 단계\n",
        "\n",
        "이 첫 번째 단계는 기본적으로 거의 수행하지 않으며 주로 자체 초기 최적화를 포함하려는 경우에 유용합니다.  대부분의 레이아웃 및 라우팅 알고리즘은 단일 및 2큐비트 게이트에서만 작동하도록 설계되었기 때문에 이 단계는 2큐비트 이상에서 작동하는 모든 게이트를 1 또는 2큐비트에서만 작동하는 게이트로 변환하는 데에도 사용됩니다.\n",
        "\n",
        "이 단계의 초기 최적화를 직접 구현하는 방법에 대한 자세한 내용은 플러그인 및 패스 관리자 사용자 지정 섹션을 참조하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "506a831f-b317-4335-8124-20ed994292cd",
      "metadata": {},
      "source": [
        "<span id=\"layout-stage\" />\n",
        "\n",
        "## 레이아웃 단계\n",
        "\n",
        "다음 단계에서는 신호가 전송될 백엔드의 레이아웃 또는 연결 방식을 결정합니다.  일반적으로 양자 회로는 추상적인 개념으로, 그 큐비트들은 계산에 사용되는 실제 큐비트를 “가상” 또는 “논리적”으로 표현한 것이다.  일련의 게이트 연산을 수행하려면, “가상” 큐비트와 실제 양자 장치 내의 “물리적” 큐비트 간에 일대일 대응 관계가 필요합니다.  이 매핑은 객체로 `Layout` 저장되며, 백엔드의 [명령어 집합 아키텍처(ISA)](/docs/guides/transpile#instruction-set-architecture) 내에서 정의된 제약 조건의 일부입니다.\n",
        "\n",
        "![이 이미지는 큐비트가 와이어 표현에서 QPU 내 큐비트 연결 방식을 나타내는 다이어그램으로 매핑되는 과정을 보여줍니다. ](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/layout-mapping.svg \"큐비트 매핑\")\n",
        "\n",
        "매핑 선택은 입력 회로를 디바이스 토폴로지에 매핑하고 가장 잘 보정된 큐비트가 사용되도록 하는 데 필요한 SWAP 연산 횟수를 최소화하는 데 매우 중요합니다.  이 단계의 중요성 때문에 프리셋 패스 관리자는 최적의 레이아웃을 찾기 위해 몇 가지 다른 방법을 시도합니다.  일반적으로 이 작업에는 두 단계가 포함됩니다. 먼저 '완벽한' 레이아웃(스왑 작업이 필요 없는 레이아웃)을 찾은 다음, 완벽한 레이아웃을 찾을 수 없는 경우 사용할 최적의 레이아웃을 찾는 휴리스틱 패스를 시도합니다.  이 첫 번째 단계에는 일반적으로 `Passes` 두 개가 사용됩니다:\n",
        "\n",
        "* `TrivialLayout`: 각 가상 큐비트를 장치의 동일한 번호가 매겨진 물리적 큐비트에 순진하게 매핑합니다(예: \\[`0`,`1`,`1`,`3`] -> \\[`0`,`1`,`1`,`3`] ). 이것은 단지 사용된 역사적 동작입니다. `optimzation_level=1` 완벽한 레이아웃을 찾으려고 노력합니다.  실패하면 `VF2Layout` 이 다음에 시도됩니다.\n",
        "* `VF2Layout`: 이 단계를 하위 그래프 동형 문제( VF2++ 알고리즘으로 해결)로 처리하여 이상적인 레이아웃을 선택하는 `AnalysisPass` 입니다.  레이아웃이 두 개 이상 발견되면 채점 휴리스틱이 실행되어 평균 오류가 가장 낮은 매핑을 선택합니다.\n",
        "\n",
        "그런 다음 휴리스틱 단계에서는 기본적으로 두 개의 패스가 사용됩니다:\n",
        "\n",
        "* `DenseLayout`: 연결성이 가장 높고 회로와 동일한 수의 큐비트를 가진 장치의 하위 그래프를 찾습니다(회로에 제어 흐름 연산(예: IfElseOp )이 있는 경우 최적화 레벨 1에 사용됨).\n",
        "* `SabreLayout`이 패스는 초기 무작위 레이아웃에서 시작하여 알고리즘을 `SabreSwap` 반복적으로 실행함으로써 레이아웃을 선택합니다.  이 패스는 최적화 레벨 1, 2, 3에서만 사용되며, 해당 `VF2Layout` 패스를 통해 완벽한 레이아웃이 발견되지 않을 경우에만 적용됩니다.  이 알고리즘에 대한 자세한 내용은 논문 ' [arXiv:1809.02573](https://arxiv.org/abs/1809.02573) '를 참조하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf772b6c-2578-455d-8014-9a7de2f9db19",
      "metadata": {},
      "source": [
        "<span id=\"routing-stage\" />\n",
        "\n",
        "## 라우팅 단계\n",
        "\n",
        "양자 디바이스에서 직접 연결되지 않은 큐비트 사이에 2큐비트 게이트를 구현하려면 하나 이상의 SWAP 게이트를 회로에 삽입하여 디바이스 게이트 맵에서 인접할 때까지 큐비트 상태를 이동시켜야 합니다.  각 스왑 게이트는 수행 비용이 많이 들고 소음이 많은 연산을 나타냅니다.  따라서 회로를 주어진 디바이스에 매핑하는 데 필요한 최소 SWAP 게이트 수를 찾는 것은 트랜스필레이션 프로세스에서 중요한 단계입니다.  효율성을 위해 이 단계는 일반적으로 기본적으로 레이아웃 단계와 함께 계산되지만 논리적으로 서로 구분됩니다.  *레이아웃* 단계에서는 사용할 하드웨어 큐비트를 선택하고, *라우팅* 단계에서는 선택한 레이아웃을 사용하여 회로를 실행하기 위해 적절한 양의 스왑 게이트를 삽입합니다.\n",
        "\n",
        "하지만 최적의 SWAP 매핑을 찾는 것은 어려운 일입니다.  사실 이 문제는 NP-하드 문제이므로 가장 작은 양자 장치와 입력 회로를 제외하고는 모두 계산하는 데 엄청난 비용이 듭니다.  이 문제를 해결하기 위해 키스킷은 `SabreSwap` 이라는 확률적 휴리스틱 알고리즘을 사용하여 최적은 아니지만 좋은 스왑 매핑을 계산합니다. 확률적 방법을 사용한다는 것은 반복 실행 시 생성되는 회로가 동일하다는 보장이 없다는 것을 의미합니다.  실제로 동일한 회로를 반복적으로 실행하면 출력에서 회로 깊이와 게이트 수의 분포가 달라집니다.  이러한 이유로 많은 사용자가 라우팅 기능(또는 전체 `StagedPassManager`)을 여러 번 실행하고 출력 분포에서 가장 깊이가 낮은 회로를 선택합니다.\n",
        "\n",
        "예를 들어 \"나쁜\"(연결이 끊어진) `initial_layout` 을 사용하여 100회 실행된 15-큐비트 GHZ 회로를 예로 들어 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "62479697-cef1-4a89-ac2a-20051dd294f4",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'Counts')"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/62479697-cef1-4a89-ac2a-20051dd294f4-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.providers.fake_provider import GenericBackendV2\n",
        "\n",
        "backend = GenericBackendV2(15)\n",
        "\n",
        "\n",
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "for seed in range(100):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=1,\n",
        "        backend=backend,\n",
        "        layout_method=\"trivial\",  # Fixed layout mapped in circuit order\n",
        "        seed_transpiler=seed,  # For reproducible results\n",
        "    )\n",
        "    depths.append(pass_manager.run(ghz).depth())\n",
        "\n",
        "plt.figure(figsize=(8, 6))\n",
        "plt.hist(depths, align=\"left\", color=\"#AC557C\")\n",
        "plt.xlabel(\"Depth\", fontsize=14)\n",
        "plt.ylabel(\"Counts\", fontsize=14)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff31f484-a816-4479-8827-d56641501319",
      "metadata": {},
      "source": [
        "이 넓은 분포는 SWAP 매퍼가 최적의 매핑을 계산하는 것이 얼마나 어려운지를 보여줍니다.  인사이트를 얻기 위해 실행 중인 회로와 하드웨어에서 선택된 큐비트를 모두 살펴봅시다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "ab89c4ea-06c4-4320-b493-feb691b3570d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ab89c4ea-06c4-4320-b493-feb691b3570d-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz.draw(\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f6a3a92a-8656-4518-ba2c-c3b0b038f507",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/f6a3a92a-8656-4518-ba2c-c3b0b038f507-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.visualization import plot_circuit_layout\n",
        "\n",
        "# Plot the hardware graph and indicate which hardware qubits were chosen to run the circuit\n",
        "transpiled_circ = pass_manager.run(ghz)\n",
        "plot_circuit_layout(transpiled_circ, backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ec2818a-8087-42ba-990d-b3c1258dbf35",
      "metadata": {},
      "source": [
        "보시다시피, 이 회로는 연결 그래프에서 매우 멀리 떨어져 있는 큐비트 0과 14 사이에서 2큐비트 게이트를 실행해야 합니다.  따라서 이 회로를 실행하려면 `SabreSwap` 패스를 사용하여 모든 2쿼비트 게이트를 실행하기 위해 스왑 게이트를 삽입해야 합니다.\n",
        "\n",
        "`SabreSwap` 알고리즘은 이전 단계의 더 큰 `SabreLayout` 방법과 다르다는 점도 참고하세요.  기본적으로 `SabreLayout` 은 레이아웃과 라우팅을 모두 실행하고 변환된 회로를 반환합니다.  이는 패스의 [API 참조 페이지에](../api/qiskit/qiskit.transpiler.passes.SabreLayout) 명시된 몇 가지 특정 기술적인 이유로 인해 수행됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "650f978b-d992-4d67-a356-5bf73902f212",
      "metadata": {},
      "source": [
        "<span id=\"translation-stage\" />\n",
        "\n",
        "## 번역 단계\n",
        "\n",
        "양자 회로를 작성할 때는 원하는 양자 게이트(유니터리 연산)를 자유롭게 사용할 수 있으며, 큐비트 측정이나 리셋 명령어와 같은 게이트가 아닌 연산들도 함께 활용할 수 있습니다.  그러나 대부분의 양자 장치는 기본적으로 소수의 양자 게이트 및 비게이트 연산만 지원한다.  이러한 네이티브 게이트는 대상의 [ISA](/docs/guides/transpile#instruction-set-architecture) 정의의 일부이며, 프리셋의 이 단계에서는 회로에 지정된 게이트를 지정된 `PassManagers` 백엔드의 네이티브 기준 게이트로 변환(또는 *언롤* )합니다.  이는 회로를 백엔드에서 실행할 수 있게 해주기 때문에 중요한 단계이지만, 일반적으로 회로의 깊이와 게이트 수가 증가하게 됩니다.\n",
        "\n",
        "이 단계의 기능을 설명하는 데 도움이 되는 두 가지 특별한 경우를 특히 강조할 필요가 있습니다.\n",
        "\n",
        "1. SWAP 게이트가 타겟 백엔드의 기본 게이트가 아닌 경우 세 개의 CNOT 게이트가 필요합니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "d4d1f65a-3336-4d70-9189-65ba010f2366",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "native gates:['cx', 'delay', 'id', 'measure', 'reset', 'rz', 'sx', 'x']\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/d4d1f65a-3336-4d70-9189-65ba010f2366-1.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\"native gates:\" + str(sorted(backend.operation_names)))\n",
        "qc = QuantumCircuit(2)\n",
        "qc.swap(0, 1)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56347603-8766-4165-af18-1f6fe4c61d4f",
      "metadata": {},
      "source": [
        "3개의 CNOT 게이트의 산물인 스왑은 잡음이 많은 양자 디바이스에서 수행하기에는 비용이 많이 드는 작업입니다.  그러나 이러한 작업은 일반적으로 많은 디바이스의 제한된 게이트 연결에 회로를 내장하는 데 필요합니다.  따라서 트랜스파일레이션 프로세스의 주요 목표는 회로에서 SWAP 게이트 수를 최소화하는 것입니다.\n",
        "\n",
        "2. 토폴리 또는 제어-제어-제어-낫 게이트(`ccx`)는 3비트 게이트입니다.  기본 게이트 세트에는 단일 및 2큐비트 게이트만 포함되어 있으므로 이 연산을 분해해야 합니다.  하지만 비용이 상당히 많이 듭니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "4552b367-75e9-4faa-a59d-8317e25ac145",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/4552b367-75e9-4faa-a59d-8317e25ac145-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.ccx(0, 1, 2)\n",
        "qc.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70af8d85-84c2-43cf-96fa-37bcf68f89c9",
      "metadata": {},
      "source": [
        "양자 회로의 모든 토폴리 게이트에 대해 하드웨어는 최대 6개의 CNOT 게이트와 소수의 단일 큐비트 게이트를 실행할 수 있습니다.  이 예는 여러 토폴리 게이트를 사용하는 모든 알고리즘이 결국 큰 깊이를 가진 회로가 되어 노이즈의 영향을 크게 받는다는 것을 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8b396526-b14b-48a3-93ed-37e590b06caf",
      "metadata": {},
      "source": [
        "<span id=\"optimization-stage\" />\n",
        "\n",
        "## 최적화 단계\n",
        "\n",
        "이 단계에서는 양자 회로를 대상 디바이스의 기본 게이트 세트로 분해하는 데 중점을 두며, 레이아웃 및 라우팅 단계의 증가된 깊이와 싸워야 합니다.  다행히도 게이트를 결합하거나 제거하여 회로를 최적화하는 많은 루틴이 있습니다.  경우에 따라 이러한 방법은 매우 효과적이어서 하드웨어 토폴로지로 레이아웃 및 라우팅한 후에도 출력 회로가 입력보다 깊이가 낮은 경우도 있습니다.  다른 경우에는 많은 작업을 수행할 수 없으며 소음이 심한 장치에서는 계산을 수행하기 어려울 수 있습니다.  이 단계에서는 다양한 최적화 수준이 달라지기 시작합니다.\n",
        "\n",
        "* `optimization_level=1` 의 경우 이 단계에서는 [`Optimize1qGatesDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition) 와 [`CXCancellation`](/docs/api/qiskit/1.4/qiskit.transpiler.passes.CXCancellation)를 생성하여 단일 큐비트 게이트 체인을 결합하고 연속된 CNOT 게이트를 취소합니다.\n",
        "* `optimization_level=2` 의 경우 이 단계에서는 [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation) 대신 `CXCancellation` 패스를 사용하여 정류 관계를 활용하여 중복 게이트를 제거합니다.\n",
        "* `optimization_level=3` 의 경우 이 단계에서는 다음 패스를 준비합니다:\n",
        "  * [`Collect2qBlocks`](../api/qiskit/qiskit.transpiler.passes.Collect2qBlocks)\n",
        "  * [`ConsolidateBlocks`](../api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks)\n",
        "  * [`UnitarySynthesis`](../api/qiskit/qiskit.transpiler.passes.UnitarySynthesis)\n",
        "  * [`Optimize1qGateDecomposition`](../api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition)\n",
        "  * [`CommutativeCancellation`](../api/qiskit/qiskit.transpiler.passes.CommutativeCancellation)\n",
        "\n",
        "또한 이 단계에서는 회로의 모든 명령이 대상 백엔드에서 사용 가능한 기본 게이트로 구성되었는지 확인하기 위해 몇 가지 최종 검사를 실행합니다.\n",
        "\n",
        "GHZ 상태를 사용한 아래 예는 다양한 최적화 수준 설정이 회로 깊이와 게이트 수에 미치는 영향을 보여줍니다.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  트랜스필레이션 출력은 확률론적 SWAP 매퍼에 따라 달라집니다. 따라서 아래 숫자는 코드를 실행할 때마다 변경될 가능성이 높습니다.\n",
        "</Admonition>\n",
        "\n",
        "![15-쿼비트 GHZ 상태](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-11.avif \"트랜스퓔레이션 전 15-쿼비트 GHZ 상태\")\n",
        "\n",
        "다음 코드는 15-큐비트 GHZ 상태를 구성하고 결과 회로 깊이, 게이트 수 및 멀티-큐비트 게이트 수 측면에서 트랜스퓔레이션의 `optimization_levels` 을 비교합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "2700405a-f559-45d3-99a9-5b4447621743",
      "metadata": {
        "tags": []
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/2700405a-f559-45d3-99a9-5b4447621743-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(15)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 15))\n",
        "\n",
        "depths = []\n",
        "gate_counts = []\n",
        "multiqubit_gate_counts = []\n",
        "levels = [str(x) for x in range(4)]\n",
        "for level in range(4):\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=level,\n",
        "        backend=backend,\n",
        "        seed_transpiler=1234,\n",
        "    )\n",
        "    circ = pass_manager.run(ghz)\n",
        "    depths.append(circ.depth())\n",
        "    gate_counts.append(sum(circ.count_ops().values()))\n",
        "    multiqubit_gate_counts.append(circ.count_ops()[\"cx\"])\n",
        "\n",
        "fig, (ax1, ax2) = plt.subplots(2, 1)\n",
        "ax1.bar(levels, depths, label=\"Depth\")\n",
        "ax1.set_xlabel(\"Optimization Level\")\n",
        "ax1.set_ylabel(\"Depth\")\n",
        "ax1.set_title(\"Output Circuit Depth\")\n",
        "ax2.bar(levels, gate_counts, label=\"Number of Circuit Operations\")\n",
        "ax2.bar(levels, multiqubit_gate_counts, label=\"Number of CX gates\")\n",
        "ax2.set_xlabel(\"Optimization Level\")\n",
        "ax2.set_ylabel(\"Number of gates\")\n",
        "ax2.legend()\n",
        "ax2.set_title(\"Number of output circuit gates\")\n",
        "fig.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c870a48f-2bc4-4150-83ff-857a06e42ffb",
      "metadata": {},
      "source": [
        "<span id=\"scheduling\" />\n",
        "\n",
        "## 스케줄링\n",
        "\n",
        "이 마지막 단계는 명시적으로 호출된 경우에만 실행되며(Init 단계와 유사) 기본적으로 실행되지 않습니다( `generate_preset_pass_manager` 호출 시 `scheduling_method` 인수를 설정하여 메서드를 지정할 수 있음).  스케줄링 단계는 일반적으로 회로를 대상 기준으로 변환하고, 디바이스에 매핑하고, 최적화한 후에 사용됩니다.  이 패스는 서킷의 모든 유휴 시간을 고려하는 데 중점을 둡니다.  높은 수준에서 스케줄링 패스는 게이트 실행 사이의 유휴 시간을 고려하고 백엔드에서 회로가 얼마나 오래 실행될지 검사하기 위해 지연 명령을 명시적으로 삽입하는 것으로 생각할 수 있습니다.\n",
        "\n",
        "예는 다음과 같습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "ae2d9390-5c26-46f3-9418-a684ba8a406a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/transpiler-stages/extracted-outputs/ae2d9390-5c26-46f3-9418-a684ba8a406a-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz = QuantumCircuit(5)\n",
        "ghz.h(0)\n",
        "ghz.cx(0, range(1, 5))\n",
        "\n",
        "\n",
        "# Use fake backend\n",
        "backend = GenericBackendV2(5)\n",
        "\n",
        "# Run with optimization level 3 and 'asap' scheduling pass\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    scheduling_method=\"asap\",\n",
        "    seed_transpiler=1234,\n",
        ")\n",
        "\n",
        "\n",
        "circ = pass_manager.run(ghz)\n",
        "circ.draw(output=\"mpl\", idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "442cb546-3463-4044-8406-1c68d371a2c9",
      "metadata": {},
      "source": [
        "![지연 지침이 있는 회로](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-16.avif)\n",
        "\n",
        "트랜스파일러는 각 큐비트에서 유휴 시간을 고려하기 위해 `Delay` 명령어를 삽입했습니다. 회로의 타이밍을 더 잘 파악하려면 `timeline.draw()` 함수를 사용하여 살펴볼 수도 있습니다:\n",
        "\n",
        "![timeline.draw ()에서 본 동일한 회로의 모습](https://quantum.cloud.ibm.com/docs/images/guides/transpiler-stages/transpiler-17.svg)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b214bba-1f0e-49fc-be7e-29ccb57fff8a",
      "metadata": {},
      "source": [
        "회로 스케줄링은 분석과 제약 조건 매핑, 그리고 패딩 패스의 두 부분으로 구성됩니다.  첫 번째 부분은 스케줄링 분석 패스를 실행해야 합니다(기본값은 [`ALAPSchedulingAnalysis`](../api/qiskit/qiskit.transpiler.passes.ALAPScheduleAnalysis))를 실행하여 회로를 분석하고 회로 내 각 명령어의 시작 시간을 스케줄에 기록합니다.  회로에 초기 일정이 설정되면 대상 백엔드의 타이밍 제약을 고려하여 추가 패스를 실행할 수 있습니다.  마지막으로, 패딩 패스는 [`PadDelay`](../api/qiskit/qiskit.transpiler.passes.PadDelay) 또는 [`PadDynamicalDecoupling`](../api/qiskit/qiskit.transpiler.passes.PadDynamicalDecoupling) 와 같은 패딩 패스를 실행할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "62c19c54-6dcc-4025-b800-7a74be69808d",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * `generate_preset_passmanager` 기능 사용 방법을 알아보려면 [번역 기본 설정 및 구성 옵션](defaults-and-configuration-options) 항목부터 시작하세요.\n",
        "  * [패스 관리자 주제를 사용하여](transpile-with-pass-managers) Transpiler에 대해 계속해서 학습하세요.\n",
        "  * [Compare 트랜스파일러 설정](/docs/guides/circuit-transpilation-settings) 가이드를 시도해 보세요.\n",
        "  * [Transpile API](https://docs.quantum-computing.ibm.com/api/qiskit/transpiler) 문서를 참조하십시오.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}