สร้าง transpiler plugin
เวอร์ชันของแพ็กเกจ
โค้ดในหน้านี้พัฒนาขึ้นโดยใช้ข้อกำหนดต่อไปนี้ แนะนำให้ใช้เวอร์ชันเหล่านี้หรือใหม่กว่า
qiskit[all]~=2.3.0
การสร้าง transpiler plugin เป็นวิธีที่ดีในการแชร์โค้ด transpilation ของคุณกับชุมชน Qiskit ในวงกว้าง ทำให้ผู้ใช้คนอื่นได้รับประโยชน์จากฟังก์ชันที่คุณพัฒนาขึ้น ขอบคุณที่สนใจมีส่วนร่วมกับชุมชน Qiskit!
ก่อนสร้าง transpiler plugin คุณต้องตัดสินใจว่า plugin ประเภทใดเหมาะกับสถานการณ์ของคุณ มี transpiler plugin อยู่สามประเภท:
- Transpiler stage plugin เลือกแบบนี้ถ้าคุณกำลังกำหนด pass manager ที่สามารถใช้แทนหนึ่งใน 6 ขั้นตอน ของ preset staged pass manager
- Unitary synthesis plugin เลือกแบบนี้ถ้าโค้ด transpilation ของคุณรับ unitary matrix เป็น input (แสดงเป็น Numpy array) และ output คำอธิบายของ quantum Circuit ที่ implement unitary นั้น
- High-level synthesis plugin เลือกแบบนี้ถ้าโค้ด transpilation ของคุณรับ "high-level object" เช่น Clifford operator หรือ linear function เป็น input และ output คำอธิบายของ quantum Circuit ที่ implement high-level object นั้น High-level object แสดงโดย subclass ของคลาส Operation
เมื่อกำหนดได้แล้วว่าจะสร้าง plugin ประเภทใด ให้ทำตามขั้นตอนเหล่านี้เพื่อสร้าง plugin:
- สร้าง subclass ของ abstract plugin class ที่เหมาะสม:
- PassManagerStagePlugin สำหรับ transpiler stage plugin
- UnitarySynthesisPlugin สำหรับ unitary synthesis plugin และ
- HighLevelSynthesisPlugin สำหรับ high-level synthesis plugin
- เปิดเผยคลาสในฐานะ setuptools entry point ใน package metadata โดยทั่วไปแล้วทำได้โดยแก้ไขไฟล์
pyproject.toml,setup.cfgหรือsetup.pyของ Python package ของคุณ
ไม่มีการจำกัดจำนวน plugin ที่ package หนึ่งจะกำหนดได้ แต่แต่ละ plugin ต้องมีชื่อที่ไม่ซ้ำกัน Qiskit SDK เองมี plugin จำนวนหนึ่ง ซึ่งชื่อของมันก็ถูกสงวนไว้ด้วย ชื่อที่สงวนไว้คือ:
- Transpiler stage plugin: ดู ตารางนี้
- Unitary synthesis plugin:
default,aqc,sk - High-level synthesis plugin:
| คลาส Operation | ชื่อ Operation | ชื่อที่สงวนไว้ |
|---|---|---|
| Clifford | clifford | default, ag, bm, greedy, layers, lnn |
| LinearFunction | linear_function | default, kms, pmh |
| PermutationGate | permutation | default, kms, basic, acg, token_swapper |
ในส่วนถัดไป เราจะแสดงตัวอย่างของขั้นตอนเหล่านี้สำหรับ plugin แต่ละประเภท ในตัวอย่างเหล่านี้ เราสมมติว่าเรากำลังสร้าง Python package ชื่อ my_qiskit_plugin สำหรับข้อมูลเกี่ยวกับการสร้าง Python package ดูได้ที่ tutorial นี้ จากเว็บไซต์ Python
ตัวอย่าง: สร้าง transpiler stage plugin
ในตัวอย่างนี้ เราสร้าง transpiler stage plugin สำหรับ layout stage (ดู Transpiler stages สำหรับคำอธิบายของ 6 ขั้นตอนใน transpilation pipeline ที่ built-in ของ Qiskit)
plugin ของเราเพียงแค่รัน VF2Layout สำหรับจำนวน trial ที่ขึ้นอยู่กับ optimization level ที่ร้องขอ
ก่อนอื่น เราสร้าง subclass ของ PassManagerStagePlugin มีหนึ่ง method ที่ต้อง implement ชื่อว่า pass_manager method นี้รับ PassManagerConfig เป็น input และส่งคืน pass manager ที่เราต้องการกำหนด object PassManagerConfig เก็บข้อมูลเกี่ยวกับ backend เป้าหมาย เช่น coupling map และ basis 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
ตอนนี้ เราเปิดเผย plugin โดยเพิ่ม entry point ใน Python package metadata ของเรา
ที่นี่ เราสมมติว่าคลาสที่เรากำหนดเปิดเผยอยู่ใน module ชื่อ my_qiskit_plugin เช่น ถูก import ในไฟล์ __init__.py ของ module my_qiskit_plugin
เราแก้ไขไฟล์ pyproject.toml, setup.cfg หรือ setup.py ของ package ของเรา (ขึ้นอยู่กับประเภทของไฟล์ที่คุณเลือกเก็บ Python project metadata):
- 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',
]
}
)
ดู ตาราง transpiler plugin stage สำหรับ entry point และข้อกำหนดของแต่ละ transpiler stage
เพื่อตรวจสอบว่า plugin ของคุณถูก Qiskit ตรวจพบสำเร็จ ติดตั้ง plugin package ของคุณแล้วทำตามคำแนะนำที่ Transpiler plugins สำหรับการแสดงรายการ plugin ที่ติดตั้งแล้ว และตรวจสอบว่า plugin ของคุณปรากฏอยู่ในรายการ:
from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins
list_stage_plugins("layout")
['default', 'dense', 'sabre', 'trivial']
ถ้า plugin ตัวอย่างของเราถูกติดตั้ง ชื่อ my_layout จะปรากฏในรายการนี้
ถ้าคุณต้องการใช้ transpiler stage ที่ built-in เป็นจุดเริ่มต้นสำหรับ transpiler stage plugin ของคุณ คุณสามารถรับ pass manager สำหรับ transpiler stage ที่ built-in ได้โดยใช้ PassManagerStagePluginManager code cell ต่อไปนี้แสดงวิธีทำเพื่อรับ optimization stage ที่ built-in สำหรับ 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
)
ตัวอย่าง: สร้าง unitary synthesis plugin
ในตัวอย่างนี้ เราจะสร้าง unitary synthesis plugin ที่เพียงใช้ transpilation pass UnitarySynthesis ที่ built-in เพื่อ synthesize Gate แน่นอนว่า plugin ของคุณเองจะทำสิ่งที่น่าสนใจกว่านี้
คลาส UnitarySynthesisPlugin กำหนด interface และ contract สำหรับ unitary synthesis
plugin method หลักคือ
run
ซึ่งรับ Numpy array ที่เก็บ unitary matrix เป็น input
และส่งคืน DAGCircuit ที่แสดง Circuit ที่ synthesize มาจาก unitary matrix นั้น
นอกจาก method run แล้ว ยังมี property method อีกหลายอย่างที่ต้องกำหนด
ดู UnitarySynthesisPlugin สำหรับเอกสารของ property ที่จำเป็นทั้งหมด
มาสร้าง 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
ถ้าคุณพบว่า input ที่มีให้กับ method run
ไม่เพียงพอสำหรับจุดประสงค์ของคุณ กรุณา เปิด issue อธิบ ายข้อกำหนดของคุณ การเปลี่ยนแปลง plugin interface เช่น การเพิ่ม optional input เพิ่มเติม จะทำในลักษณะที่เข้ากันได้แบบย้อนหลัง เพื่อไม่ให้ต้องมีการเปลี่ยนแปลงจาก plugin ที่มีอยู่แล้ว
method ทั้งหมดที่นำหน้าด้วย supports_ ถูกสงวนไว้บน derived class ของ UnitarySynthesisPlugin เป็นส่วนหนึ่งของ interface คุณไม่ควรกำหนด supports_* method ที่กำหนดเองบน subclass ที่ไม่ได้กำหนดใน abstract class
ตอนนี้ เราเปิดเผย plugin โดยเพิ่ม entry point ใน Python package metadata ของเรา
ที่นี่ เราสมมติว่าคลาสที่เรากำหนดเปิดเผยอยู่ใน module ชื่อ my_qiskit_plugin เช่น ถูก import ในไฟล์ __init__.py ของ module my_qiskit_plugin
เราแก้ไขไฟล์ pyproject.toml, setup.cfg หรือ setup.py ของ 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',
]
}
)
เช่นเดิม ถ้าโปรเจกต์ของคุณใช้ setup.cfg หรือ setup.py แทน pyproject.toml ดู เอกสาร setuptools สำหรับวิธีปรับแต่ง line เหล่านี้สำหรับสถานการณ์ของคุณ
เพื่อตรวจสอบว่า plugin ของคุณถูก Qiskit ตรวจพบสำเร็จ ติดตั้ง plugin package ของคุณแล้วทำตามคำแนะนำที่ Transpiler plugins สำหรับการแสดงรายการ plugin ที่ติดตั้งแล้ว และตรวจสอบว่า plugin ของคุณปรากฏอยู่ในรายการ:
from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names
unitary_synthesis_plugin_names()
['aqc', 'clifford', 'default', 'gridsynth', 'sk']
ถ้า plugin ตัวอย่างของเราถูกติดตั้ง ชื่อ my_unitary_synthesis จะปรากฏในรายการนี้
เพื่อรองรับ unitary synthesis plugin ที่เปิดเผย option หลายอย่าง
plugin interface มี option สำหรับผู้ใช้เพื่อกำหนด
configuration dictionary แบบ free-form ซึ่งจะถูกส่งไปยัง method run
ผ่าน keyword argument options ถ้า plugin ของคุณมี configuration option เหล่านี้ คุณควรบันทึกเอกสารไว้อย่างชัดเจน
ตัวอย่าง: สร้าง high-level synthesis plugin
ในตัวอย่างนี้ เราจะสร้าง high-level synthesis plugin ที่ใช้ฟังก์ชัน synth_clifford_bm ในตัวเพื่อสังเคราะห์ตัวดำเนินการ Clifford
คลาส HighLevelSynthesisPlugin กำหนด interface และข้อตกลงสำหรับ high-level synthesis plugins เมธอดหลักคือ run
อาร์กิวเมนต์แบบ positional ชื่อ high_level_object คือ Operation ที่แทนออบเจกต์ "ระดับสูง" ที่ต้องการสังเคราะห์ ตัวอย่างเช่น อาจเป็น
LinearFunction หรือ
Clifford
keyword arguments ที่มีอยู่ได้แก่:
targetระบุ Backend เป้าหมาย ทำให้ plugin สามารถเข้าถึงข้อมูลเฉพาะของ Backend ได้ เช่น coupling map, ชุด Gate ที่รองรับ และอื่นๆcoupling_mapระบุเฉพาะ coupling map และใช้เฉพาะเมื่อไม่ได้ระบุtargetqubitsระบุรายการ Qubit ที่ออบเจกต์ระดับสูงนั้นทำงานอยู่ ในกรณีที่การสังเคราะห์ทำบน physical circuit ค่าNoneหมายความว่ายังไม่ได้เลือก layout และยังไม่ได้กำหนด physical Qubit ใน target หรือ coupling map ที่ operation นี้ทำงานอยู่optionsเป็น dictionary การตั้งค่าแบบอิสระสำหรับ option เฉพาะของ plugin ถ้า plugin มี configuration option เหล่านี้ควรระบุ documentation ให้ชัดเจน
เมธอด run คืนค่า QuantumCircuit
ที่แทน Circuit ที่สังเคราะห์จากออบเจกต์ระดับสูงนั้น
อนุญาตให้คืนค่า None ได้เช่นกัน ซึ่งหมายความว่า plugin ไม่สามารถสังเคราะห์ออบเจกต์ระดับสูงที่กำหนดได้
การสังเคราะห์ออบเจกต์ระดับสูงจริงๆ นั้นดำเนินการโดย
HighLevelSynthesis
Transpiler pass
นอกจากเมธอด run แล้ว ยังมี property method อีกจำนวนหนึ่งที่ต้องกำหนด
ดู HighLevelSynthesisPlugin สำหรับ documentation ของ property ที่จำเป็นทั้งหมด
มาสร้าง subclass 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
Plugin นี้สังเคราะห์ออบเจกต์ประเภท Clifford ที่มี
ไม่เกิน 3 Qubit โดยใช้เมธอด synth_clifford_bm
ตอนนี้เราเปิดเผย plugin โดยเพิ่ม entry point ในข้อมูล metadata ของ Python package
ที่นี่ เราสมมติว่าคลาสที่เรากำหนดถูกเปิดเผยในโมดูลชื่อ my_qiskit_plugin เช่น โดยการ import ในไฟล์ __init__.py ของโมดู ล my_qiskit_plugin
เราแก้ไขไฟล์ pyproject.toml, setup.cfg, หรือ setup.py ของ 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',
]
}
)
name ประกอบด้วยสองส่วนที่คั่นด้วยจุด (.):
- ชื่อประเภทของ Operation ที่ plugin สังเคราะห์ (ในกรณีนี้คือ
clifford) โปรดทราบว่า string นี้ตรงกับแอตทริบิวต์nameของคลาส Operation ไม่ใช่ชื่อของคลาสเอง - ชื่อของ plugin (ในกรณีนี้คือ
special)
เช่นเดิม ถ้าโปรเจกต์ใช้ setup.cfg หรือ setup.py แทน pyproject.toml ดู setuptools documentation สำหรับวิธีปรับ lines เหล่านี้ให้เหมาะกับสถานการณ์ของคุณ
เพื่อตรวจสอบว่า plugin ของคุณถูกตรวจพบโดย Qiskit สำเร็จ ให้ติดตั้ง package plugin แล้วทำตามคำแนะนำที่ Transpiler plugins สำหรับการแสดงรายการ plugin ที่ติดตั้ง และตรวจสอบว่า plugin ของคุณปรากฏในรายการ:
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']
ถ้า plugin ตัวอย่างของเราถูกติดตั้ง ชื่อ my_clifford_synthesis จะปรากฏในรายการนี้
- ส่ง plugin ของคุณไปยัง Qiskit Ecosystem!
- ดู tutorials สำหรับตัวอย่างการ transpile และรัน quantum circuits