انتقل إلى المحتوى الرئيسي
هذا المشروع في مرحلة تجريبية. وجدت خطأ؟ افتح مشكلة على GitHub. لديك سؤال أو فكرة؟ اسأل في Discussions — نحب سماع ملاحظاتك!
كيف جودة الترجمة في هذه الصفحة؟

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

ملاحظة

Toshinari Itoko (21 يونيو 2024)

تحميل ملف PDF للمحاضرة الأصلية. لاحظ أن بعض مقتطفات الكود قد تصبح متقادمة لأنها صور ثابتة.

الوقت التقريبي لتشغيل هذه التجربة على وحدة المعالجة الكمومية (QPU) هو 15 ثانية.

(ملاحظة: بعض خلايا الجزء الثاني مأخوذة من دفتر الملاحظات "Qiskit Deep dive" الذي كتبه Matthew Treinish، أحد مشرفي Qiskit)

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "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")
# !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 مستوى التحسين​

يحتوي optimization_level على أربعة خيارات، من 0 إلى 3. كلما زاد مستوى التحسين، زاد الجهد الحسابي المبذول لتحسين الدارة. المستوى 0 لا يجري أي تحسين ويقوم فقط بالحد الأدنى من العمل لجعل الدارة قابلة للتشغيل على backend المحدد. المستوى 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 لخمسة كيوبتات (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 لخمسة كيوبتات (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)، وS†S^\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'