{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "58b1f0a7-d62e-4f71-ba01-b8f0beaeeb83",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"트랜스파일러 플러그인 생성\"\n",
        "description: \"Qiskit 트랜스파일러 플러그인을 생성하여 트랜스파일링 코드를 Qiskit 커뮤니티와 공유하는 방법.\"\n",
        "---\n",
        "\n",
        "<span id=\"create-a-transpiler-plugin\" />\n",
        "\n",
        "# 트랜스파일러 플러그인 생성\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ec7b7a4-5318-4422-ab3d-c88cee551eaa",
      "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": "a7f87a76-b7a1-4dbb-ad45-55ff63c4665b",
      "metadata": {},
      "source": [
        "[트랜스파일러 플러그인을](transpiler-plugins) 만들면 더 넓은 키스킷 커뮤니티와 트랜스파일 코드를 공유하여 다른 사용자가 여러분이 개발한 기능의 혜택을 누릴 수 있습니다. 키스킷 커뮤니티에 관심을 가져주셔서 감사합니다!\n",
        "\n",
        "트랜스파일러 플러그인을 만들기 전에 어떤 종류의 플러그인이 상황에 적합한지 결정해야 합니다. 트랜스파일러 플러그인에는 세 가지 종류가 있습니다:\n",
        "\n",
        "* [**트랜스파일러 스테이지 플러그인**](/docs/api/qiskit/transpiler_plugins). 사전 설정된 스테이지 패스 매니저의 [6단계](transpiler-stages) 중 하나를 대체할 수 있는 패스 매니저를 정의하는 경우 이 옵션을 선택합니다.\n",
        "* [**유니티 합성 플러그인**](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin). 변환 코드가 단일 행렬(Numpy 배열로 표현됨)을 입력으로 받아 해당 단일 행렬을 구현하는 양자 회로에 대한 설명을 출력하는 경우 이 옵션을 선택합니다.\n",
        "* [**고급 합성 플러그인입니다**](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin). 번역 코드가 클리포드 연산자나 선형 함수와 같은 \"상위 수준 객체\"를 입력으로 받아 해당 상위 수준 객체를 구현하는 양자 회로에 대한 설명을 출력하는 경우 이 옵션을 선택합니다. 상위 레벨 객체는 [Operation](/docs/api/qiskit/qiskit.circuit.Operation) 클래스의 서브클래스로 표현됩니다.\n",
        "\n",
        "어떤 종류의 플러그인을 만들지 결정했으면 다음 단계에 따라 플러그인을 만듭니다:\n",
        "\n",
        "1. 적절한 추상 플러그인 클래스의 서브클래스를 만듭니다:\n",
        "   * [PassManagerStagePlugin](/docs/api/qiskit/qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePlugin) 트랜스파일러 스테이지 플러그인입니다,\n",
        "   * [UnitarySynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin) 단일 합성 플러그인의 경우\n",
        "   * [HighLevelSynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin) 를 사용하면 높은 수준의 합성 플러그인을 사용할 수 있습니다.\n",
        "2. 일반적으로 Python 패키지의 `pyproject.toml`, `setup.cfg`, 또는 `setup.py` 파일을 편집하여 패키지 메타데이터에 [setuptools 진입점으로](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) 클래스를 노출합니다.\n",
        "\n",
        "하나의 패키지에 정의할 수 있는 플러그인 수에는 제한이 없지만 각 플러그인에는 고유한 이름이 있어야 합니다. 키스킷 SDK 자체에는 여러 플러그인이 포함되어 있으며 이름도 예약되어 있습니다. 예약된 이름은 다음과 같습니다:\n",
        "\n",
        "* 트랜스파일러 스테이지 플러그인: [이 표를](/docs/api/qiskit/transpiler_plugins#plugin-stages) 참조하세요.\n",
        "* 유니티 합성 플러그인: `default`, `aqc`, `sk`\n",
        "* 고급 합성 플러그인:\n",
        "\n",
        "| 작업 클래스                                                                                     | 오퍼레이션 이름          | 예약된 이름                                            |\n",
        "| ------------------------------------------------------------------------------------------ | ----------------- | ------------------------------------------------- |\n",
        "| [클리퍼드](/docs/api/qiskit/qiskit.quantum_info.Clifford#clifford)                             | `clifford`        | `default`, `ag`, `bm`, `greedy`, `layers`, `lnn`  |\n",
        "| [LinearFunction](/docs/api/qiskit/qiskit.circuit.library.LinearFunction#linearfunction)    | `linear_function` | `default`, `kms`, `pmh`                           |\n",
        "| [PermutationGate](/docs/api/qiskit/qiskit.circuit.library.PermutationGate#permutationgate) | `permutation`     | `default`, `kms`, `basic`, `acg`, `token_swapper` |\n",
        "\n",
        "다음 섹션에서는 다양한 유형의 플러그인에 대한 이러한 단계의 예를 보여 드리겠습니다. 이 예제에서는 `my_qiskit_plugin` 이라는 Python 패키지를 만든다고 가정합니다. Python 패키지 생성에 대한 자세한 내용은 Python 웹사이트에서 [이 튜토리얼을](https://packaging.python.org/en/latest/tutorials/packaging-projects/) 확인할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4519c0dc-2bcd-48f4-8522-435b72efdb40",
      "metadata": {},
      "source": [
        "<span id=\"example-create-a-transpiler-stage-plugin\" />\n",
        "\n",
        "## 예시: 트랜스파일러 스테이지 플러그인 생성\n",
        "\n",
        "이 예제에서는 `layout` 단계에 대한 트랜스파일러 단계 플러그인을 생성한다(키스킷에 내장된 트랜스파일 파이프라인의 6단계에 대한 설명은 [트랜스파일러 단계를](transpiler-stages) 참조한다).\n",
        "플러그인은 요청된 최적화 수준에 따라 [VF2Layout](/docs/api/qiskit/qiskit.transpiler.passes.VF2Layout) 를 실행하여 요청된 최적화 수준에 따라 여러 번의 테스트를 수행합니다.\n",
        "\n",
        "먼저, 하위 클래스인 [PassManagerStagePlugin](/docs/api/qiskit/qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePlugin). 구현해야 하는 메서드가 하나 있는데, 바로 [`pass_manager`](/docs/api/qiskit/qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePlugin#pass_manager). 이 메서드는 입력으로 [PassManagerConfig](/docs/api/qiskit/qiskit.transpiler.PassManagerConfig) 를 입력으로 받고 정의 중인 패스 관리자를 반환합니다. PassManagerConfig 객체는 커플링 맵 및 베이시스 게이트와 같은 대상 백엔드에 대한 정보를 저장합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "f90299d9-5026-424c-b528-6d0defdddb54",
      "metadata": {},
      "outputs": [],
      "source": [
        "# This import is needed for python versions prior to 3.10\n",
        "from __future__ import annotations\n",
        "\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.passes import VF2Layout\n",
        "from qiskit.transpiler.passmanager_config import PassManagerConfig\n",
        "from qiskit.transpiler.preset_passmanagers import common\n",
        "from qiskit.transpiler.preset_passmanagers.plugin import (\n",
        "    PassManagerStagePlugin,\n",
        ")\n",
        "\n",
        "\n",
        "class MyLayoutPlugin(PassManagerStagePlugin):\n",
        "    def pass_manager(\n",
        "        self,\n",
        "        pass_manager_config: PassManagerConfig,\n",
        "        optimization_level: int | None = None,\n",
        "    ) -> PassManager:\n",
        "        layout_pm = PassManager(\n",
        "            [\n",
        "                VF2Layout(\n",
        "                    coupling_map=pass_manager_config.coupling_map,\n",
        "                    properties=pass_manager_config.backend_properties,\n",
        "                    max_trials=optimization_level * 10 + 1,\n",
        "                    target=pass_manager_config.target,\n",
        "                )\n",
        "            ]\n",
        "        )\n",
        "        layout_pm += common.generate_embed_passmanager(\n",
        "            pass_manager_config.coupling_map\n",
        "        )\n",
        "        return layout_pm"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d7666879-14bc-479c-a91b-56a800897073",
      "metadata": {},
      "source": [
        "이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다.\n",
        "여기서는 정의한 클래스가 `my_qiskit_plugin` 라는 모듈에 노출되어 있다고 가정합니다(예: `my_qiskit_plugin` 모듈의 `__init__.py` 파일에서 임포트됨).\n",
        "패키지의 `pyproject.toml`, `setup.cfg` 또는 `setup.py` 파일을 편집합니다( Python 프로젝트 메타데이터를 저장하기로 선택한 파일 종류에 따라 다름):\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"package-table-toml\" label=\"pyproject.toml\" default>\n",
        "    ```toml\n",
        "    [project.entry-points.\"qiskit.transpiler.layout\"]\n",
        "    \"my_layout\" = \"my_qiskit_plugin:MyLayoutPlugin\"\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-cfg\" label=\"setup.cfg\">\n",
        "    ```ini\n",
        "    [options.entry_points]\n",
        "    qiskit.transpiler.layout =\n",
        "        my_layout = my_qiskit_plugin:MyLayoutPlugin\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-py\" label=\"setup.py\">\n",
        "    ```python\n",
        "    from setuptools import setup\n",
        "\n",
        "    setup(\n",
        "        # ...,\n",
        "        entry_points={\n",
        "            'qiskit.transpiler.layout': [\n",
        "                'my_layout = my_qiskit_plugin:MyLayoutPlugin',\n",
        "            ]\n",
        "        }\n",
        "    )\n",
        "    ```\n",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5c5edd30",
      "metadata": {},
      "source": [
        "각 트랜스파일러 단계의 진입 점과 기대치는 트랜스파일러 [플러그인 단계 표를](/docs/api/qiskit/transpiler_plugins#stage-table) 참조하세요.\n",
        "\n",
        "플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 [트랜스파일러 플러그인의](transpiler-plugins#list-available-transpiler-stage-plugins) 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "04b07ec3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "['default', 'dense', 'sabre', 'trivial']"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins\n",
        "\n",
        "list_stage_plugins(\"layout\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d62c4edb",
      "metadata": {},
      "source": [
        "예제 플러그인이 설치되어 있다면 `my_layout` 이라는 이름이 이 목록에 표시됩니다.\n",
        "\n",
        "내장 트랜스파일러 스테이지를 트랜스파일러 스테이지 플러그인의 시작점으로 사용하려는 경우, 내장 트랜스파일러 스테이지의 패스 매니저를 얻으려면 [PassManagerStagePluginManager](/docs/api/qiskit/qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePluginManager#passmanagerstagepluginmanager). 다음 코드 셀은 최적화 레벨 3을 위한 기본 제공 최적화 단계를 얻는 방법을 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f4d578d6",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler.preset_passmanagers.plugin import (\n",
        "    PassManagerStagePluginManager,\n",
        ")\n",
        "\n",
        "# Initialize the plugin manager\n",
        "plugin_manager = PassManagerStagePluginManager()\n",
        "\n",
        "# Here we create a pass manager config to use as an example.\n",
        "# Instead, you should use the pass manager config that you already received as input\n",
        "# to the pass_manager method of your PassManagerStagePlugin.\n",
        "pass_manager_config = PassManagerConfig()\n",
        "\n",
        "# Obtain the desired built-in transpiler stage\n",
        "optimization = plugin_manager.get_passmanager_stage(\n",
        "    \"optimization\", \"default\", pass_manager_config, optimization_level=3\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe3a1a6c-5aa2-4f00-9bdd-45598717be1d",
      "metadata": {},
      "source": [
        "<span id=\"example-create-a-unitary-synthesis-plugin\" />\n",
        "\n",
        "## 예시: 단일 합성 플러그인 생성\n",
        "\n",
        "이 예제에서는 기본 제공 트랜스필레이션 패스를 사용하여 게이트를 합성하는 [UnitarySynthesis](/docs/api/qiskit/qiskit.transpiler.passes.UnitarySynthesis#unitarysynthesis) 트랜스필레이션 패스를 사용하여 게이트를 합성하는 단일 합성 플러그인을 만들겠습니다. 물론 자체 플러그인은 그보다 더 흥미로운 작업을 수행할 수 있습니다.\n",
        "\n",
        "클래스는 [UnitarySynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin) 클래스는 단일 합성을 위한 인터페이스와 컨트랙트를 정의합니다 플러그인의 인터페이스와 컨트랙트를 정의합니다. 기본 방법은 다음과 같습니다 [`run`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin#run), 는 단일 행렬을 저장하는 Numpy 배열을 입력으로 받아 를 입력으로 받고 그 단일 행렬에서 합성된 회로를 나타내는 [DAGCircuit을](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit) 반환합니다.\n",
        "`run` 메서드 외에도 정의해야 하는 여러 속성 메서드가 있습니다.\n",
        "참조 [UnitarySynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin) 에서 모든 필수 속성에 대한 설명서를 확인하세요.\n",
        "\n",
        "UnitarySynthesisPlugin 서브클래스를 만들어 보겠습니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "6bc1011c-b15d-4210-973b-d9d530ece880",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister\n",
        "from qiskit.converters import circuit_to_dag\n",
        "from qiskit.dagcircuit.dagcircuit import DAGCircuit\n",
        "from qiskit.quantum_info import Operator\n",
        "from qiskit.transpiler.passes import UnitarySynthesis\n",
        "from qiskit.transpiler.passes.synthesis.plugin import UnitarySynthesisPlugin\n",
        "\n",
        "\n",
        "class MyUnitarySynthesisPlugin(UnitarySynthesisPlugin):\n",
        "    @property\n",
        "    def supports_basis_gates(self):\n",
        "        # Returns True if the plugin can target a list of basis gates\n",
        "        return True\n",
        "\n",
        "    @property\n",
        "    def supports_coupling_map(self):\n",
        "        # Returns True if the plugin can synthesize for a given coupling map\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_natural_direction(self):\n",
        "        # Returns True if the plugin supports a toggle for considering\n",
        "        # directionality of 2-qubit gates\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_pulse_optimize(self):\n",
        "        # Returns True if the plugin can optimize pulses during synthesis\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_gate_lengths(self):\n",
        "        # Returns True if the plugin can accept information about gate lengths\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_gate_errors(self):\n",
        "        # Returns True if the plugin can accept information about gate errors\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_gate_lengths_by_qubit(self):\n",
        "        # Returns True if the plugin can accept information about gate lengths\n",
        "        # (The format of the input differs from supports_gate_lengths)\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def supports_gate_errors_by_qubit(self):\n",
        "        # Returns True if the plugin can accept information about gate errors\n",
        "        # (The format of the input differs from supports_gate_errors)\n",
        "        return False\n",
        "\n",
        "    @property\n",
        "    def min_qubits(self):\n",
        "        # Returns the minimum number of qubits the plugin supports\n",
        "        return None\n",
        "\n",
        "    @property\n",
        "    def max_qubits(self):\n",
        "        # Returns the maximum number of qubits the plugin supports\n",
        "        return None\n",
        "\n",
        "    @property\n",
        "    def supported_bases(self):\n",
        "        # Returns a dictionary of supported bases for synthesis\n",
        "        return None\n",
        "\n",
        "    def run(self, unitary: np.ndarray, **options) -> DAGCircuit:\n",
        "        basis_gates = options[\"basis_gates\"]\n",
        "        synth_pass = UnitarySynthesis(basis_gates, min_qubits=3)\n",
        "        qubits = QuantumRegister(3)\n",
        "        circuit = QuantumCircuit(qubits)\n",
        "        circuit.append(Operator(unitary).to_instruction(), qubits)\n",
        "        dag_circuit = synth_pass.run(circuit_to_dag(circuit))\n",
        "        return dag_circuit"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6daebf1b-aa38-44a8-bf62-eea96838e95f",
      "metadata": {},
      "source": [
        "입력값을 사용할 수 없는 경우 [`run`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin#run) 메서드에 사용할 수 있는 입력이 목적에 맞지 않는 경우 요구 사항을 설명하는 [이슈를 개설하세요](https://github.com/Qiskit/qiskit/issues/new/choose). 추가 옵션 입력 추가와 같은 플러그인 인터페이스 변경은 기존 플러그인에서 변경할 필요가 없도록 이전 버전과 호환되는 방식으로 이루어집니다.\n",
        "\n",
        "<Admonition type=\"note\" title=\"참고\">\n",
        "  `supports_` 접두사가 붙은 모든 메서드는 인터페이스의 일부로 `UnitarySynthesisPlugin` 파생 클래스에 예약되어 있습니다. 추상 클래스에 정의되지 않은 사용자 정의 `supports_*` 메서드를 하위 클래스에 정의해서는 안 됩니다.\n",
        "</Admonition>\n",
        "\n",
        "이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다.\n",
        "여기서는 정의한 클래스가 `my_qiskit_plugin` 라는 모듈에 노출되어 있다고 가정합니다(예: `my_qiskit_plugin` 모듈의 `__init__.py` 파일에서 임포트됨).\n",
        "패키지의 `pyproject.toml`, `setup.cfg`, 또는 `setup.py` 파일을 편집합니다:\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"package-table-toml\" label=\"pyproject.toml\" default>\n",
        "    ```toml\n",
        "    [project.entry-points.\"qiskit.unitary_synthesis\"]\n",
        "    \"my_unitary_synthesis\" = \"my_qiskit_plugin:MyUnitarySynthesisPlugin\"\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-cfg\" label=\"setup.cfg\">\n",
        "    ```ini\n",
        "    [options.entry_points]\n",
        "    qiskit.unitary_synthesis =\n",
        "        my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPlugin\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-py\" label=\"setup.py\">\n",
        "    ```python\n",
        "    from setuptools import setup\n",
        "\n",
        "    setup(\n",
        "        # ...,\n",
        "        entry_points={\n",
        "            'qiskit.unitary_synthesis': [\n",
        "                'my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPlugin',\n",
        "            ]\n",
        "        }\n",
        "    )\n",
        "    ```\n",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n",
        "이전과 마찬가지로 프로젝트에서 `pyproject.toml` 대신 `setup.cfg` 또는 `setup.py` 을 사용하는 경우 [설정 도구 문서를](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) 참조하여 상황에 맞게 이 줄을 조정하는 방법을 확인하세요.\n",
        "\n",
        "플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 [트랜스파일러 플러그인의](transpiler-plugins#list-available-unitary-synthesis-plugins) 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "31bfaf30",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "['aqc', 'clifford', 'default', 'gridsynth', 'sk']"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names\n",
        "\n",
        "unitary_synthesis_plugin_names()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4faf2d51",
      "metadata": {},
      "source": [
        "예제 플러그인이 설치되어 있다면 `my_unitary_synthesis` 이라는 이름이 이 목록에 표시됩니다.\n",
        "\n",
        "여러 옵션을 노출하는 단일 합성 플러그인을 수용하기 위해, 플러그인 인터페이스에는 사용자가 자유 형식의 구성 사전을 제공하는 옵션이 있습니다. 이는 `run` 메소드에 전달됩니다 `options` 키워드 인수를 통해 전달됩니다. 플러그인에 이러한 구성 옵션이 있는 경우 이를 명확하게 문서화해야 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "651c863d-41d9-41f4-a133-b392dae2f363",
      "metadata": {},
      "source": [
        "<span id=\"example-create-a-high-level-synthesis-plugin\" />\n",
        "\n",
        "## 예시: 하이레벨 합성 플러그인 생성\n",
        "\n",
        "이 예제에서는 내장된 [synth\\_clifford\\_bm](/docs/api/qiskit/synthesis#synth_clifford_bm) 함수를 사용하여 클리포드 연산자를 합성하는 높은 수준의 합성 플러그인을 만들어 보겠습니다.\n",
        "\n",
        "클래스는 [HighLevelSynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin) 클래스는 하이레벨 합성 플러그인을 위한 인터페이스와 컨트랙트를 정의합니다. 기본 방법은 [`run`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin#run).\n",
        "위치 인수 `high_level_object` 는 합성할 \"상위 수준\" 객체를 나타내는 [연산입니다](/docs/api/qiskit/qiskit.circuit.Operation). 예를 들어 [LinearFunction](/docs/api/qiskit/qiskit.circuit.library.LinearFunction) 또는 [클리포드](/docs/api/qiskit/qiskit.quantum_info.Clifford).\n",
        "다음과 같은 키워드 인수가 있습니다:\n",
        "\n",
        "* `target` 는 대상 백엔드를 지정하여 플러그인 이 모든 대상별 정보에 액세스할 수 있도록 합니다, 커플링 맵, 지원되는 게이트 세트 등과 같은 모든 대상별 정보에 액세스할 수 있습니다\n",
        "* `coupling_map` 는 커플링 맵만 지정하며 `target` 가 지정되지 않은 경우에만 사용됩니다.\n",
        "* `qubits` 는 물리적 회로에서 합성이 이루어지는 경우 상위 레벨 객체가 정의되는 상위 레벨 객체가 정의되는 큐비트 목록을 지정합니다(물리적 회로에서 합성이 수행되는 경우).\n",
        "  `None` 값은 레이아웃이 아직 선택되지 않았으며 이 작업이 작동 중인 대상 또는 커플링 맵의 물리적 큐비트가 아직 결정되지 않았음을 나타냅니다.\n",
        "* `options`플러그인별 옵션을 위한 자유 형식 구성 사전입니다. 플러그인에 이러한 구성 옵션이 있는 경우 를 명확하게 문서화해야 합니다.\n",
        "\n",
        "`run` 메서드는 [QuantumCircuit](/docs/api/qiskit/qiskit.circuit.QuantumCircuit) 를 반환하며, 이는 해당 상위 객체에서 합성된 회로를 나타냅니다.\n",
        "또한 플러그인이 주어진 상위 수준 객체를 합성할 수 없음을 나타내는 `None` 을 반환할 수도 있습니다.\n",
        "하이 레벨 오브젝트의 실제 합성은 [HighLevelSynthesis](/docs/api/qiskit/qiskit.transpiler.passes.HighLevelSynthesis) 트랜스파일러 패스에 의해 수행됩니다.\n",
        "\n",
        "`run` 메서드 외에도 정의해야 하는 여러 속성 메서드가 있습니다.\n",
        "참조 [HighLevelSynthesisPlugin](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin) 에서 모든 필수 속성에 대한 설명서를 확인하세요.\n",
        "\n",
        "HighLevelSynthesisPlugin 서브클래스를 정의해 보겠습니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "3c0e59d4-85b0-4157-824b-b1f6220e83ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.synthesis import synth_clifford_bm\n",
        "from qiskit.transpiler.passes.synthesis.plugin import HighLevelSynthesisPlugin\n",
        "\n",
        "\n",
        "class MyCliffordSynthesisPlugin(HighLevelSynthesisPlugin):\n",
        "    def run(\n",
        "        self,\n",
        "        high_level_object,\n",
        "        coupling_map=None,\n",
        "        target=None,\n",
        "        qubits=None,\n",
        "        **options,\n",
        "    ) -> QuantumCircuit:\n",
        "        if high_level_object.num_qubits <= 3:\n",
        "            return synth_clifford_bm(high_level_object)\n",
        "        else:\n",
        "            return None"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1285dbfd-04ce-494b-8a01-a58040035dbd",
      "metadata": {},
      "source": [
        "이 플러그인은 [클리포드](/docs/api/qiskit/qiskit.quantum_info.Clifford) 타입의 객체를 합성합니다 최대 3 큐비트를 가진 클리포드 타입의 객체를 `synth_clifford_bm` 메서드를 사용하여 합성합니다.\n",
        "\n",
        "이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다.\n",
        "여기서는 정의한 클래스가 `my_qiskit_plugin` 라는 모듈에 노출되어 있다고 가정합니다(예: `my_qiskit_plugin` 모듈의 `__init__.py` 파일에서 임포트됨).\n",
        "패키지의 `pyproject.toml`, `setup.cfg`, 또는 `setup.py` 파일을 편집합니다:\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"package-table-toml\" label=\"pyproject.toml\" default>\n",
        "    ```toml\n",
        "    [project.entry-points.\"qiskit.synthesis\"]\n",
        "    \"clifford.my_clifford_synthesis\" = \"my_qiskit_plugin:MyCliffordSynthesisPlugin\"\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-cfg\" label=\"setup.cfg\">\n",
        "    ```ini\n",
        "    [options.entry_points]\n",
        "    qiskit.synthesis =\n",
        "        clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPlugin\n",
        "    ```\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"package-table-py\" label=\"setup.py\">\n",
        "    ```python\n",
        "    from setuptools import setup\n",
        "\n",
        "    setup(\n",
        "        # ...,\n",
        "        entry_points={\n",
        "            'qiskit.synthesis': [\n",
        "                'clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPlugin',\n",
        "            ]\n",
        "        }\n",
        "    )\n",
        "    ```\n",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n",
        "`name` 은 점으로 구분된 두 부분으로 구성됩니다(`.`):\n",
        "\n",
        "* 플러그인이 합성하는 [작업](/docs/api/qiskit/qiskit.circuit.Operation) 유형의 이름(이 경우 `clifford`)입니다. 이 문자열은 클래스 자체의 이름이 아니라 오퍼레이션 클래스의 [`name`](/docs/api/qiskit/qiskit.circuit.Operation#name) 속성에 해당하며 클래스 자체의 이름이 아닙니다.\n",
        "* 플러그인 이름(이 경우 `special`)입니다.\n",
        "\n",
        "이전과 마찬가지로 프로젝트에서 `pyproject.toml` 대신 `setup.cfg` 또는 `setup.py` 을 사용하는 경우 [설정 도구 문서를](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) 참조하여 상황에 맞게 이 줄을 조정하는 방법을 확인하세요.\n",
        "\n",
        "플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 [트랜스파일러 플러그인의](transpiler-plugins#list-available-high-level-synthesis-plugins) 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "fbe1f265",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "['rb_default', 'ag', 'bm', 'default', 'greedy', 'layers', 'lnn']"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.passes.synthesis import (\n",
        "    high_level_synthesis_plugin_names,\n",
        ")\n",
        "\n",
        "high_level_synthesis_plugin_names(\"clifford\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f1e86f49",
      "metadata": {},
      "source": [
        "예제 플러그인이 설치되어 있다면 `my_clifford_synthesis` 이라는 이름이 이 목록에 표시됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a48c2d0b-c402-4b83-ae2e-42c33fe1720e",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * [여러분의 플러그인을 키스킷 생태계에 제출하세요!](https://github.com/Qiskit/ecosystem?tab=readme-ov-file#how-to-join)\n",
        "  * [튜토리얼에서](/docs/tutorials) 양자 회로 트랜스파일링 및 실행의 예시를 확인하세요.\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
}