انتقل إلى المحتوى الرئيسي

تحسين الدوائر الكمومية

ملاحظة

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 كيوبتات (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) مع التحسين وبدونه.

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")

Output of the previous code cell

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:

Output of the previous code cell

optimization_level=2:

Output of the previous code cell

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:

Output of the previous code cell

تشغيل على خلفية وهمية (محاكاة ضوضائية). راجع الملحق 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",
],
)

Output of the previous code cell

3. أهمية تركيب الدوائر

نقارن بعد ذلك نتائج تشغيل دائرتين مُركَّبتين بشكل مختلف لتحضير حالة GHZ ذات 5 كيوبتات (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)).

# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")

Output of the previous code cell

# 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")

Output of the previous code cell

# 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:

Output of the previous code cell

new synthesis:

Output of the previous code cell

التركيب الجديد ينتج دائرة أقل عمقًا. لماذا؟

السبب هو أن الدائرة الجديدة يمكن وضعها على كيوبتات متصلة خطيًا، وبالتالي على رسم بياني للاقتران الثقيل-السداسي الخاص بـ 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",
],
)

Output of the previous code cell

بشكل عام، يعتمد تركيب الدوائر على التطبيق وهو أمر صعب للغاية على البرامج لتغطية جميع التطبيقات الممكنة. لا يوجد في مترجم 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")

Output of the previous code cell

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()

Output of the previous code cell

يتكون التدفق من ست مراحل:

print(pm.stages)
('init', 'layout', 'routing', 'translation', 'optimization', 'scheduling')

3.2 رسم مرحلة فردية

أولًا، لنرسم جميع المهام (مراحل المترجم) المنجزة في مرحلة init.

pm.init.draw()

Output of the previous code cell

يمكننا تشغيل كل مرحلة بشكل منفصل. لنشغّل مرحلة 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)

Output of the previous code cell

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)

Output of the previous code cell

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)

Output of the previous code cell

افعل الشيء نفسه لمرحلة translation.

الحل:

display(pm.translation.draw())
basis_out = pm.translation.run(layout_out)
basis_out.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

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)

Output of the previous code cell

ملاحظة: لا يمكن دائمًا تشغيل كل مرحلة بشكل مستقل (إذ تحتاج بعضها إلى نقل معلومات من المرحلة السابقة).

3.4 مرحلة التحسين

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

# pm.pre_optimization.draw()
pm.optimization.draw()

Output of the previous code cell

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)

Output of the previous code cell

4. أمثلة متعمقة

4.1 تحسين كتل ثنائية الكيوبت باستخدام تركيب الوحدات الموحّدة ثنائية الكيوبت

للمستويين 2 و3، لدينا مراحل إضافية (Collect2qBlocks وConsolidateBlocks وUnitarySynthesis) لمزيد من التحسين، وهو تحسين كتل ثنائية الكيوبت. (قارن تدفق مرحلة التحسين للمستوى 2 بذلك أعلاه للمستوى 1)

يتكون تحسين الكتل ثنائية الكيوبت من خطوتين: جمع وتوحيد كتل الكيوبتين وتركيب المصفوفات الموحّدة ثنائية الكيوبت.

pm2 = generate_preset_pass_manager(2, backend, seed_transpiler=42)
pm2.optimization.draw()

Output of the previous code cell

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)

Output of the previous code cell

Output of the previous code cell

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

Output of the previous code cell

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")

Output of the previous code cell

sampler.run([circ])  # IBMInputValueError will be raised

4.2 أهمية تحسين الدوائر

نبدأ بمقارنة نتائج تشغيل دوائر تحضير حالة GHZ ذات 5 كيوبتات (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) مع التحسين وبدونه.

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")

Output of the previous code cell

نُترجم الدائرة بدون تحسين (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:

Output of the previous code cell

optimization_level=2:

Output of the previous code cell

# 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",
],
)

Output of the previous code cell

4.3 أهمية تركيب الدوائر

نقارن بعد ذلك نتائج تشغيل دائرتين مُركَّبتين بشكل مختلف لتحضير حالة GHZ ذات 5 كيوبتات (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)).

# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")

Output of the previous code cell

# 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")

Output of the previous code cell

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:

Output of the previous code cell

new synthesis:

Output of the previous code cell

# 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",
],
)

Output of the previous code cell

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")

Output of the previous code cell

transpile(qc, basis_gates=["rz", "sx"]).draw(output="mpl")

Output of the previous code cell

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")

Output of the previous code cell

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")

Output of the previous code cell

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")

Output of the previous code cell

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")

Output of the previous code cell

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")

Output of the previous code cell

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")

Output of the previous code cell

4.8 تكافؤ CX و ECR و CZ بوابات كليفورد محلية

لاحظ أن HH (هادامارد)، وSS (دوران Z بمقدار π/2\pi/2)، وSS^\dagger (دوران Z بمقدار π/2-\pi/2)، وXX (باولي X) كلها بوابات كليفورد.

qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["x", "s", "h", "sdg", "ecr"]).draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["h", "cz"]).draw(output="mpl", style="bw")

Output of the previous code cell

استخدام بوابات الأساس لكيوبت واحد من خلفية IBM: "rz" و"sx" و"x".

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "ecr"]).draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "cz"]).draw(output="mpl", style="bw")

Output of the previous code cell

# Check Qiskit version
import qiskit

qiskit.__version__
'2.0.2'