דלג לתוכן הראשי

יצירת תוסף Transpiler

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

qiskit[all]~=2.3.0

יצירת תוסף Transpiler היא דרך מצוינת לשתף את קוד הטרנספילציה שלך עם קהילת Qiskit הרחבה, ולאפשר למשתמשים אחרים ליהנות מהפונקציונליות שפיתחת. תודה על עניינך בתרומה לקהילת Qiskit!

לפני שאתה יוצר תוסף Transpiler, עליך להחליט איזה סוג תוסף מתאים למצב שלך. קיימים שלושה סוגי תוספי Transpiler:

  • תוסף שלב Transpiler. בחר באפשרות זו אם אתה מגדיר pass manager שיכול להחליף אחד מ-6 השלבים של pass manager מובנה עם שלבים מוגדרים מראש.
  • תוסף סינתזת יוניטרי. בחר באפשרות זו אם קוד הטרנספילציה שלך מקבל כקלט מטריצה יוניטרית (המיוצגת כמערך Numpy) ומייצר תיאור של Circuit קוונטי המממש את אותה מטריצה יוניטרית.
  • תוסף סינתזה ברמה גבוהה. בחר באפשרות זו אם קוד הטרנספילציה שלך מקבל כקלט "אובייקט ברמה גבוהה" כגון אופרטור Clifford או פונקציה לינארית, ומייצר תיאור של Circuit קוונטי המממש את אותו אובייקט ברמה גבוהה. אובייקטים ברמה גבוהה מיוצגים על ידי תת-מחלקות של מחלקת Operation.

לאחר שקבעת איזה סוג תוסף ליצור, בצע את השלבים הבאים ליצירת התוסף:

  1. צור תת-מחלקה של מחלקת התוסף המופשטת המתאימה:
  2. חשוף את המחלקה כ-entry point של setuptools במטא-נתונים של החבילה, בדרך כלל על ידי עריכת קובץ pyproject.toml, ‏setup.cfg, או setup.py של חבילת Python שלך.

אין הגבלה על מספר התוספים שחבילה אחת יכולה להגדיר, אך לכל תוסף חייב להיות שם ייחודי. ה-Qiskit SDK עצמו כולל מספר תוספים, שגם שמותיהם שמורים. השמות השמורים הם:

  • תוספי שלב Transpiler: ראה טבלה זו.
  • תוספי סינתזת יוניטרי: default, aqc, sk
  • תוספי סינתזה ברמה גבוהה:
מחלקת Operationשם Operationשמות שמורים
Cliffordclifforddefault, ag, bm, greedy, layers, lnn
LinearFunctionlinear_functiondefault, kms, pmh
PermutationGatepermutationdefault, kms, basic, acg, token_swapper

בחלקים הבאים נציג דוגמאות לשלבים אלו עבור סוגי התוספים השונים. בדוגמאות אלו אנו מניחים שאנחנו יוצרים חבילת Python בשם my_qiskit_plugin. למידע על יצירת חבילות Python, תוכל לעיין ב-מדריך זה באתר Python.

דוגמה: יצירת תוסף שלב Transpiler

בדוגמה זו נצור תוסף שלב Transpiler עבור שלב layout (ראה שלבי Transpiler לתיאור 6 השלבים של צינור הטרנספילציה המובנה של Qiskit). התוסף שלנו פשוט מריץ את VF2Layout עם מספר ניסיונות התלוי ברמת האופטימיזציה המבוקשת.

ראשית, ניצור תת-מחלקה של PassManagerStagePlugin. קיימת שיטה אחת שעלינו לממש, הנקראת pass_manager. שיטה זו מקבלת כקלט PassManagerConfig ומחזירה את ה-pass manager שאנחנו מגדירים. האובייקט PassManagerConfig מאחסן מידע על ה-Backend המטרה, כגון מפת הצימוד ו-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

