トランスパイラープラグインを作成する
このページのコードは、以下の要件に基づいて開発された。 これらのバージョンまたは新しいバージョンの使用をお勧めします。
qiskit[all]~=2.5.1
トランスパイラープラグインを作成することは、あなたのトランスパイルコードをより広いQiskitコミュニティと共有する素晴らしい方法です。 Qiskitコミュニティへの貢献に関心をお寄せいただき、ありがとうございます!
トランスパイラープラグインを作成する前に、どのようなプラグインがあなたの状況に適しているかを決める必要があります。 トランスパイラープラグインには3種類ある:
- トランスパイラーステージプラグイン。 プリセット・ステージド・パス・マネージャーの 6つのステージのうちの1つに置き換えられるパス・マネージャーを定義する場合に選択します。
- ユニタリー・シンセシス・プラグイン。 ユニタリー行列(Numpyの配列として表現)を入力とし、そのユニタリーを実装した量子回路の記述を出力するトランスパイルコードを作成する場合に選択します。
- 高位合成プラグイン。 あなたのトランスパイルコードが、クリフォード演算子や線形関数のような「高レベルオブジェクト」を入力とし、その高レベルオブジェクトを実装した量子回路の記述を出力する場合、これを選択します。 高レベルのオブジェクトは、 Operation クラスのサブクラスで表される。
作成するプラグインの種類が決まったら、以下の手順に従ってプラグインを作成します:
- 適切な抽象プラグイン・クラスのサブクラスを作成する:
- PassManagerStagePlugin トランスパイラーステージプラグイン
- UnitarySynthesisPlugin ユニタリー・シンセシス・プラグインの場合
- HighLevelSynthesisPlugin 高位合成プラグイン用。
- パッケージ・メタデータの setuptoolsエントリ・ポイントとしてクラスを公開します。通常は、 Python パッケージの
pyproject.toml、setup.cfg、またはsetup.pyファイルを編集します。
1つのパッケージで定義できるプラグインの数に制限はありませんが、各プラグインには一意な名前が必要です。 Qiskit SDK自体には多くのプラグインが含まれており、その名前も予約されています。 予約名は以下の通り:
- トランスパイラのステージプラグイン: この表を参照してください。
- 単体合成プラグイン:
defaultaqc、sk - ハイレベル・シンセシス・プラグイン:
オペレーションクラス | 操作名 | 予約名 |
|---|---|---|
| Clifford | clifford | default, ag, bm, greedy, layers, lnn |
| LinearFunction | linear_function | default, kms, pmh |
| PermutationGate | permutation | default, kms, basic, acg, token_swapper |
次のセクションでは、異なるタイプのプラグインについて、これらの手順の例を示します。 これらの例では、 my_qiskit_plugin という Python パッケージを作成すると仮定する。 Python パッケージの作成については、 Python ウェブサイトのチュートリアルをご覧ください。
例: トランスパイラーステージプラグインを作成する
この例では、 layout ステージ用のトランスパイラーステージプラグインを作成します(Qiskitの組み込みトランスパイルパイプラインの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"[options.entry_points]
qiskit.transpiler.layout =
my_layout = my_qiskit_plugin:MyLayoutPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.transpiler.layout': [
'my_layout = my_qiskit_plugin:MyLayoutPlugin',
]
}
)各トランスパイラステージのエントリーポイントと期待値については、 トランスパイラープラグインステージの表を参照してください。
プラグインがQiskitによって正常に検出されていることを確認するには、プラグインパッケージをインストールし、インストールされているプラグインを一覧表示するための Transpiler pluginsの指示に従って、プラグインがリストに表示されていることを確認します:
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配列 を格納する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 メソッドに利用可能な入力があなたの目的には不十分であるとお気づきの場合は、あなたの要件を説明する issueを開いてください。 オプション入力の追加など、プラグインのインターフェイスの変更は、既存のプラグインからの変更を必要としないよう、後方互換性のある方法で行われます。
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"[options.entry_points]
qiskit.unitary_synthesis =
my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.unitary_synthesis': [
'my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPlugin',
]
}
)あなたのプロジェクトが pyproject.toml の代わりに setup.cfg または setup.py を使用している場合、あなたの状況に合わせてこれらの行を適応させる方法については、これまでと同様に setuptoolsのドキュメントを参照してください。
プラグインがQiskitによって正常に検出されていることを確認するには、プラグインパッケージをインストールし、インストールされているプラグインを一覧表示するための Transpiler pluginsの指示に従って、プラグインがリストに表示されていることを確認します:
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 は、合成される「高レベル」オブジェクトを表す Operation である。 例えば 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このプラグインは、以下のような Clifford 型のオブジェクトを合成する。 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"[options.entry_points]
qiskit.synthesis =
clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.synthesis': [
'clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPlugin',
]
}
)name は、ドット(.)で区切られた2つの部分で構成されている:
- プラグインが合成する Operationのタイプ名(この場合、
clifford)。この文字列はOperationクラスのname属性に対応し、クラス自体の名前ではないことに注意してください。 - プラグインの名前(この場合は
special)。
あなたのプロジェクトが pyproject.toml の代わりに setup.cfg または setup.py を使用している場合、あなたの状況に合わせてこれらの行を適応させる方法については、これまでと同様に setuptoolsのドキュメントを参照してください。
プラグインがQiskitによって正常に検出されていることを確認するには、プラグインパッケージをインストールし、インストールされているプラグインを一覧表示するための Transpiler pluginsの指示に従って、プラグインがリストに表示されていることを確認します:
from qiskit.transpiler.passes.synthesis import (
high_level_synthesis_plugin_names,
)
high_level_synthesis_plugin_names("clifford")Output:
['ag', 'bm', 'default', 'greedy', 'layers', 'lnn', 'rb_default']
この例のプラグインがインストールされていれば、 my_clifford_synthesis という名前がこのリストに表示される。
- Qiskitエコシステムにプラグインを投稿してください。
- 量子回路のトランスパイルと実行の例については、 チュートリアルをチェックしてほしい。