Skip to main content
IBM Quantum Platform

트랜스파일러 플러그인 생성

  • 이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 다음 버전 이상을 사용하는 것이 좋습니다.

    qiskit[all]~=2.5.2
    

트랜스파일러 플러그인을 만들면 더 넓은 키스킷 커뮤니티와 트랜스파일 코드를 공유하여 다른 사용자가 여러분이 개발한 기능의 혜택을 누릴 수 있습니다. 키스킷 커뮤니티에 관심을 가져주셔서 감사합니다!

트랜스파일러 플러그인을 만들기 전에 어떤 종류의 플러그인이 상황에 적합한지 결정해야 합니다. 트랜스파일러 플러그인에는 세 가지 종류가 있습니다:

  • 트랜스파일러 스테이지 플러그인. 사전 설정된 스테이지 패스 매니저의 6단계 중 하나를 대체할 수 있는 패스 매니저를 정의하는 경우 이 옵션을 선택합니다.
  • 유니티 합성 플러그인. 변환 코드가 단일 행렬(Numpy 배열로 표현됨)을 입력으로 받아 해당 단일 행렬을 구현하는 양자 회로에 대한 설명을 출력하는 경우 이 옵션을 선택합니다.
  • 고급 합성 플러그인입니다. 번역 코드가 클리포드 연산자나 선형 함수와 같은 "상위 수준 객체"를 입력으로 받아 해당 상위 수준 객체를 구현하는 양자 회로에 대한 설명을 출력하는 경우 이 옵션을 선택합니다. 상위 레벨 객체는 Operation 클래스의 서브클래스로 표현됩니다.

어떤 종류의 플러그인을 만들지 결정했으면 다음 단계에 따라 플러그인을 만듭니다:

  1. 적절한 추상 플러그인 클래스의 서브클래스를 만듭니다:
  2. 일반적으로 Python 패키지의 pyproject.toml, setup.cfg, 또는 setup.py 파일을 편집하여 패키지 메타데이터에 setuptools 진입점으로 클래스를 노출합니다.

하나의 패키지에 정의할 수 있는 플러그인 수에는 제한이 없지만 각 플러그인에는 고유한 이름이 있어야 합니다. 키스킷 SDK 자체에는 여러 플러그인이 포함되어 있으며 이름도 예약되어 있습니다. 예약된 이름은 다음과 같습니다:

  • 트랜스파일러 스테이지 플러그인: 이 표를 참조하세요.
  • 유니티 합성 플러그인: default, aqc, sk
  • 고급 합성 플러그인:
작업 클래스
오퍼레이션 이름
예약된 이름
클리퍼드clifforddefault, ag, bm, greedy, layers, lnn
LinearFunctionlinear_functiondefault, kms, pmh
PermutationGatepermutationdefault, kms, basic, acg, token_swapper

다음 섹션에서는 다양한 유형의 플러그인에 대한 이러한 단계의 예를 보여 드리겠습니다. 이 예제에서는 my_qiskit_plugin 이라는 Python 패키지를 만든다고 가정합니다. Python 패키지 생성에 대한 자세한 내용은 Python 웹사이트에서 이 튜토리얼을 확인할 수 있습니다.


예시: 트랜스파일러 스테이지 플러그인 생성

이 예제에서는 layout 단계에 대한 트랜스파일러 단계 플러그인을 생성한다(키스킷에 내장된 트랜스파일 파이프라인의 6단계에 대한 설명은 트랜스파일러 단계를 참조한다). 플러그인은 요청된 최적화 수준에 따라 VF2Layout 를 실행하여 요청된 최적화 수준에 따라 여러 번의 테스트를 수행합니다.

먼저, 하위 클래스인 PassManagerStagePlugin. 구현해야 하는 메서드가 하나 있는데, 바로 pass_manager. 이 메서드는 입력으로 PassManagerConfig 를 입력으로 받고 정의 중인 패스 관리자를 반환합니다. PassManagerConfig 객체는 커플링 맵 및 베이시스 게이트와 같은 대상 백엔드에 대한 정보를 저장합니다.

# This import is needed for python versions prior to 3.10
from __future__ import annotations

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import VF2Layout
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
    PassManagerStagePlugin,
)


