ข้ามไปยังเนื้อหาหลัก

สร้าง 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:

  1. สร้าง subclass ของ abstract plugin class ที่เหมาะสม:
  2. เปิดเผยคลาสในฐานะ 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ชื่อที่สงวนไว้
Cliffordclifforddefault, ag, bm, greedy, layers, lnn
LinearFunctionlinear_functiondefault, kms, pmh
PermutationGatepermutationdefault, 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):

[project.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 ของเรา:

[project.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 และใช้เฉพาะเมื่อไม่ได้ระบุ target
  • qubits ระบุรายการ 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:

[project.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 จะปรากฏในรายการนี้

คำแนะนำ
Source: IBM Quantum docs — updated 16 มี.ค. 2569
English version on doQumentation — updated 7 พ.ค. 2569
This translation based on the English version of 11 มี.ค. 2569