تحسين الدوائر الكمومية
Toshinari Itoko (21 يونيو 2024)
تحميل ملف PDF للمحاضرة الأصلية. لاحظ أن بعض مقتطفات الكود قد تصبح متقادمة لأنها صور ثابتة.
الوقت التقريبي لتشغيل هذه التجربة على وحدة المعالجة الكمومية (QPU) هو 15 ثانية.
(ملاحظة: بعض خلايا الجزء الثاني مأخوذة من دفتر الملاحظات "Qiskit Deep dive" الذي كتبه Matthew Treinish، أحد مشرفي Qiskit)
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer qiskit-ibm-runtime
# !pip install 'qiskit[visualization]'
# !pip install qiskit_ibm_runtime qiskit_aer
# !pip install jupyter
# !pip install matplotlib pylatexenc pydot pillow
import qiskit
qiskit.__version__
'2.0.2'
import qiskit_ibm_runtime
qiskit_ibm_runtime.__version__
'0.40.1'
import qiskit_aer
qiskit_aer.__version__
'0.17.1'
1. مقدمة
يتناول هذا الدرس عدة جوانب من تحسين الدوائر في الحوسبة الكمومية. تحديدًا، سنرى قيمة تحسين الدوائر باستخدام إعدادات التحسين المدمجة في Qiskit. ثم سنتعمق قليلًا ونرى ما يمكنك فعله بوصفك خبيرًا في مجال تطبيقك لبناء دوائر بطريقة ذكية. وأخيرًا، سنلقي نظرة فاحصة على ما يجري أثناء عملية الترجمة (transpilation) التي تساعدنا على تحسين دوائرنا.
2. أهمية تحسين الدوائر
نبدأ بمقارنة نتائج تشغيل دوائر تحضير حالة GHZ ذات 5 كيوبتات () مع التحسين وبدونه.
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.primitives import BackendSamplerV2 as Sampler
from qiskit_ibm_runtime.fake_provider import FakeBrisbane
backend = FakeBrisbane()
نبدأ باستخدام دائرة GHZ المركّبة بشكل ساذج كما يلي.
num_qubits = 5
ghz_circ = QuantumCircuit(num_qubits)
ghz_circ.h(0)
[ghz_circ.cx(0, i) for i in range(1, num_qubits)]
ghz_circ.measure_all()
ghz_circ.draw("mpl")
2.1 مستوى التحسين
تتوفر 4 مستويات optimization_level من 0 إلى 3. كلما ارتفع مستوى التحسين، زاد الجهد الحسابي المبذول لتحسين الدائرة. المستوى 0 لا يُجري أي تحسين وينفّذ الحد الأدنى من العمل لجعل الدائرة قابلة للتشغيل على الخلفية المختارة. المستوى 3 يبذل أقصى جهد (وعادةً أطول وقت تشغيل) في محاولة لتحسين الدائرة. المستوى 1 هو مستوى التحسين الافتراضي.
نُترجم الدائرة بدون تحسين (optimization_level=0) وبتحسين (optimization_level=2).
نلاحظ فرقًا كبيرًا في طول الدوائر المُترجمة.
pm0 = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=777
)
pm2 = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=777
)
circ0 = pm0.run(ghz_circ)
circ2 = pm2.run(ghz_circ)
print("optimization_level=0:")
display(circ0.draw("mpl", idle_wires=False, fold=-1))
print("optimization_level=2:")
display(circ2.draw("mpl", idle_wires=False, fold=-1))
optimization_level=0:

optimization_level=2:
2.2 تمرين
جرّب optimization_level=1 أيضًا وقارن الدائرة الناتجة بالاثنتين أعلاه. جرّب ذلك بتعديل الكود أعلاه.
الحل:
pm1 = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=777
)
circ1 = pm1.run(ghz_circ)
print("optimization_level=1:")
display(circ1.draw("mpl", idle_wires=False, fold=-1))
optimization_level=1:
تشغيل على خلفية وهمية (محاكاة ضوضائية). راجع الملحق 1 لمعرفة كيفية التشغيل على خلفية حقيقية.
# run the circuits on the fake backend (noisy simulator)
sampler = Sampler(backend=backend)
job = sampler.run([circ0, circ2], shots=10000)
print(f"Job ID: {job.job_id()}")
Job ID: 93a4ac70-e3ea-44ad-aea9-5045840c9076
# get results
result = job.result()
unoptimized_result = result[0].data.meas.get_counts()
optimized_result = result[1].data.meas.get_counts()
from qiskit.visualization import plot_histogram
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, unoptimized_result, optimized_result]],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"with optimization",
],
)
3. أهمية تركيب الدوائر
نقارن بعد ذلك نتائج تشغيل دائرتين مُركَّبتين بشكل مختلف لتحضير حالة GHZ ذات 5 كيوبتات ().
# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")
# A cleverly-synthesized GHZ circuit
ghz_circ2 = QuantumCircuit(5)
ghz_circ2.h(2)
ghz_circ2.cx(2, 1)
ghz_circ2.cx(2, 3)
ghz_circ2.cx(1, 0)
ghz_circ2.cx(3, 4)
ghz_circ2.measure_all()
ghz_circ2.draw("mpl")
# transpile both with the same optimization level 2
circ_org = pm2.run(ghz_circ)
circ_new = pm2.run(ghz_circ2)
print("original synthesis:")
display(circ_org.draw("mpl", idle_wires=False, fold=-1))
print("new synthesis:")
display(circ_new.draw("mpl", idle_wires=False, fold=-1))
original synthesis:
new synthesis:
التركيب الجديد ينتج دائرة أقل عمقًا. لماذا؟
السبب هو أن الدائرة الجديدة يمكن وضعها على كيوبتات متصلة خطيًا، وبالتالي على رسم بياني للاقتران الثقيل-السداسي الخاص بـ IBM® Brisbane أيضًا، بينما تتطلب الدائرة الأصلية اتصالًا نجميًا (عقدة بدرجة 4) وبالتالي لا يمكن وضعها على رسم بياني للاقتران الثقيل-السداسي الذي تكون درجة عقده 3 كحد أقصى. نتيجةً لذلك، تتطلب الدائرة الأصلية توجيه الكيوبتات مما يضيف بوابات SWAP ويزيد عدد البوابات.
ما فعلناه في الدائرة الجديدة يمكن اعتباره تركيبًا يدويًا "واعيًا بقيود الاقتران". بعبارة أخرى: حل تركيب الدائرة وتعيين الدائرة في آنٍ واحد يدويًا.
# run the circuits
sampler = Sampler(backend=backend)
job = sampler.run([circ_org, circ_new], shots=10000)
print(f"Job ID: {job.job_id()}")
Job ID: 19d635b0-4d8b-44c2-a76e-49e4b9078b1b
# get results
result = job.result()
synthesis_org_result = result[0].data.meas.get_counts()
synthesis_new_result = result[1].data.meas.get_counts()
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[
result
for result in [
sim_result,
unoptimized_result,
synthesis_org_result,
synthesis_new_result,
]
],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"synthesis_org",
"synthesis_new",
],
)
بشكل عام، يعتمد تركيب الدوائر على التطبيق وهو أمر صعب للغاية على البرامج لتغطية جميع التطبيقات الممكنة. لا يوجد في مترجم Qiskit وظائف لتركيب دائرة تحضير حالة GHZ. في مثل هذه الحالة، يستحق التركيب اليدوي للدائرة كما هو موضح أعلاه الاعتبار.
في هذا القسم، نتعمق في تفاصيل كيفية عمل مترجم Qiskit باستخدام مثال تجريبي صغير.
# Build a toy example circuit
from math import pi
import itertools
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import excitation_preserving
circuit = QuantumCircuit(4, name="Example circuit")
circuit.append(excitation_preserving(4, reps=1, flatten=True), range(4))
circuit.measure_all()
value_cycle = itertools.cycle([0, pi / 4, pi / 2, 3 * pi / 4, pi, 2 * pi])
circuit.assign_parameters(
[x[1] for x in zip(range(len(circuit.parameters)), value_cycle)], inplace=True
)
circuit.draw("mpl")
3.1 رسم تدفق الترجمة الكامل في Qiskit
نستعرض مراحل المترجم (المهام) لـ optimization_level=1.
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# There is no need to read this entire image, but this outputs all the steps in the transpile() call
# for optimization level 1
pm = generate_preset_pass_manager(1, backend, seed_transpiler=42)
pm.draw()