class MyLayoutPlugin(PassManagerStagePlugin):
    def pass_manager(
        self,
        pass_manager_config: PassManagerConfig,
        optimization_level: int | None = None,
    ) -> PassManager:
        layout_pm = PassManager(
            [
                VF2Layout(
                    coupling_map=pass_manager_config.coupling_map,
                    properties=pass_manager_config.backend_properties,
                    max_trials=optimization_level * 10 + 1,
                    target=pass_manager_config.target,
                )
            ]
        )
        layout_pm += common.generate_embed_passmanager(
            pass_manager_config.coupling_map
        )
        return layout_pm

이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다. 여기서는 정의한 클래스가 my_qiskit_plugin 라는 모듈에 노출되어 있다고 가정합니다(예: my_qiskit_plugin 모듈의 __init__.py 파일에서 임포트됨). 패키지의 pyproject.toml, setup.cfg 또는 setup.py 파일을 편집합니다( Python 프로젝트 메타데이터를 저장하기로 선택한 파일 종류에 따라 다름):

[project.entry-points."qiskit.transpiler.layout"]
"my_layout" = "my_qiskit_plugin:MyLayoutPlugin"

각 트랜스파일러 단계의 진입 점과 기대치는 트랜스파일러 플러그인 단계 표를 참조하세요.

플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 트랜스파일러 플러그인의 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:

from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins

list_stage_plugins("layout")

Output:

['default', 'dense', 'sabre', 'trivial']

예제 플러그인이 설치되어 있다면 my_layout 이라는 이름이 이 목록에 표시됩니다.

내장 트랜스파일러 스테이지를 트랜스파일러 스테이지 플러그인의 시작점으로 사용하려는 경우, 내장 트랜스파일러 스테이지의 패스 매니저를 얻으려면 PassManagerStagePluginManager. 다음 코드 셀은 최적화 레벨 3을 위한 기본 제공 최적화 단계를 얻는 방법을 보여줍니다.

from qiskit.transpiler.preset_passmanagers.plugin import (
    PassManagerStagePluginManager,
)

# Initialize the plugin manager
plugin_manager = PassManagerStagePluginManager()

# Here we create a pass manager config to use as an example.
# Instead, you should use the pass manager config that you already received as input
# to the pass_manager method of your PassManagerStagePlugin.
pass_manager_config = PassManagerConfig()

# Obtain the desired built-in transpiler stage
optimization = plugin_manager.get_passmanager_stage(
    "optimization", "default", pass_manager_config, optimization_level=3
)

예시: 단일 합성 플러그인 생성

이 예제에서는 기본 제공 트랜스필레이션 패스를 사용하여 게이트를 합성하는 UnitarySynthesis 트랜스필레이션 패스를 사용하여 게이트를 합성하는 단일 합성 플러그인을 만들겠습니다. 물론 자체 플러그인은 그보다 더 흥미로운 작업을 수행할 수 있습니다.

클래스는 UnitarySynthesisPlugin 클래스는 단일 합성을 위한 인터페이스와 컨트랙트를 정의합니다 플러그인의 인터페이스와 컨트랙트를 정의합니다. 기본 방법은 다음과 같습니다 run, 는 단일 행렬을 저장하는 Numpy 배열을 입력으로 받아 를 입력으로 받고 그 단일 행렬에서 합성된 회로를 나타내는 DAGCircuit을 반환합니다. run 메서드 외에도 정의해야 하는 여러 속성 메서드가 있습니다. 참조 UnitarySynthesisPlugin 에서 모든 필수 속성에 대한 설명서를 확인하세요.

UnitarySynthesisPlugin 서브클래스를 만들어 보겠습니다:

import numpy as np
from qiskit.circuit import QuantumCircuit, QuantumRegister
from qiskit.converters import circuit_to_dag
from qiskit.dagcircuit.dagcircuit import DAGCircuit
from qiskit.quantum_info import Operator
from qiskit.transpiler.passes import UnitarySynthesis
from qiskit.transpiler.passes.synthesis.plugin import UnitarySynthesisPlugin