כעת נחשוף את התוסף על ידי הוספת entry point במטא-נתונים של חבילת Python שלנו. כאן אנו מניחים שהמחלקה שהגדרנו חשופה במודול בשם my_qiskit_plugin, לדוגמה על ידי ייבואה בקובץ __init__.py של מודול my_qiskit_plugin. נערוך את קובץ pyproject.toml, ‏setup.cfg, או setup.py של החבילה שלנו (בהתאם לסוג הקובץ שבחרת לאחסן את מטא-נתוני פרויקט Python שלך):

[project.entry-points."qiskit.transpiler.layout"]
"my_layout" = "my_qiskit_plugin:MyLayoutPlugin"

ראה את טבלת שלבי תוסף Transpiler לנקודות הכניסה והציפיות עבור כל שלב Transpiler.

כדי לבדוק שהתוסף שלך מזוהה בהצלחה על ידי Qiskit, התקן את חבילת התוסף שלך ועקוב אחר ההוראות ב-תוספי Transpiler לרשימת התוספים המותקנים, וודא שהתוסף שלך מופיע ברשימה:

from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins

list_stage_plugins("layout")
['default', 'dense', 'sabre', 'trivial']

אם תוסף הדוגמה שלנו היה מותקן, אז השם my_layout היה מופיע ברשימה זו.

אם ברצונך להשתמש בשלב Transpiler מובנה כנקודת מוצא לתוסף שלב Transpiler שלך, תוכל לקבל את ה-pass manager עבור שלב Transpiler מובנה באמצעות 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 המובנה להמרת Gate. כמובן, התוסף שלך יעשה משהו מעניין יותר.

המחלקה UnitarySynthesisPlugin מגדירה את הממשק והחוזה עבור תוספי סינתזת יוניטרי. השיטה העיקרית היא run, שמקבלת כקלט מערך Numpy המאחסן מטריצה יוניטרית ומחזירה DAGCircuit המייצג את ה-Circuit המסונתז מאותה מטריצה יוניטרית. בנוסף לשיטת run, ישנן מספר שיטות property שיש להגדיר. ראה 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 שמסביר את הדרישות שלך. שינויים בממשק התוסף, כגון הוספת קלטים אופציונליים נוספים, יתבצעו בצורה תואמת לאחור כדי שלא יידרשו שינויים מתוספים קיימים.

Note

כל השיטות עם הקידומת supports_ שמורות במחלקה נגזרת של UnitarySynthesisPlugin כחלק מהממשק. אין להגדיר שיטות supports_* מותאמות אישית בתת-מחלקה שאינן מוגדרות במחלקה המופשטת.

כעת נחשוף את התוסף על ידי הוספת entry point במטא-נתונים של חבילת Python שלנו. כאן אנו מניחים שהמחלקה שהגדרנו חשופה במודול בשם my_qiskit_plugin, לדוגמה על ידי ייבואה בקובץ __init__.py של מודול my_qiskit_plugin. נערוך את קובץ pyproject.toml, ‏setup.cfg, או setup.py של החבילה שלנו:

[project.entry-points."qiskit.unitary_synthesis"]
"my_unitary_synthesis" = "my_qiskit_plugin:MyUnitarySynthesisPlugin"

כמו לפני כן, אם הפרויקט שלך משתמש ב-setup.cfg או setup.py במקום pyproject.toml, ראה את תיעוד setuptools כיצד להתאים שורות אלו למצב שלך.

כדי לבדוק שהתוסף שלך מזוהה בהצלחה על ידי Qiskit, התקן את חבילת התוסף שלך ועקוב אחר ההוראות ב-תוספי Transpiler לרשימת התוספים המותקנים, וודא שהתוסף שלך מופיע ברשימה:

from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names

unitary_synthesis_plugin_names()
['aqc', 'clifford', 'default', 'gridsynth', 'sk']

אם תוסף הדוגמה שלנו היה מותקן, אז השם my_unitary_synthesis היה מופיע ברשימה זו.

כדי להתאים לתוספי סינתזת יוניטרי שחושפים אפשרויות מרובות, לממשק התוסף יש אפשרות למשתמשים לספק מילון תצורה חופשי. הוא יועבר לשיטת run דרך ארגומנט מילת המפתח options. אם לתוסף שלך יש אפשרויות תצורה אלו, עליך לתעד אותן בבירור.

