نوى كمومية باستخدام البوابات الكسرية
تقدير الاستخدام: أقل من 30 ثانية على معالج Heron r2 (ملاحظة: هذا تقدير فحسب. قد يختلف وقت التشغيل الفعلي.)
مخرجات التعلم
-
ما هي البوابات الكسرية وكيف تُقلل عمق الدائرة ومدتها على وحدات معالجة الكم QPUs من IBM®
-
القيود المرتبطة باستخدام البوابات الكسرية (على وجه الخصوص، نطاق زاوية RZZ)
-
كيفية بناء سير عمل نواة كمومية يستخدم البوابات الكسرية مع IBM Quantum Compute Service
-
كيفية مقارنة مقاييس التنفيذ على الأجهزة (العمق، المدة، عدد البوابات غير المحلية، الإخلاص) مع البوابات الكسرية وبدونها
-
كيفية استخدام بوابات RX الكسرية فقط مع الحفاظ على سير عمل أنماط Qiskit القياسي
المتطلبات المسبقة
-
سير عمل أنماط Qiskit
-
دليل البوابات الكسرية
-
البرنامج التعليمي تدريب النواة الكمومية ودرس النوى الكمومية من دورة تعلم الآلة الكمومية
الخلفية النظرية
البوابات الكسرية على وحدات المعالجة الكمومية من IBM
البوابات الكسرية هي بوابات كمومية ذات معاملات تُتيح التنفيذ المباشر للدوران بزوايا اعتباطية (ضمن حدود محددة)، مما يُلغي الحاجة إلى تحليلها إلى بوابات أساسية متعددة. من خلال استغلال التفاعلات الأصيلة بين البتات الكمومية الفيزيائية، يمكنك تطبيق وحدات unitaries معينة بكفاءة أعلى على الأجهزة.
تدعم وحدات المعالجة الكمومية IBM Quantum® Heron البوابات الكسرية التالية:
- لقيم
- لأي قيمة حقيقية
يمكن لهذه البوابات أن تُقلل بشكل ملحوظ من عمق الدوائر الكمومية ومدتها. وهي مفيدة بصفة خاصة في التطبيقات التي تعتمد بشكل كبير على و ، مثل محاكاة هاميلتوني، وخوارزمية التحسين الكمومي التقريبي (QAOA)، وطرق النواة الكمومية. في هذا البرنامج التعليمي، نركز على النواة الكمومية كمثال تطبيقي عملي.
القيود
البوابات الكسرية ميزة تجريبية في الوقت الراهن وتأتي مع بعض القيود:
- يقتصر نطاق زاوية على القيم في المجال .
- لا يُدعم استخدام البوابات الكسرية مع الدوائر الديناميكية، أو تفتيل Pauli (Pauli twirling)، أو إلغاء الأخطاء الاحتمالي (PEC)، أو استقراء الضوضاء الصفرية (ZNE) (باستخدام تضخيم الأخطاء الاحتمالي (PEA)).
تتطلب البوابات الكسرية سير عمل مختلفاً مقارنةً بالنهج المعياري. يشرح هذا البرنامج التعليمي كيفية التعامل مع البوابات الكسرية من خلال تطبيق عملي.
راجع ما يلي للمزيد من التفاصيل حول البوابات الكسرية.
نُهج سير العمل لقيد زاوية RZZ
يتبع سير العمل الخاص باستخدام البوابات الكسرية بشكل عام سير عمل أنماط Qiskit. الفارق الرئيسي هو أن جميع زوايا RZZ يجب أن تستوفي الشرط . ثمة نهجان لضمان استيفاء هذا الشرط، كما نناقش أدناه. نوصي بالنهج الثاني، وفي هذا البرنامج التعليمي، نوضحه من خلال مثال مستوحى من طريقة النواة الكمومية. لفهم أفضل لأين من المرجح أن تكون النوى الكمومية مفيدة، نوصي بقراءة Liu, Arunachalam & Temme (2021).
يمكنك أيضاً العمل على البرنامج التعليمي تدريب النواة الكمومية ودرس النوى الكمومية في دورة تعلم الآلة الكمومية على IBM Quantum® Learning.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "qiskit_basis_constructor": "qiskit-basis-constructor", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
1. توليد قيم المعاملات التي تستوفي قيد زاوية RZZ
إذا كنت متأكداً من أن جميع زوايا RZZ تقع ضمن النطاق الصحيح، فيمكنك اتباع سير عمل أنماط Qiskit المعياري. في هذه الحالة، تُمرر قيم المعاملات ببساطة كجزء من PUB. يسير سير العمل على النحو التالي.
pm = generate_preset_pass_manager(backend=backend, ...)
t_circuit = pm.run(circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit, parameter_values)])
estimator.run([(t_circuit, t_observable, parameter_values)])
إذا حاولت إرسال PUB يتضمن بوابة RZZ بزاوية خارج النطاق الصحيح، فستواجه رسالة خطأ من هذا القبيل:
'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'
لتجنب هذا الخطأ، استخدم النهج الثاني الموضح أدناه.
2. تعيين قيم المعاملات للدوائر قبل عملية التحويل
توفر حزمة qiskit-ibm-runtime مرحلة تحويل متخصصة تُسمى FoldRzzAngle.
تقوم هذه المرحلة بتحويل الدوائر الكمومية بحيث تستوفي جميع زوايا RZZ قيد زاوية RZZ.
إذا زوّدت الـ backend إلى generate_preset_pass_manager أو transpile، يُطبّق Qiskit تلقائياً FoldRzzAngle على الدوائر الكمومية.
يستلزم هذا النهج تعيين قيم المعاملات للدوائر الكمومية قبل عملية التحويل.
يسير سير العمل على النحو التالي.
pm = generate_preset_pass_manager(backend=backend, ...)
b_circuit = circuit.assign_parameters(parameter_values)
t_circuit = pm.run(b_circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit,)])
estimator.run([(t_circuit, t_observable)])
لاحظ أن سير العمل هذا يتكبد تكلفة حسابية أعلى من النهج الأول، لأنه يتضمن تعيين قيم المعاملات للدوائر الكمومية وتخزين الدوائر المُقيدة بالمعاملات محلياً.
لاحظ وجود مشكلة معروفة في qiskit-ibm-runtime v0.47.0 حيث قد تبقى بوابات RZZ ذات الزوايا غير الصالحة في الدوائر حتى بعد التحويل في سيناريوهات معينة.
انظر qiskit-ibm-runtime#2441 لتتبع التقدم في هذه المشكلة. نوصي بالحل البديل التالي حتى تُحل.
pm = generate_preset_pass_manager(backend=backend, ...)
pm.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend.target),
RemoveIdentityEquivalent(target=backend.target),
]
)
... = pm.run(...)
المتطلبات
قبل البدء في هذا البرنامج التعليمي، تأكد من تثبيت ما يلي:
- Qiskit SDK الإصدار v2.0 أو أحدث، مع دعم التصور البصري
- Qiskit Runtime الإصدار v0.41 أو أحدث (
pip install qiskit-ibm-runtime) - Qiskit Aer الإصدار v0.17 أو أحدث (
pip install qiskit-aer) - Qiskit Basis Constructor (
pip install qiskit_basis_constructor)
الإعداد
import matplotlib.pyplot as plt
import numpy as np
from qiskit import QuantumCircuit, generate_preset_pass_manager
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import UGate, n_local, unitary_overlap
from qiskit.transpiler import Target, PassManager
from qiskit.transpiler.passes import (
Optimize1qGatesDecomposition,
RemoveIdentityEquivalent,
)
from qiskit_aer.primitives import SamplerV2 as AerSampler
from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle
تفعيل البوابات الكسرية والتحقق من البوابات الأساسية
لاستخدام البوابات الكسرية، يمكنك الحصول على backend يدعمها عبر ضبط الخيار use_fractional_gates=True.
إذا كان الـ backend يدعم البوابات الكسرية، فستجد rzz و rx مُدرجتين ضمن بواباته الأساسية.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=133
) # backend should be a heron device or later
backend_name = backend.name
backend_c = service.backend(backend_name) # w/o fractional gates
backend_f = service.backend(
backend_name, use_fractional_gates=True
) # w/ fractional gates
print(f"Backend: {backend_name}")
print(f"No fractional gates: {backend_c.basis_gates}")
print(f"With fractional gates: {backend_f.basis_gates}")
if "rzz" not in backend_f.basis_gates:
print(f"Backend {backend_name} does not support fractional gates")
Backend: ibm_marrakesh
No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']
With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']
مثال محاكي صغير المقياس
في هذا القسم، نستعرض الخطوات الأربع لسير عمل أنماط Qiskit على محاكٍ، باستخدام دائرة النواة الكمومية كمثال عملي.
الخطوة 1: تعيين المدخلات الكلاسيكية إلى مسألة كمومية
دائرة النواة الكمومية
في هذا القسم، نستكشف دائرة النواة الكمومية باستخدام بوابات RZZ لتقديم سير العمل الخاص بالبوابات الكسرية.
نبدأ ببناء دائرة كمومية لحساب عناصر مصفوفة النواة بصورة فردية. يتم ذلك من خلال دمج دوائر ZZ feature map مع تداخل وحدوي (unitary overlap). تأخذ دالة النواة متجهات في فضاء الخريطة المميزة وتُعيد حاصل ضربها الداخلي كعنصر في مصفوفة النواة: حيث يمثل الحالة الكمومية المعيّنة بالخريطة المميزة.
نبني يدوياً دائرة ZZ feature map باستخدام بوابات RZZ.
على الرغم من أن Qiskit يوفر zz_feature_map مدمجة، إلا أنها لا تدعم حالياً بوابات RZZ اعتباراً من Qiskit v2.4.1 (انظر المشكلة).
بعد ذلك، نحسب دالة النواة لمدخلات متطابقة - على سبيل المثال، . على أجهزة الحوسبة الكمومية المشوشة، قد تكون هذه القيمة أقل من 1 بسبب الضوضاء. نتيجة أقرب إلى 1 تُشير إلى ضوضاء أقل في التنفيذ. في هذا البرنامج التعليمي، نُشير إلى هذه القيمة بـ الإخلاص (fidelity)، المُعرَّف بأنه
optimization_level = 2
shots = 2000
reps = 3
rng = np.random.default_rng(seed=123)
def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:
x = ParameterVector("x", num_qubits * reps)
qc = QuantumCircuit(num_qubits)
qc.h(range(num_qubits))
for k in range(reps):
K = k * num_qubits
for i in range(num_qubits):
qc.rz(x[i + K], i)
pairs = [(i, i + 1) for i in range(num_qubits - 1)]
for i, j in pairs[0::2] + pairs[1::2]:
qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)
return qc
def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:
qc = my_zz_feature_map(num_qubits, reps=reps)
inner_product = unitary_overlap(qc, qc, "x", "y", insert_barrier=True)
inner_product.measure_all()
return inner_product
def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:
return np.tile(rng.random(inner_product.num_parameters // 2), 2)
def fidelity(result) -> float:
ba = result.data.meas
return ba.get_int_counts().get(0, 0) / ba.num_shots
تُولَّد دوائر النواة الكمومية وقيم معاملاتها المقابلة لأنظمة تتراوح من 4 إلى 40 بتة كمومية، ثم يُقيَّم إخلاصها لاحقاً.
qubits = list(range(4, 12, 2))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
تُعرض دائرة البتات الكمومية الأربع في الشكل أدناه.
circuits[0].draw("mpl", fold=-1)
في سير عمل أنماط Qiskit المعياري، تُمرَّر قيم المعاملات عادةً إلى Sampler أو Estimator كجزء من PUB. غير أنه عند استخدام backend يدعم البوابات الكسرية، يجب تعيين قيم المعاملات هذه صراحةً إلى الدائرة الكمومية قبل عملية التحويل.
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
b_qc[0].draw("mpl", fold=-1)
الخطوة 2: تحسين المسألة لتنفيذها على الأجهزة الكمومية
نُحوّل بعد ذلك الدائرة باستخدام مدير المراحل وفق نمط Qiskit المعياري.
من خلال تزويد generate_preset_pass_manager بـ backend يدعم البوابات الكسرية، تُضاف تلقائياً مرحلة متخصصة تُسمى FoldRzzAngle.
تُعدّل هذه المرحلة الدائرة لتستوفي قيود زاوية RZZ.
ونتيجةً لذلك، تتحول بوابات RZZ ذات القيم السالبة في الشكل السابق إلى قيم موجبة، مع إضافة بعض بوابات X.
backend_f = service.backend(name=backend_name, use_fractional_gates=True)
# pm_f includes `FoldRzzAngle` pass
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_f
)
pm_f.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend_f.target),
RemoveIdentityEquivalent(target=backend_f.target),
]
)
t_qc_f = pm_f.run(b_qc)
print(t_qc_f[0].count_ops())
t_qc_f[0].draw("mpl", fold=-1)
OrderedDict({'rz': 35, 'rzz': 18, 'x': 13, 'rx': 9, 'measure': 4, 'barrier': 2})
لتقييم تأثير البوابات الكسرية، نقيس عدد البوابات غير المحلية (CZ و RZZ لهذا الـ backend)، إلى جانب عمق الدوائر ومدتها، ثم نقارن هذه المقاييس بتلك الخاصة بسير العمل المعياري لاحقاً.
nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]
depth_f = [qc.depth() for qc in t_qc_f]
duration_f = [
qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc_f
]
الخطوة 3: التنفيذ باستخدام Qiskit primitives
نُشغّل الدائرة المحوَّلة مع الـ backend الذي يدعم البوابات الكسرية.
sampler_f = AerSampler.from_backend(backend_f)
job = sampler_f.run(t_qc_f, shots=shots)
print(job.job_id())
085ce928-767e-4200-93bf-3905e5411cfe
الخطوة 4: المعالجة اللاحقة وإعادة النتيجة بالصيغة الكلاسيكية المطلوبة
يمكنك الحصول على قيمة دالة النواة بقياس احتمال سلسلة البتات الصفرية الكاملة 00...00 في المخرجات.
result = job.result()
fidelity_f = [fidelity(result=res) for res in result]
print(fidelity_f)
[0.929, 0.882, 0.8645, 0.817]
مقارنة سير العمل والدائرة بدون البوابات الكسرية
في هذا القسم، نعرض سير عمل أنماط Qiskit المعياري باستخدام backend لا يدعم البوابات الكسرية. بمقارنة الدوائر المحوَّلة، ستلاحظ أن النسخة التي تستخدم البوابات الكسرية (من القسم السابق) أكثر إيجازاً من النسخة التي لا تستخدمها.
# step 1: map classical inputs to quantum problem
# `circuits` and `params` from the previous section are reused here
# step 2: optimize circuits
backend_c = service.backend(backend_name) # w/o fractional gates
pm_c = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_c
)
t_qc_c = pm_c.run(circuits)
print(t_qc_c[0].count_ops())
t_qc_c[0].draw("mpl", fold=-1)
OrderedDict({'rz': 130, 'sx': 80, 'cz': 36, 'measure': 4, 'barrier': 2})
nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]
depth_c = [qc.depth() for qc in t_qc_c]
duration_c = [
qc.estimate_duration(backend_c.target, unit="u") for qc in t_qc_c
]
# step 3: execute
sampler_c = AerSampler.from_backend(backend_c)
job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)
print(job.job_id())
f2cca29d-7263-4976-9e51-13a91b75c3ae
# step 4: post-processing
result = job.result()
fidelity_c = [fidelity(res) for res in result]
print(fidelity_c)
[0.8625, 0.7605, 0.702, 0.671]
مقارنة الأعماق والمدد والإخلاص
في هذا القسم، نقارن عدد البوابات غير المحلية والإخلاص بين الدوائر مع البوابات الكسرية ودونها. يُبرز هذا الفوائد المحتملة لاستخدام البوابات الكسرية من حيث كفاءة التنفيذ وجودته.
plt.plot(qubits, depth_c, "-o", label="no fractional gates")
plt.plot(qubits, depth_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("depth")
plt.title("Comparison of depths")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x116af3cb0>
plt.plot(qubits, duration_c, "-o", label="no fractional gates")
plt.plot(qubits, duration_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("duration (µs)")
plt.title("Comparison of durations")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x11ea4f4d0>
plt.plot(qubits, nnl_c, "-o", label="no fractional gates")
plt.plot(qubits, nnl_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("number of non-local gates")
plt.title("Comparison of numbers of non-local gates")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x1247fc440>
plt.plot(qubits, fidelity_c, "-o", label="no fractional gates")
plt.plot(qubits, fidelity_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("fidelity")
plt.title("Comparison of fidelities")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x120b792b0>
مثال جهاز كبير المقياس
في هذا القسم، نُقيّم سير عمل النواة الكمومية مع البوابات الكسرية وبدونها على جهاز كمومي يصل إلى 40 كيوبت.
الخطوات 1-4 مجتمعة
يتبع سير العمل نفس بنية المثال صغير المقياس. نُحوّل جميع الدوائر مع البوابات الكسرية وبدونها، ونجمع المقاييس، ثم نُرسل الدوائر إلى جهاز كمومي حقيقي.
# -------------------------Step 1-------------------------
qubits = list(range(4, 44, 4))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
def benchmark(b_qc, backend):
# -------------------------Step 2-------------------------
pm = generate_preset_pass_manager(optimization_level, backend=backend)
if "rzz" in backend.target.operation_names:
# workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved
pm.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend.target),
RemoveIdentityEquivalent(target=backend.target),
]
)
t_qc = pm.run(b_qc)
nnl = [qc.num_nonlocal_gates() for qc in t_qc]
depth = [qc.depth() for qc in t_qc]
duration = [
qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc
]
# -------------------------Step 3-------------------------
sampler = SamplerV2(mode=backend)
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XY4"
sampler.options.dynamical_decoupling.skip_reset_qubits = True
sampler.options.environment.job_tags = ["TUT_FG"]
job = sampler.run(t_qc, shots=shots)
job_id = job.job_id()
return nnl, depth, duration, job_id
def postprocessing(job_id: str):
# -------------------------Step 4-------------------------
job = service.job(job_id)
result = job.result()
fidelities = [fidelity(result=res) for res in result]
usage = job.usage()
return fidelities, usage
backend_f = service.backend(backend_name, use_fractional_gates=True)
nnl_f, depth_f, duration_f, job_id_f = benchmark(
b_qc, backend_f
) # step 2 & 3
print("job id (w/ fractional gates):", job_id_f)
fidelity_f, usage_f = postprocessing(job_id_f) # step 4
job id (w/ fractional gates): d8uasitbh0os73eqnpig
backend_c = service.backend(backend_name, use_fractional_gates=False)
nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)
print("job id (w/o fractional gates):", job_id_c)
fidelity_c, usage_c = postprocessing(job_id_c)
job id (w/o fractional gates): d8uav3lposuc738pruug
ثم نُقارن المقاييس.
plt.plot(qubits, depth_c, "-o", label="no fractional gates")
plt.plot(qubits, depth_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("depth")
plt.title("Comparison of depths")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x12461e660>
plt.plot(qubits, duration_c, "-o", label="no fractional gates")
plt.plot(qubits, duration_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("duration (µs)")
plt.title("Comparison of durations")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x11f2ac980>
plt.plot(qubits, nnl_c, "-o", label="no fractional gates")
plt.plot(qubits, nnl_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("number of non-local gates")
plt.title("Comparison of numbers of non-local gates")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x125c91be0>
plt.plot(qubits, fidelity_c, "-o", label="no fractional gates")
plt.plot(qubits, fidelity_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("fidelity")
plt.title("Comparison of fidelities")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x11fcf6e40>
نقارن وقت استخدام وحدة المعالجة الكمومية مع البوابات الكسرية ودونها. تُظهر نتائج الخلية التالية أن أوقات استخدام وحدة المعالجة الكمومية متقاربة تقريباً.
print(f"no fractional gates: {usage_c} seconds")
print(f"fractional gates: {usage_f} seconds")
no fractional gates: 8 seconds
fractional gates: 8 seconds
موضوع متقدم: استخدام بوابات RX الكسرية فحسب
تنبع الحاجة إلى سير العمل المعدَّل عند استخدام البوابات الكسرية أساساً من القيد المفروض على زوايا بوابة RZZ. غير أنه إذا اقتصرت على استخدام بوابات RX الكسرية واستثنيت بوابات RZZ الكسرية، يمكنك الاستمرار في اتباع سير عمل أنماط Qiskit المعياري. لا يزال هذا النهج يُقدّم فوائد ملموسة، لا سيما في الدوائر التي تحتوي على عدد كبير من بوابات RX وبوابات U، وذلك بتقليل عدد البوابات الإجمالي وتحسين الأداء المحتمل. في هذا القسم، نوضح كيفية تحسين دوائرك باستخدام بوابات RX الكسرية فحسب، مع إغفال بوابات RZZ.
لدعم هذا الغرض، نوفر دالة مساعدة تُتيح لك تعطيل بوابة أساسية محددة في كائن Target. نستخدمها هنا لتعطيل بوابات RZZ.
def remove_instruction_from_target(target: Target, gate_name: str) -> Target:
new_target = Target(
description=target.description,
num_qubits=target.num_qubits,
dt=target.dt,
granularity=target.granularity,
min_length=target.min_length,
pulse_alignment=target.pulse_alignment,
acquire_alignment=target.acquire_alignment,
qubit_properties=target.qubit_properties,
concurrent_measurements=target.concurrent_measurements,
)
for name, qarg_map in target.items():
if name == gate_name:
continue
instruction = target.operation_from_name(name)
if qarg_map == {None: None}:
qarg_map = None
new_target.add_instruction(instruction, qarg_map, name=name)
return new_target
نستخدم دائرة تتكون من بوابات U و CZ و RZZ كمثال.
qc = n_local(3, "u", "cz", "linear", reps=1)
qc.rzz(1.1, 0, 1)
qc.draw("mpl")
نُحوّل أولاً الدائرة لـ backend لا يدعم البوابات الكسرية.
pm_c = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_c
)
t_qc = pm_c.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict({'rz': 23, 'sx': 16, 'cz': 4})
ثم نُحوّل الدائرة ذاتها باستخدام بوابات RX الكسرية، مع استثناء بوابات RZZ. يُفضي ذلك إلى تخفيض طفيف في إجمالي عدد البوابات، بفضل التطبيق الأكثر كفاءة لبوابات RX.
backend_f = service.backend(backend_name, use_fractional_gates=True)
target = remove_instruction_from_target(backend_f.target, "rzz")
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level,
target=target,
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict({'rz': 22, 'sx': 14, 'cz': 4, 'rx': 1})
تحسين بوابات U باستخدام بوابات RX الكسرية
في هذا القسم، نوضح كيفية تحسين بوابات U باستخدام بوابات RX الكسرية، بالبناء على الدائرة نفسها المُقدمة في القسم السابق. نُحوّل الدائرة باستخدام بوابات RX الكسرية فحسب، مع استثناء بوابات RZZ. من خلال إدخال قاعدة تحليل مخصصة، كما هو موضح فيما يلي، يمكن تقليل عدد البوابات أحادية البت الكمومي اللازمة لتطبيق بوابة U.
هذه الميزة قيد النقاش حالياً في هذه مشكلة على GitHub.
# special decomposition rule for UGate
x = ParameterVector("x", 3)
zxz = QuantumCircuit(1)
zxz.rz(x[2] - np.pi / 2, 0)
zxz.rx(x[0], 0)
zxz.rz(x[1] + np.pi / 2, 0)
DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)
بعد ذلك، نطبق المُحوّل باستخدام ترجمة constructor-beta المُوفَّرة من حزمة qiskit-basis-constructor.
ونتيجةً لذلك، يتقلص إجمالي عدد البوابات مقارنةً بعملية التحويل السابقة.
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level,
target=target,
translation_method="constructor-beta",
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict({'rz': 16, 'rx': 9, 'cz': 4})
الخطوات التالية
إذا وجدت هذا العمل مثيراً للاهتمام، فقد تكون مهتماً بالمواد التالية:
- دليل البوابات الكسرية
- متى لا يجب استخدام البوابات الكسرية
- مرجع API لتمريرة التحويل
FoldRzzAngle - البرنامج التعليمي تدريب النواة الكمومية
- درس النوى الكمومية في دورة تعلم الآلة الكمومية





