Vytvoření pluginu pro Transpiler
Verze balíčků
Kód na této stránce byl vytvořen s použitím následujících požadavků. Doporučujeme používat tyto verze nebo novější.
qiskit[all]~=2.3.0
Vytvoření pluginu pro Transpiler je skvělý způsob, jak sdílet svůj transpilační kód s širší komunitou Qiskit a umožnit ostatním uživatelům těžit z funkcionalit, které jsi vyvinul/a. Děkujeme za tvůj zájem přispívat do komunity Qiskit!
Před vytvořením pluginu pro Transpiler se musíš rozhodnout, jaký druh pluginu je pro tvou situaci vhodný. Existují tři druhy pluginů pro Transpiler:
- Plugin pro fázi Transpileru. Zvol tuto možnost, pokud definuješ pass manager, který lze nahradit za jednu z 6 fází nastaveného stagovaného pass manageru.
- Plugin pro syntézu unitárních operátorů. Zvol tuto možnost, pokud tvůj transpilační kód přijímá jako vstup unitární matici (reprezentovanou jako pole Numpy) a vrací popis kvantového Circuit implementujícího tuto unitární matici.
- Plugin pro vysokoúrovňovou syntézu. Zvol tuto možnost, pokud tvůj transpilační kód přijímá jako vstup „vysokoúrovňový objekt", například operátor Clifford nebo lineární funkci, a vrací popis kvantového Circuit implementujícího tento vysokoúrovňový objekt. Vysokoúrovňové objekty jsou reprezentovány podtřídami třídy Operation.
Jakmile určíš, jaký druh pluginu chceš vytvořit, postupuj podle těchto kroků:
- Vytvoř podtřídu příslušné abstraktní třídy pluginu:
- PassManagerStagePlugin pro plugin fáze Transpileru,
- UnitarySynthesisPlugin pro plugin syntézy unitárních operátorů a
- HighLevelSynthesisPlugin pro plugin vysokoúrovňové syntézy.
- Vystav třídu jako vstupní bod setuptools v metadatech balíčku, obvykle úpravou souboru
pyproject.toml,setup.cfgnebosetup.pysvého Python balíčku.
Neexistuje žádné omezení počtu pluginů, které může jeden balíček definovat, ale každý plugin musí mít jedinečný název. Samotné Qiskit SDK obsahuje řadu pluginů, jejichž názvy jsou také rezervovány. Rezervované názvy jsou:
- Pluginy fází Transpileru: Viz tato tabulka.
- Pluginy syntézy unitárních operátorů:
default,aqc,sk - Pluginy vysokoúrovňové syntézy:
| Třída operace | Název operace | Rezervované názvy |
|---|---|---|
| Clifford | clifford | default, ag, bm, greedy, layers, lnn |
| LinearFunction | linear_function | default, kms, pmh |
| PermutationGate | permutation | default, kms, basic, acg, token_swapper |
V následujících sekcích ukážeme příklady těchto kroků pro různé typy pluginů. V těchto příkladech předpokládáme, že vytváříme Python balíček s názvem my_qiskit_plugin. Informace o vytváření Python balíčků najdeš v tomto tutoriálu na webu Pythonu.
Příklad: Vytvoření pluginu fáze Transpileru
V tomto příkladu vytvoříme plugin fáze Transpileru pro fázi layout (popis 6 fází vestavěného transpilačního pipeline Qiskitu najdeš v části Fáze Transpileru).
Náš plugin jednoduše spouští VF2Layout s počtem pokusů závislým na požadované úrovni optimalizace.
Nejprve vytvoříme podtřídu PassManagerStagePlugin. Potřebujeme implementovat jednu metodu s názvem pass_manager. Tato metoda přijímá jako vstup PassManagerConfig a vrací pass manager, který definujeme. Objekt PassManagerConfig uchovává informace o cílovém Backend, například jeho coupling map a základní Gate.
# 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
Nyní vystavíme plugin přidáním vstupního bodu do metadat našeho Python balíčku.
Předpokládáme, že třída, kterou jsme definovali, je vystavena v modulu s názvem my_qiskit_plugin, například importem v souboru __init__.py modulu my_qiskit_plugin.
Upravíme soubor pyproject.toml, setup.cfg nebo setup.py našeho balíčku (podle toho, jaký soubor jsi zvolil/a pro uložení metadat svého Python projektu):
- 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',
]
}
)
Viz tabulka fází pluginů pro Transpiler, kde najdeš vstupní body a požadavky pro každou fázi Transpileru.
Chceš-li ověřit, že Qiskit tvůj plugin úspěšně detekuje, nainstaluj balíček pluginu a postupuj podle pokynů v části Pluginy pro Transpiler pro výpis nainstalovaných pluginů, a ujisti se, že tvůj plugin se v seznamu zobrazí:
from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins
list_stage_plugins("layout")
['default', 'dense', 'sabre', 'trivial']
Pokud by byl náš ukázkový plugin nainstalován, v tomto seznamu by se zobrazil název my_layout.
Chceš-li jako výchozí bod pro svůj plugin fáze Transpileru použít vestavěnou fázi Transpileru, můžeš získat pass manager pro vestavěnou fázi Transpileru pomocí PassManagerStagePluginManager. Následující buňka kódu ukazuje, jak to provést pro získání vestavěné fáze optimalizace pro úroveň optimalizace 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
)
Příklad: Vytvoření pluginu pro syntézu unitárních operátorů
V tomto příkladu vytvoříme plugin pro syntézu unitárních operátorů, který jednoduše používá vestavěný transpilační průchod UnitarySynthesis pro syntézu Gate. Tvůj vlastní plugin samozřejmě bude dělat něco zajímavějšího.
Třída UnitarySynthesisPlugin definuje rozhraní a kontrakt pro pluginy syntézy unitárních operátorů. Primární metodou je
run,
která přijímá jako vstup pole Numpy uchovávající unitární matici
a vrací DAGCircuit reprezentující Circuit syntetizovaný z této unitární matice.
Kromě metody run je třeba definovat řadu property metod.
Dokumentaci všech požadovaných vlastností najdeš v UnitarySynthesisPlugin.
Pojďme vytvořit naši podtřídu 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
Pokud zjistíš, že vstupy dostupné metodě run
pro tvé účely nestačí, prosím otevři issue s popisem svých požadavků. Zm ěny rozhraní pluginu, jako je přidání dalších volitelných vstupů, budou provedeny zpětně kompatibilním způsobem, takže nebudou vyžadovat změny v existujících pluginech.
Všechny metody s předponou supports_ jsou na odvozené třídě UnitarySynthesisPlugin vyhrazeny jako součást rozhraní. Na podtřídě bys neměl/a definovat žádné vlastní metody supports_*, které nejsou definovány v abstraktní třídě.
Nyní vystavíme plugin přidáním vstupního bodu do metadat našeho Python balíčku.
Předpokládáme, že třída, kterou jsme definovali, je vystavena v modulu s názvem my_qiskit_plugin, například importem v souboru __init__.py modulu my_qiskit_plugin.
Upravíme soubor pyproject.toml, setup.cfg nebo setup.py našeho balíčku:
- 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',
]
}
)
Stejně jako dříve, pokud tvůj projekt používá setup.cfg nebo setup.py místo pyproject.toml, viz dokumentace setuptools, kde najdeš, jak tyto řádky upravit pro svou situaci.
Chceš-li ověřit, že Qiskit tvůj plugin úspěšně detekuje, nainstaluj balíček pluginu a postupuj podle pokynů v části Pluginy pro Transpiler pro výpis nainstalovaných pluginů, a ujisti se, že tvůj plugin se v seznamu zobrazí:
from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names
unitary_synthesis_plugin_names()
['aqc', 'clifford', 'default', 'gridsynth', 'sk']
Pokud by byl náš ukázkový plugin nainstalován, v tomto seznamu by se zobrazil název my_unitary_synthesis.
Aby se vyhovělo pluginům pro syntézu unitárních operátorů, které nabízejí více možností,
rozhraní pluginu obsahuje volbu, kde mohou uživatelé poskytnout slovník s volnou konfigurací. Ten bude předán metodě run
prostřednictvím klíčového argumentu options. Pokud tvůj plugin tyto konfigurační možnosti má, měl/a bys je jasně zdokumentovat.
Příklad: Vytvoření pluginu pro vysokoúrovňovou syntézu
V tomto příkladu vytvoříme plugin pro vysokoúrovňovou syntézu, který jednoduše používá vestavěnou funkci synth_clifford_bm pro syntézu operátoru Clifford.
Třída HighLevelSynthesisPlugin definuje rozhraní a kontrakt pro pluginy vysokoúrovňové syntézy. Primární metodou je run.
Poziční argument high_level_object je Operation reprezentující „vysokoúrovňový" objekt, který má být syntetizován. Může to být například
LinearFunction nebo
Clifford.
Jsou přítomny následující klíčové argumenty:
targetspecifikuje cílový Backend a umožňuje pluginu přistupovat ke všem informacím specifickým pro cíl, jako je coupling map, podporovaná sada Gate a podobněcoupling_mapspecifikuje pouze coupling map a používá se pouze tehdy, kdyžtargetnení zadán.qubitsspecifikuje seznam Qubitů, nad kterými je vysokoúrovňový objekt definován, v případě, že syntéza probíhá na fyzickém Circuit. HodnotaNoneznamená, že rozložení ještě nebylo zvoleno a fyzické Qubity v cíli nebo coupling mapě, na nichž tato operace pracuje, ještě nebyly určeny.options, slovník s volnou konfigurací pro volby specifické pro plugin. Pokud tvůj plugin tyto konfigurační možnosti má, měl/a bys je jasně zdokumentovat.
Metoda run vrací QuantumCircuit
reprezentující Circuit syntetizovaný z daného vysokoúrovňového objektu.
Je také povoleno vrátit None, což znamená, že plugin není schopen syntetizovat daný vysokoúrovňový objekt.
Samotná syntéza vysokoúrovňových objektů je prováděna průchodem Transpileru
HighLevelSynthesis.
Kromě metody run je třeba definovat řadu property metod.
Dokumentaci všech požadovaných vlastností najdeš v HighLevelSynthesisPlugin.
Pojďme definovat naši podtřídu 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
Tento plugin syntetizuje objekty typu Clifford, které mají
nejvýše 3 Qubity, pomocí metody synth_clifford_bm.
Nyní vystavíme plugin přidáním vstupního bodu do metadat našeho Python balíčku.
Předpokládáme, že třída, kterou jsme definovali, je vystavena v modulu s názvem my_qiskit_plugin, například importem v souboru __init__.py modulu my_qiskit_plugin.
Upravíme soubor pyproject.toml, setup.cfg nebo setup.py našeho balíčku:
- 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',
]
}
)
Název name se skládá ze dvou částí oddělených tečkou (.):
- Název typu Operation, který plugin syntetizuje (v tomto případě
clifford). Upozorňujeme, že tento řetězec odpovídá atributunametřídy Operation, nikoli názvu samotné třídy. - Název pluginu (v tomto případě
special).
Stejně jako dříve, pokud tvůj projekt používá setup.cfg nebo setup.py místo pyproject.toml, viz dokumentace setuptools, kde najdeš, jak tyto řádky upravit pro svou situaci.
Chceš-li ověřit, že Qiskit tvůj plugin úspěšně detekuje, nainstaluj balíček pluginu a postupuj podle pokynů v části Pluginy pro Transpiler pro výpis nainstalovaných pluginů, a ujisti se, že tvůj plugin se v seznamu zobrazí:
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']
Pokud by byl náš ukázkový plugin nainstalován, v tomto seznamu by se zobrazil název my_clifford_synthesis.
- Přidej svůj plugin do ekosystému Qiskit!.
- Prohlédni si tutoriály s příklady transpilace a spouštění kvantových Circuit.