class MyUnitarySynthesisPlugin(UnitarySynthesisPlugin):
    @property
    def supports_basis_gates(self):
        # Returns True if the plugin can target a list of basis gates
        return True

    @property
    def supports_coupling_map(self):
        # Returns True if the plugin can synthesize for a given coupling map
        return False

    @property
    def supports_natural_direction(self):
        # Returns True if the plugin supports a toggle for considering
        # directionality of 2-qubit gates
        return False

    @property
    def supports_pulse_optimize(self):
        # Returns True if the plugin can optimize pulses during synthesis
        return False

    @property
    def supports_gate_lengths(self):
        # Returns True if the plugin can accept information about gate lengths
        return False

    @property
    def supports_gate_errors(self):
        # Returns True if the plugin can accept information about gate errors
        return False

    @property
    def supports_gate_lengths_by_qubit(self):
        # Returns True if the plugin can accept information about gate lengths
        # (The format of the input differs from supports_gate_lengths)
        return False

    @property
    def supports_gate_errors_by_qubit(self):
        # Returns True if the plugin can accept information about gate errors
        # (The format of the input differs from supports_gate_errors)
        return False

    @property
    def min_qubits(self):
        # Returns the minimum number of qubits the plugin supports
        return None

    @property
    def max_qubits(self):
        # Returns the maximum number of qubits the plugin supports
        return None

    @property
    def supported_bases(self):
        # Returns a dictionary of supported bases for synthesis
        return None

    def run(self, unitary: np.ndarray, **options) -> DAGCircuit:
        basis_gates = options["basis_gates"]
        synth_pass = UnitarySynthesis(basis_gates, min_qubits=3)
        qubits = QuantumRegister(3)
        circuit = QuantumCircuit(qubits)
        circuit.append(Operator(unitary).to_instruction(), qubits)
        dag_circuit = synth_pass.run(circuit_to_dag(circuit))
        return dag_circuit

입력값을 사용할 수 없는 경우 run 메서드에 사용할 수 있는 입력이 목적에 맞지 않는 경우 요구 사항을 설명하는 이슈를 개설하세요. 추가 옵션 입력 추가와 같은 플러그인 인터페이스 변경은 기존 플러그인에서 변경할 필요가 없도록 이전 버전과 호환되는 방식으로 이루어집니다.

참고

supports_ 접두사가 붙은 모든 메서드는 인터페이스의 일부로 UnitarySynthesisPlugin 파생 클래스에 예약되어 있습니다. 추상 클래스에 정의되지 않은 사용자 정의 supports_* 메서드를 하위 클래스에 정의해서는 안 됩니다.

이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다. 여기서는 정의한 클래스가 my_qiskit_plugin 라는 모듈에 노출되어 있다고 가정합니다(예: my_qiskit_plugin 모듈의 __init__.py 파일에서 임포트됨). 패키지의 pyproject.toml, setup.cfg, 또는 setup.py 파일을 편집합니다:

[project.entry-points."qiskit.unitary_synthesis"]
"my_unitary_synthesis" = "my_qiskit_plugin:MyUnitarySynthesisPlugin"

이전과 마찬가지로 프로젝트에서 pyproject.toml 대신 setup.cfg 또는 setup.py 을 사용하는 경우 설정 도구 문서를 참조하여 상황에 맞게 이 줄을 조정하는 방법을 확인하세요.

플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 트랜스파일러 플러그인의 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:

from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names

unitary_synthesis_plugin_names()

Output:

['aqc', 'clifford', 'default', 'gridsynth', 'sk']

예제 플러그인이 설치되어 있다면 my_unitary_synthesis 이라는 이름이 이 목록에 표시됩니다.

여러 옵션을 노출하는 단일 합성 플러그인을 수용하기 위해, 플러그인 인터페이스에는 사용자가 자유 형식의 구성 사전을 제공하는 옵션이 있습니다. 이는 run 메소드에 전달됩니다 options 키워드 인수를 통해 전달됩니다. 플러그인에 이러한 구성 옵션이 있는 경우 이를 명확하게 문서화해야 합니다.


예시: 하이레벨 합성 플러그인 생성

이 예제에서는 내장된 synth_clifford_bm 함수를 사용하여 클리포드 연산자를 합성하는 높은 수준의 합성 플러그인을 만들어 보겠습니다.