يتكون التدفق من ست مراحل:
print(pm.stages)
('init', 'layout', 'routing', 'translation', 'optimization', 'scheduling')
3.2 رسم مرحلة فردية
أولًا، لنرسم جميع ا لمهام (مراحل المترجم) المنجزة في مرحلة init.
pm.init.draw()

يمكننا تشغيل كل مرحلة بشكل منفصل. لنشغّل مرحلة init لدائرتنا. بتفعيل المسجّل، يمكننا رؤية تفاصيل التشغيل.
import logging
logger = logging.getLogger()
logger.setLevel("INFO")
init_out = pm.init.run(circuit)
init_out.draw("mpl", fold=-1)
INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03576 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.16618 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.07176 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.27299 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00811 (ms)
3.3 تمرين
ارسم مراحل layout وشغّل المرحلة على الدائرة الناتجة من مرحلة init (init_out)، بتعديل الخلايا المستخدمة أعلاه.
الحل:
display(pm.layout.draw())
layout_out = pm.layout.run(init_out)
layout_out.draw("mpl", idle_wires=False, fold=-1)

INFO:qiskit.passmanager.base_tasks:Pass: SetLayout - 0.01001 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: TrivialLayout - 0.07129 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: CheckMap - 0.08917 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: VF2Layout - 1.24431 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BarrierBeforeFinalMeasurements - 0.02599 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: SabreLayout - 5.11169 (ms)
افعل الشيء نفسه لمرحلة translation.
الحل:
display(pm.translation.draw())
basis_out = pm.translation.run(layout_out)
basis_out.draw("mpl", idle_wires=False, fold=-1)

INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03386 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.02718 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 2.64192 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: CheckGateDirection - 0.02217 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GateDirection - 0.36502 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.64778 (ms)

ملاحظة: لا يمكن دائمًا تشغيل كل مرحلة بشكل مستقل (إذ تحتاج بعضها إلى نقل معلومات من المرحلة السابقة).
3.4 مرحلة التحسين
المرحلة الافتراضية الأخيرة في خط الأنابيب هي التحسين. بعد أن أدرجنا الدائرة للهدف، توسعت الدائرة كثيرًا. معظم هذا التوسع يعود إلى عدم الكفاءة في علاقات التكافؤ من ترجمة الأساس وإدراج SWAP. تُستخدم مرحلة التحسين لمحاولة تقليل حجم الدائرة وعمقها. تُشغّل سلسلة من المراحل في حلقة do while حتى تصل إلى ناتج ثابت.
# pm.pre_optimization.draw()
pm.optimization.draw()

logger = logging.getLogger()
logger.setLevel("INFO")
opt_out = pm.optimization.run(basis_out)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.30112 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.03195 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.01216 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.01001 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.63729 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.41723 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.01192 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.05484 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.08583 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.20599 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00787 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00715 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.16809 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.17190 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00691 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.02408 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.04935 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00525 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00620 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00286 (ms)
opt_out.draw("mpl", idle_wires=False, fold=-1)

4. أمثلة متعمقة
4.1 تحسين كتل ثنائية الكيوبت باستخدام تركيب الوحدات الموحّدة ثنائية الكيوبت
للمستويين 2 و3، لدينا مراحل إضافية (Collect2qBlocks وConsolidateBlocks وUnitarySynthesis) لمزيد من التحسين، وهو تحسين كتل ثنائية الكيوبت. (قارن تدفق مرحلة التحسين للمستوى 2 بذلك أعلاه للمستوى 1)
يتكون تحسين الكتل ثنائي ة الكيوبت من خطوتين: جمع وتوحيد كتل الكيوبتين وتركيب المصفوفات الموحّدة ثنائية الكيوبت.
pm2 = generate_preset_pass_manager(2, backend, seed_transpiler=42)
pm2.optimization.draw()

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import (
Collect2qBlocks,
ConsolidateBlocks,
UnitarySynthesis,
)
# Collect 2q blocks and consolidate to unitary when we expect that we can reduce the 2q gate count for that unitary
consolidate_pm = PassManager(
[
Collect2qBlocks(),
ConsolidateBlocks(target=backend.target),
]
)
display(basis_out.draw("mpl", idle_wires=False, fold=-1))
consolidated = consolidate_pm.run(basis_out)
consolidated.draw("mpl", idle_wires=False, fold=-1)