דוגמה: יצירת תוסף סינתזה ברמה גבוהה

בדוגמה זו נצור תוסף סינתזה ברמה גבוהה שפשוט משתמש בפונקציה המובנית synth_clifford_bm לסינתזת אופרטור Clifford.

המחלקה HighLevelSynthesisPlugin מגדירה את הממשק והחוזה עבור תוספי סינתזה ברמה גבוהה. השיטה העיקרית היא run. הארגומנט המיקומי high_level_object הוא Operation המייצג את האובייקט "ברמה גבוהה" שיש לסנתז. לדוגמה, הוא יכול להיות LinearFunction או Clifford. ארגומנטי מילת המפתח הבאים קיימים:

  • target מציין את ה-Backend המטרה, ומאפשר לתוסף לגשת לכל המידע הספציפי למטרה, כגון מפת הצימוד, מערך ה-Gate הנתמך, וכן הלאה
  • coupling_map מציין רק את מפת הצימוד, ומשמש רק כאשר target אינו מצוין.
  • qubits מציין את רשימת ה-Qubit-ים שעליהם מוגדר האובייקט ברמה גבוהה, במקרה שהסינתזה מתבצעת על ה-Circuit הפיזי. ערך של None מציין שהפריסה טרם נבחרה וה-Qubit-ים הפיזיים ב-Backend המטרה או במפת הצימוד שעליהם פועלת פעולה זו טרם נקבעו.
  • options, מילון תצורה חופשי לאפשרויות ספציפיות לתוסף. אם לתוסף שלך יש אפשרויות תצורה אלו עליך לתעד אותן בבירור.

שיטת run מחזירה QuantumCircuit המייצג את ה-Circuit המסונתז מאותו אובייקט ברמה גבוהה. מותר גם להחזיר None, שמציין שהתוסף אינו מסוגל לסנתז את האובייקט ברמה הגבוהה שניתן. הסינתזה בפועל של אובייקטים ברמה גבוהה מתבצעת על ידי מעבר ה-Transpiler HighLevelSynthesis.

בנוסף לשיטת run, ישנן מספר שיטות property שיש להגדיר. ראה 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 שיש להם לכל היותר 3 Qubit-ים, באמצעות שיטת synth_clifford_bm.

כעת נחשוף את התוסף על ידי הוספת entry point במטא-נתונים של חבילת Python שלנו. כאן אנו מניחים שהמחלקה שהגדרנו חשופה במודול בשם my_qiskit_plugin, לדוגמה על ידי ייבואה בקובץ __init__.py של מודול my_qiskit_plugin. נערוך את קובץ pyproject.toml, ‏setup.cfg, או setup.py של החבילה שלנו:

[project.entry-points."qiskit.synthesis"]
"clifford.my_clifford_synthesis" = "my_qiskit_plugin:MyCliffordSynthesisPlugin"

ה-name מורכב משני חלקים מופרדים בנקודה (.):

  • שם סוג ה-Operation שהתוסף מסנתז (במקרה זה, clifford). שים לב שמחרוזת זו מתאימה לתכונת name של מחלקת Operation, ולא לשם המחלקה עצמה.
  • שם התוסף (במקרה זה, special).

כמו לפני כן, אם הפרויקט שלך משתמש ב-setup.cfg או setup.py במקום pyproject.toml, ראה את תיעוד setuptools כיצד להתאים שורות אלו למצב שלך.

כדי לבדוק שהתוסף שלך מזוהה בהצלחה על ידי Qiskit, התקן את חבילת התוסף שלך ועקוב אחר ההוראות ב-תוספי Transpiler לרשימת התוספים המותקנים, וודא שהתוסף שלך מופיע ברשימה:

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']

אם תוסף הדוגמה שלנו היה מותקן, אז השם my_clifford_synthesis היה מופיע ברשימה זו.

Recommendation