Gumawa ng transpiler plugin
Mga bersyon ng package
Ang code sa pahinang ito ay ginawa gamit ang mga sumusunod na kinakailangan. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago.
qiskit[all]~=2.3.0
Ang paggawa ng transpiler plugin ay isang magandang paraan para ibahagi ang iyong transpilation code sa mas malawak na komunidad ng Qiskit, na nagbibigay-daan sa ibang mga user na makinabang sa functionality na iyong ginawa. Salamat sa iyong interes na mag-ambag sa komunidad ng Qiskit!
Bago ka gumawa ng transpiler plugin, kailangan mong magpasya kung anong uri ng plugin ang angkop para sa iyong sitwasyon. May tatlong uri ng transpiler plugins:
- Transpiler stage plugin. Piliin ito kung nagtatakda ka ng pass manager na maaaring ipalit sa isa sa 6 na yugto ng isang preset staged pass manager.
- Unitary synthesis plugin. Piliin ito kung ang iyong transpilation code ay tumatanggap ng unitary matrix bilang input (kinakatawan bilang Numpy array) at naglalabas ng paglalarawan ng quantum circuit na nagpapatupad ng unitary na iyon.
- High-level synthesis plugin. Piliin ito kung ang iyong transpilation code ay tumatanggap ng "high-level na object" tulad ng Clifford operator o linear function bilang input at naglalabas ng paglalarawan ng quantum circuit na nagpapatupad ng high-level na object na iyon. Ang mga high-level na object ay kinakatawan ng mga subclass ng Operation class.
Kapag natukoy mo na kung anong uri ng plugin ang gagawin, sundin ang mga hakbang na ito para gawin ang plugin:
- Gumawa ng subclass ng naaangkop na abstract plugin class:
- PassManagerStagePlugin para sa transpiler stage plugin,
- UnitarySynthesisPlugin para sa unitary synthesis plugin, at
- HighLevelSynthesisPlugin para sa high-level synthesis plugin.
- I-expose ang class bilang setuptools entry point sa metadata ng package, karaniwan sa pamamagitan ng pag-edit ng
pyproject.toml,setup.cfg, osetup.pyna file ng iyong Python package.
Walang limitasyon sa bilang ng mga plugin na maaaring tukuyin ng isang package, ngunit ang bawat plugin ay dapat may natatanging pangalan. Kasama sa Qiskit SDK ang ilang built-in na plugins, at ang kanilang mga pangalan ay nakalaan din. Ang mga nakalaan na pangalan ay:
- Transpiler stage plugins: Tingnan ang talahanayan na ito.
- Unitary synthesis plugins:
default,aqc,sk - High-level synthesis plugins:
| Klase ng Operation | Pangalan ng Operation | Mga nakalaan na pangalan |
|---|---|---|
| Clifford | clifford | default, ag, bm, greedy, layers, lnn |
| LinearFunction | linear_function | default, kms, pmh |
| PermutationGate | permutation | default, kms, basic, acg, token_swapper |
Sa mga susunod na seksyon, nagpapakita tayo ng mga halimbawa ng mga hakbang na ito para sa iba't ibang uri ng plugins. Sa mga halimbawang ito, ipinapalagay natin na gumagawa tayo ng Python package na tinatawag na my_qiskit_plugin. Para sa impormasyon tungkol sa paggawa ng Python packages, maaari mong tingnan ang tutorial na ito mula sa website ng Python.
Halimbawa: Gumawa ng transpiler stage plugin​
Sa halimbawang ito, gumagawa tayo ng transpiler stage plugin para sa layout na yugto (tingnan ang Transpiler stages para sa paglalarawan ng 6 na yugto ng built-in na transpilation pipeline ng Qiskit).
Ang aming plugin ay nagpapatakbo lang ng VF2Layout para sa bilang ng mga trial na depende sa hiniling na antas ng optimization.
Una, gumagawa tayo ng subclass ng PassManagerStagePlugin. May isang method na kailangan nating i-implement, na tinatawag na pass_manager. Tinatanggap ng method na ito bilang input ang isang PassManagerConfig at ibinabalik ang pass manager na ating tinutukoy. Ang PassManagerConfig na object ay nag-iimbak ng impormasyon tungkol sa target na backend, tulad ng coupling map at basis gates nito.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit
# 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
Ngayon, i-expose natin ang plugin sa pamamagitan ng pagdaragdag ng entry point sa metadata ng aming Python package.
Dito, ipinapalagay natin na ang class na aming tinukoy ay naka-expose sa isang module na tinatawag na my_qiskit_plugin, halimbawa sa pamamagitan ng pag-import nito sa __init__.py na file ng my_qiskit_plugin module.
Ie-edit natin ang pyproject.toml, setup.cfg, o setup.py na file ng aming package (depende kung aling uri ng file ang pinili mong gamitin para i-store ang metadata ng iyong Python project):
- pyproject.toml
- setup.cfg
- setup.py
[project.entry-points."qiskit.transpiler.layout"]
"my_layout" = "my_qiskit_plugin:MyLayoutPlugin"
[options.entry_points]
qiskit.transpiler.layout =
my_layout = my_qiskit_plugin:MyLayoutPlugin
from setuptools import setup
setup(
# ...,
entry_points={
'qiskit.transpiler.layout': [
'my_layout = my_qiskit_plugin:MyLayoutPlugin',
]
}
)
Tingnan ang talahanayan ng mga transpiler plugin stage para sa mga entry point at mga inaasahan para sa bawat transpiler stage.
Para tingnan kung matagumpay na nadetect ng Qiskit ang iyong plugin, i-install ang iyong plugin package at sundin ang mga tagubilin sa Transpiler plugins para sa pag-lista ng mga naka-install na plugins, at tiyakin na lumalabas ang iyong plugin sa listahan:
from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins
list_stage_plugins("layout")
['default', 'dense', 'sabre', 'trivial']
Kung naka-install ang aming halimbawang plugin, lilitaw ang pangalang my_layout sa listahang ito.
Kung gusto mong gamitin ang isang built-in na transpiler stage bilang panimulang punto para sa iyong transpiler stage plugin, maaari mong makuha ang pass manager para sa isang built-in na transpiler stage gamit ang PassManagerStagePluginManager. Ipinapakita ng sumusunod na code cell kung paano ito gawin para makuha ang built-in na optimization stage para sa optimization level 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
)
Halimbawa: Gumawa ng unitary synthesis plugin​
Sa halimbawang ito, gagawa tayo ng unitary synthesis plugin na gumagamit lang ng built-in na UnitarySynthesis transpilation pass para mag-synthesize ng gate. Syempre, ang iyong sariling plugin ay gagawa ng mas kawili-wiling bagay kaysa riyan.
Ang UnitarySynthesisPlugin class ay tumutukoy sa interface at kontrata para sa unitary synthesis
plugins. Ang pangunahing method ay
run,
na tumatanggap bilang input ng Numpy array na nag-iimbak ng unitary matrix
at nagbabalik ng DAGCircuit na kumakatawan sa circuit na na-synthesize mula sa unitary matrix na iyon.
Bukod sa run method, may ilang property method na kailangang tukuyin.
Tingnan ang UnitarySynthesisPlugin para sa dokumentasyon ng lahat ng kinakailangang property.
Gawin natin ang ating UnitarySynthesisPlugin subclass:
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
Kung nalaman mong hindi sapat ang mga input na available sa run
method para sa iyong layunin, mangyaring mag-open ng issue na nagpapaliwanag ng iyong mga kinakailangan. Ang mga pagbabago sa plugin interface, tulad ng pagdaragdag ng karagdagang opsyonal na input, ay gagawin sa isang paraan na backward compatible para hindi ito mangailangan ng mga pagbabago mula sa mga kasalukuyang plugins.
Lahat ng method na may prefix na supports_ ay nakalaan sa isang UnitarySynthesisPlugin derived class bilang bahagi ng interface. Hindi ka dapat mag-define ng anumang custom na supports_* method sa isang subclass na hindi tinukoy sa abstract class.
Ngayon, i-expose natin ang plugin sa pamamagitan ng pagdaragdag ng entry point sa metadata ng aming Python package.
Dito, ipinapalagay natin na ang class na aming tinukoy ay naka-expose sa isang module na tinatawag na my_qiskit_plugin, halimbawa sa pamamagitan ng pag-import nito sa __init__.py na file ng my_qiskit_plugin module.
Ie-edit natin ang pyproject.toml, setup.cfg, o setup.py na file ng aming package:
- 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:MyUnitarySynthesisPlugin
from setuptools import setup
setup(
# ...,
entry_points={
'qiskit.unitary_synthesis': [
'my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPlugin',
]
}
)
Tulad ng dati, kung ang iyong project ay gumagamit ng setup.cfg o setup.py sa halip na pyproject.toml, tingnan ang dokumentasyon ng setuptools para malaman kung paano i-adapt ang mga linyang ito para sa iyong sitwasyon.
Para tingnan kung matagumpay na nadetect ng Qiskit ang iyong plugin, i-install ang iyong plugin package at sundin ang mga tagubilin sa Transpiler plugins para sa pag-lista ng mga naka-install na plugins, at tiyakin na lumalabas ang iyong plugin sa listahan:
from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names
unitary_synthesis_plugin_names()
['aqc', 'clifford', 'default', 'gridsynth', 'sk']
Kung naka-install ang aming halimbawang plugin, lilitaw ang pangalang my_unitary_synthesis sa listahang ito.
Para ma-accommodate ang mga unitary synthesis plugin na naglalantad ng maraming opsyon,
ang plugin interface ay may opsyon para sa mga user na magbigay ng free-form
na configuration dictionary. Ito ay ipapasa sa run method
sa pamamagitan ng options keyword argument. Kung ang iyong plugin ay may mga configuration option na ito, dapat mong malinaw na idokumento ang mga ito.
Halimbawa: Gumawa ng high-level synthesis plugin​
Sa halimbawang ito, gagawa tayo ng high-level synthesis plugin na gumagamit lang ng built-in na function na synth_clifford_bm para mag-synthesize ng Clifford operator.
Ang HighLevelSynthesisPlugin class ay tumutukoy sa interface at kontrata para sa high-level synthesis plugins. Ang pangunahing method ay run.
Ang positional argument na high_level_object ay isang Operation na kumakatawan sa "high-level" na object na ise-synthesize. Halimbawa, maaari itong maging isang
LinearFunction o isang
Clifford.
Ang mga sumusunod na keyword argument ay naroroon:
- Ang
targetay tumutukoy sa target na backend, na nagbibigay-daan sa plugin na ma-access ang lahat ng target-specific na impormasyon, tulad ng coupling map, ang sinusuportahang gate set, at iba pa - Ang
coupling_mapay tumutukoy lamang sa coupling map, at ginagamit lamang kapag hindi tinukoy angtarget. - Ang
qubitsay tumutukoy sa listahan ng mga Qubit kung saan tinukoy ang high-level na object, sa kaso na ang synthesis ay ginagawa sa physical circuit. Ang halagangNoneay nagpapahiwatig na hindi pa napili ang layout at ang mga physical na Qubit sa target o coupling map na pinagtatrabahuhan ng operasyong ito ay hindi pa natutukoy. - Ang
options, isang free-form configuration dictionary para sa mga opsyon na tukoy sa plugin. Kung ang iyong plugin ay may mga configuration option na ito, dapat mong malinaw na idokumento ang mga ito.
Ang run method ay nagbabalik ng QuantumCircuit
na kumakatawan sa circuit na na-synthesize mula sa high-level na object na iyon.
Pinapayagan din na magbalik ng None, na nagpapahiwatig na hindi makakapag-synthesize ang plugin ng ibinigay na high-level na object.
Ang aktwal na synthesis ng mga high-level na object ay isinasagawa ng
HighLevelSynthesis
transpiler pass.
Bukod sa run method, may ilang property method na kailangang tukuyin.
Tingnan ang HighLevelSynthesisPlugin para sa dokumentasyon ng lahat ng kinakailangang property.
Tukuyin natin ang ating HighLevelSynthesisPlugin subclass:
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
Ang plugin na ito ay nag-synthesize ng mga object ng uri Clifford na may
hindi hihigit sa 3 na Qubit, gamit ang synth_clifford_bm method.
Ngayon, i-expose natin ang plugin sa pamamagitan ng pagdaragdag ng entry point sa metadata ng aming Python package.
Dito, ipinapalagay natin na ang class na aming tinukoy ay naka-expose sa isang module na tinatawag na my_qiskit_plugin, halimbawa sa pamamagitan ng pag-import nito sa __init__.py na file ng my_qiskit_plugin module.
Ie-edit natin ang pyproject.toml, setup.cfg, o setup.py na file ng aming package:
- 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:MyCliffordSynthesisPlugin
from setuptools import setup
setup(
# ...,
entry_points={
'qiskit.synthesis': [
'clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPlugin',
]
}
)
Ang name ay binubuo ng dalawang bahagi na pinaghiwalay ng tuldok (.):
- Ang pangalan ng uri ng Operation na ine-synthesize ng plugin (sa kasong ito,
clifford). Tandaan na ang string na ito ay tumutugma sanameattribute ng Operation class, at hindi sa pangalan ng class mismo. - Ang pangalan ng plugin (sa kasong ito,
special).
Tulad ng dati, kung ang iyong project ay gumagamit ng setup.cfg o setup.py sa halip na pyproject.toml, tingnan ang dokumentasyon ng setuptools para malaman kung paano i-adapt ang mga linyang ito para sa iyong sitwasyon.
Para tingnan kung matagumpay na nadetect ng Qiskit ang iyong plugin, i-install ang iyong plugin package at sundin ang mga tagubilin sa Transpiler plugins para sa pag-lista ng mga naka-install na plugins, at tiyakin na lumalabas ang iyong plugin sa listahan:
from qiskit.transpiler.passes.synthesis import (
high_level_synthesis_plugin_names,
)
high_level_synthesis_plugin_names("clifford")
['ag', 'bm', 'default', 'greedy', 'layers', 'lnn', 'rb_default']
Kung naka-install ang aming halimbawang plugin, lilitaw ang pangalang my_clifford_synthesis sa listahang ito.
- I-submit ang iyong plugin sa Qiskit Ecosystem!.
- Tingnan ang mga tutorial para sa mga halimbawa ng pag-transpile at pagpapatakbo ng mga quantum circuit.