# Synthesize unitaries
UnitarySynthesis(target=backend.target)(consolidated).draw(
"mpl", idle_wires=False, fold=-1
)

logger.setLevel("WARNING")
رأينا في الجزء الثاني أن تدفق المترجم الكمومي الحقيقي ليس بسيطًا وهو مؤلف من مراحل كثيرة (مهام). يعود ذلك بشكل رئيسي إلى متطلبات هندسة البرمجيات لضمان الأداء لمجموعة واسعة من دوائر التطبيقات وقابلية صيانة البرنامج. يعمل مترجم Qiskit بشكل جيد في معظم الحالات، ولكن إذا لاحظت أن دائرتك لم تُحسَّن جيدًا بواسطة مترجم Qiskit، فسيكون ذلك فرصة جيدة للبحث في تحسين الدوائر الخاصة بتطبيقك كما هو موضح في الجزء الأول. تقنية المترجم تتطور، ومساهمتك في البحث والتطوير مرحّب بها.
from qiskit.circuit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
service = QiskitRuntimeService()
backend = service.backend("ibm_brisbane")
sampler = Sampler(backend)
circ = QuantumCircuit(3)
circ.ccx(0, 1, 2)
circ.measure_all()
circ.draw("mpl")
sampler.run([circ]) # IBMInputValueError will be raised
4.2 أهمية تحسين الدوائر
نبدأ بمقارنة نتائج تشغيل دوائر تحضير حالة GHZ ذات 5 كيوبتات () مع التحسين وبدونه.
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
service = QiskitRuntimeService()
# backend = service.backend('ibm_brisbane')
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
) # Eagle
backend
نبدأ باستخدام دائرة GHZ المركّبة بشكل ساذج كما يلي.
num_qubits = 5
ghz_circ = QuantumCircuit(num_qubits)
ghz_circ.h(0)
[ghz_circ.cx(0, i) for i in range(1, num_qubits)]
ghz_circ.measure_all()
ghz_circ.draw("mpl")
نُترجم الدائرة بدون تحسين (optimization_level=0) وبتحسين (optimization_level=2).
كما ترى، هناك فرق كبير في طول الدوائر المُترجمة.
pm0 = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=777
)
pm2 = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=777
)
circ0 = pm0.run(ghz_circ)
circ2 = pm2.run(ghz_circ)
print("optimization_level=0:")
display(circ0.draw("mpl", idle_wires=False, fold=-1))
print("optimization_level=2:")
display(circ2.draw("mpl", idle_wires=False, fold=-1))
optimization_level=0:

optimization_level=2:
# run the circuits
sampler = Sampler(backend)
job = sampler.run([circ0, circ2], shots=10000)
job_id = job.job_id()
print(f"Job ID: {job_id}")
Job ID: d13rnnemya70008ek1zg
# REPLACE WITH YOUR OWN JOB IDS
job = service.job(job_id)
# get results
result = job.result()
unoptimized_result = result[0].data.meas.get_counts()
optimized_result = result[1].data.meas.get_counts()
from qiskit.visualization import plot_histogram
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, unoptimized_result, optimized_result]],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"with optimization",
],
)
4.3 أهمية تركيب الدوائر
نقارن بعد ذلك نتائج تشغيل دائرتين مُركَّبتين بشكل مختلف لتحضير حالة GHZ ذات 5 كيوبتات ().
# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")
# A better GHZ circuit (smarter synthesis), you learned in a previous lecture
ghz_circ2 = QuantumCircuit(5)
ghz_circ2.h(2)
ghz_circ2.cx(2, 1)
ghz_circ2.cx(2, 3)
ghz_circ2.cx(1, 0)
ghz_circ2.cx(3, 4)
ghz_circ2.measure_all()
ghz_circ2.draw("mpl")
circ_org = pm2.run(ghz_circ)
circ_new = pm2.run(ghz_circ2)
print("original synthesis:")
display(circ_org.draw("mpl", idle_wires=False, fold=-1))
print("new synthesis:")
display(circ_new.draw("mpl", idle_wires=False, fold=-1))
original synthesis:
new synthesis:
# run the circuits
sampler = Sampler(backend)
job = sampler.run([circ_org, circ_new], shots=10000)
job_id = job.job_id()
print(f"Job ID: {job_id}")
Job ID: d13rp283grvg008j12fg
# REPLACE WITH YOUR OWN JOB IDS
job = service.job(job_id)
# get results
result = job.result()
synthesis_org_result = result[0].data.meas.get_counts()
synthesis_new_result = result[1].data.meas.get_counts()
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, synthesis_org_result, synthesis_new_result]],
bar_labels=False,
legend=[
"ideal",
"synthesis_org",
"synthesis_new",
],
)
4.4 تحليل بوابات الكيوبت الواحد العامة
from qiskit import QuantumCircuit, transpile
from qiskit.circuit import Parameter
from qiskit.circuit.library.standard_gates import UGate
phi, theta, lam = Parameter("φ"), Parameter("θ"), Parameter("λ")
qc = QuantumCircuit(1)
qc.append(UGate(theta, phi, lam), [0])
qc.draw(output="mpl")
transpile(qc, basis_gates=["rz", "sx"]).draw(output="mpl")
4.5 تحسين كتل الكيوبت الواحد
from qiskit import QuantumCircuit
qc = QuantumCircuit(1)
qc.x(0)
qc.y(0)
qc.z(0)
qc.rx(1.23, 0)
qc.ry(1.23, 0)
qc.rz(1.23, 0)
qc.h(0)
qc.s(0)
qc.t(0)
qc.sx(0)
qc.sdg(0)
qc.tdg(0)
qc.draw(output="mpl")
from qiskit.quantum_info import Operator
Operator(qc)
Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],
[ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],
input_dims=(2,), output_dims=(2,))
from qiskit import transpile
qc_opt = transpile(qc, basis_gates=["rz", "sx"])
qc_opt.draw(output="mpl")
Operator(qc_opt)
Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],
[ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],
input_dims=(2,), output_dims=(2,))
Operator(qc).equiv(Operator(qc_opt))
True
4.6 تحليل بوابة Toffoli
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.draw(output="mpl")
from qiskit import QuantumCircuit, transpile
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc = transpile(qc, basis_gates=["rz", "sx", "cx"])
qc.draw(output="mpl")
4.7 تحليل بوابة CU
from qiskit.circuit.library.standard_gates import CUGate
phi, theta, lam, gamma = Parameter("φ"), Parameter("θ"), Parameter("λ"), Parameter("γ")
qc = QuantumCircuit(2)
# qc.cu(theta, phi, lam, gamma, 0, 1)
qc.append(CUGate(theta, phi, lam, gamma), [0, 1])
qc.draw(output="mpl")
from qiskit.circuit.library.standard_gates import CUGate
phi, theta, lam, gamma = Parameter("φ"), Parameter("θ"), Parameter("λ"), Parameter("γ")
qc = QuantumCircuit(2)
qc.append(CUGate(theta, phi, lam, gamma), [0, 1])
qc = transpile(qc, basis_gates=["rz", "sx", "cx"])
qc.draw(output="mpl")
4.8 تكافؤ CX و ECR و CZ بوابات كليفورد محلية
لاحظ أن (هادامارد)، و (دوران Z بمقدار )، و (دوران Z بمقدار )، و (باولي X) كلها بوابات كليفورد.
qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw(output="mpl", style="bw")
qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["x", "s", "h", "sdg", "ecr"]).draw(output="mpl", style="bw")
qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["h", "cz"]).draw(output="mpl", style="bw")
استخدام بوابات الأساس لكيوبت واحد من خلفية IBM: "rz" و"sx" و"x".
qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "ecr"]).draw(output="mpl", style="bw")
qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "cz"]).draw(output="mpl", style="bw")
# Check Qiskit version
import qiskit
qiskit.__version__
'2.0.2'