클래스는 HighLevelSynthesisPlugin 클래스는 하이레벨 합성 플러그인을 위한 인터페이스와 컨트랙트를 정의합니다. 기본 방법은 run. 위치 인수 high_level_object 는 합성할 "상위 수준" 객체를 나타내는 연산입니다. 예를 들어 LinearFunction 또는 클리포드. 다음과 같은 키워드 인수가 있습니다:

  • target 는 대상 백엔드를 지정하여 플러그인 이 모든 대상별 정보에 액세스할 수 있도록 합니다, 커플링 맵, 지원되는 게이트 세트 등과 같은 모든 대상별 정보에 액세스할 수 있습니다
  • coupling_map 는 커플링 맵만 지정하며 target 가 지정되지 않은 경우에만 사용됩니다.
  • qubits 는 물리적 회로에서 합성이 이루어지는 경우 상위 레벨 객체가 정의되는 상위 레벨 객체가 정의되는 큐비트 목록을 지정합니다(물리적 회로에서 합성이 수행되는 경우). None 값은 레이아웃이 아직 선택되지 않았으며 이 작업이 작동 중인 대상 또는 커플링 맵의 물리적 큐비트가 아직 결정되지 않았음을 나타냅니다.
  • options플러그인별 옵션을 위한 자유 형식 구성 사전입니다. 플러그인에 이러한 구성 옵션이 있는 경우 를 명확하게 문서화해야 합니다.

run 메서드는 QuantumCircuit 를 반환하며, 이는 해당 상위 객체에서 합성된 회로를 나타냅니다. 또한 플러그인이 주어진 상위 수준 객체를 합성할 수 없음을 나타내는 None 을 반환할 수도 있습니다. 하이 레벨 오브젝트의 실제 합성은 HighLevelSynthesis 트랜스파일러 패스에 의해 수행됩니다.

run 메서드 외에도 정의해야 하는 여러 속성 메서드가 있습니다. 참조 HighLevelSynthesisPlugin 에서 모든 필수 속성에 대한 설명서를 확인하세요.

HighLevelSynthesisPlugin 서브클래스를 정의해 보겠습니다:

from qiskit.synthesis import synth_clifford_bm
from qiskit.transpiler.passes.synthesis.plugin import HighLevelSynthesisPlugin


class MyCliffordSynthesisPlugin(HighLevelSynthesisPlugin):
    def run(
        self,
        high_level_object,
        coupling_map=None,
        target=None,
        qubits=None,
        **options,
    ) -> QuantumCircuit:
        if high_level_object.num_qubits <= 3:
            return synth_clifford_bm(high_level_object)
        else:
            return None

이 플러그인은 클리포드 타입의 객체를 합성합니다 최대 3 큐비트를 가진 클리포드 타입의 객체를 synth_clifford_bm 메서드를 사용하여 합성합니다.

이제 Python 패키지 메타데이터에 엔트리 포인트를 추가하여 플러그인을 노출합니다. 여기서는 정의한 클래스가 my_qiskit_plugin 라는 모듈에 노출되어 있다고 가정합니다(예: my_qiskit_plugin 모듈의 __init__.py 파일에서 임포트됨). 패키지의 pyproject.toml, setup.cfg, 또는 setup.py 파일을 편집합니다:

[project.entry-points."qiskit.synthesis"]
"clifford.my_clifford_synthesis" = "my_qiskit_plugin:MyCliffordSynthesisPlugin"

name 은 점으로 구분된 두 부분으로 구성됩니다(.):

  • 플러그인이 합성하는 작업 유형의 이름(이 경우 clifford)입니다. 이 문자열은 클래스 자체의 이름이 아니라 오퍼레이션 클래스의 name 속성에 해당하며 클래스 자체의 이름이 아닙니다.
  • 플러그인 이름(이 경우 special)입니다.

이전과 마찬가지로 프로젝트에서 pyproject.toml 대신 setup.cfg 또는 setup.py 을 사용하는 경우 설정 도구 문서를 참조하여 상황에 맞게 이 줄을 조정하는 방법을 확인하세요.

플러그인이 키스킷에서 성공적으로 감지되었는지 확인하려면 플러그인 패키지를 설치하고 설치된 플러그인을 나열하는 트랜스파일러 플러그인의 지침에 따라 플러그인이 목록에 표시되는지 확인하세요:

from qiskit.transpiler.passes.synthesis import (
    high_level_synthesis_plugin_names,
)

high_level_synthesis_plugin_names("clifford")

Output:

['rb_default', 'ag', 'bm', 'default', 'greedy', 'layers', 'lnn']

예제 플러그인이 설치되어 있다면 my_clifford_synthesis 이라는 이름이 이 목록에 표시됩니다.

권장사항
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.