بناء الدوائر
إصدارات الحزم
تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث منها.
qiskit[all]~=2.3.0
تتناول هذه الصفحة بشكل أعمق فئة QuantumCircuit في Qiskit SDK، وتستعرض بعض الأساليب الأكثر تقدمًا التي يمكنك استخدامها لإنشاء الدوائر الكمومية.
ما هي الدائرة الكمومية؟
الدائرة الكمومية البسيطة هي مجموعة من Qubits وقائمة من التعليمات التي تعمل عليها. لتوضيح ذلك، ينشئ الكود التالي دائرة جديدة بـ Qubitين، ثم يعرض السمة qubits الخاصة بالدائرة، وهي قائمة من Qubits مرتبة من البت الأقل أهمية إلى البت الأكثر أهمية .
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
يمكن دمج كائنات QuantumRegister وClassicalRegister المتعددة لإنشاء دائرة. ويمك ن تسمية كل QuantumRegister وClassicalRegister أيضًا.
from qiskit.circuit import QuantumRegister, ClassicalRegister
qr1 = QuantumRegister(2, "qreg1") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
يمكنك معرفة فهرس Qubit وسجله باستخدام طريقة find_bit الخاصة بالدائرة وسماتها.
desired_qubit = qr2[0] # Qubit 0 of register 'qreg2'
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
إضافة تعليمة إلى الدائرة يُلحق التعليمة بسمة data الخاصة بالدائرة. يُظهر ناتج الكود التالي أن data هي قائمة من كائنات CircuitInstruction، ولكل منها سمة operation وسمة qubits.
qc.x(0) # Add X-gate to qubit 0
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
أسهل طريقة لعرض هذه المعلومات هي استخدام طريقة draw، التي تُعيد تمثيلًا مرئيًا للدائرة. راجع تصور الدوائر للاطلاع على طرق مختلفة لعرض الدوائر الكمومية.
qc.draw("mpl")
يمكن أن تحتوي كائنات تعليمات الدائرة على دوائر "تعريف" تصف التعليمة بمصطلحات تعليمات أكثر أساسية. على سبيل المثال، يُعرَّف بوابة X باعتبارها حالة خاصة من بوابة U3، وهي بوابة أكثر عمومية لـ Qubit واحد.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")
التعليمات والدوائر متشابهة في أنها تصف كلتاهما عمليات على البتات و Qubits، لكنها تخدم أغراضًا مختلفة:
- تُعامَل التعليمات على أنها ثابتة، وعادةً ما تُعيد طرقها تعليمات جديدة (دون تغيير الكائن الأصلي).
- صُمِّمت الدوائر للبناء عبر أسطر كثيرة من الكود، وكثيرًا ما تُعدِّل طرق
QuantumCircuitالكائن الموجود.
ما هو عمق الدائرة؟
عمق الدائرة الكمومية هو مقياس لعدد "طبقات" البوابات الكمومية المنفَّذة بالتوازي اللازمة لإتمام الحساب الذي تُعرِّفه الدائرة. لأن البوابات الكمومية تستغرق وقتًا في التنفيذ، يتوافق عمق الدائرة تقريبًا مع المدة الزمنية التي يحتاجها الحاسوب الكمومي لتنفيذها. لذا يُعدّ عمق الدائرة من أبرز المعايير التي تُحدِّد ما إذا كان بالإمكان تشغيل الدائرة على جهاز معين.
تُوضِّح بقية هذه الصفحة كيفية التعامل مع الدوائر الكمومية.
بناء الدوائر
تُضيف طرق مثل QuantumCircuit.h وQuantumCircuit.cx تعليمات محددة إلى الدوائر. لإضافة تعليمات إلى دائرة بشكل أعم، استخدم طريقة append. تأخذ هذه الطريقة تعليمةً وقائمةً من Qubits لتطبيق التعليمة عليها. راجع توثيق واجهة برمجة مكتبة الدوائر للاطلاع على قائمة التعليمات المدعومة.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")
لدمج دائرتين، استخدم طريقة compose. تقبل هذه الطريقة كائن QuantumCircuit آخر وقائمةً اختيارية من تعيينات Qubits.
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")
قد ترغب أيضًا في تجميع الدوائر كتعليمات للحفاظ على تنظيمها. يمكنك تحويل دائرة إلى تعليمة باستخدام طريقة to_instruction، ثم إلحاقها بدائرة أخرى كما تفعل مع أي تعليمة أخرى. الدائرة المرسومة في الكود التالي مكافئة وظيفيًا للدائرة المرسومة في الكود السابق.
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
إذا كانت دائرتك أحادية (unitary)، يمكنك تحويلها إلى Gate باستخدام طريقة to_gate. كائنات Gate هي أنواع محددة من التعليمات تمتلك ميزات إضافية، مثل طريقة control التي تُضيف تحكمًا كموميًا.
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
لرؤية ما يجري، يمكنك استخدام طريقة decompose لتوسيع كل تعليمة إلى تعريفها.
تُعيد طريقة decompose دائرةً جديدة ولا تُعدِّل الدائرة التي تعمل عليها.
qc_a.decompose().draw("mpl")
قياس Qubits
تُستخدم القياسات لأخذ عيِّنات من حالات Qubits الفردية ونقل النتائج إلى سجل كلاسيكي. لاحظ أنه إذا كنت تُرسل الدوائر إلى بدائيّة Sampler، فإن القياسات مطلوبة. أما الدوائر المرسلة إلى بدائيّة Estimator فيجب ألا تحتوي على قياسات.
يمكن قياس Qubits باستخدام ثلاث طرق: measure وmeasure_all وmeasure_active. لمعرفة كيفية تصور نتائج القياس، راجع صفحة تصور النتائج.
-
QuantumCircuit.measure: يقيس كل Qubit في المعامل الأول على البت الكلاسيكي المحدد في المعامل الثاني. تتيح هذه الطريقة تحكمًا كاملًا في مكان تخزين نتيجة القياس. -
QuantumCircuit.measure_all: لا تأخذ أي معامل ويمكن استخدامها للدوائر الكمومية التي لا تحتوي على بتات كلاسيكية مُعرَّفة مسبقًا. تُنشئ أسلاكًا كلاسيكية وتخزن نتائج القياس بالترتيب. على سبيل المثال، يُخزَّن قياس Qubit في cbit). كما تُضيف حاجزًا قبل القياس. -
QuantumCircuit.measure_active: مشابهة لـmeasure_all، لكنها تقيس فقط Qubits التي تحتوي على عمليات.
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)
الدوائر ذات المعاملات
تتضمن كثير من الخوارزميات الكمومية قصيرة المدى تنفيذ تغييرات متعددة على دائرة كمومية. بما أن بناء الدوائر الكبيرة وتحسينها قد يكون مُكلفًا حسابيًا، يدعم Qiskit الدوائر ذات المعاملات. هذه الدوائر تحتوي على معاملات غير مُعرَّفة، ولا يلزم تحديد قيمها إلا قُبيل تنفيذ الدائرة. يتيح لك ذلك نقل عملية بناء الدائرة وتحسينها خارج الحلقة الرئيسية للبرنامج. يُنشئ الكود التالي دائرة ذات معاملات ويعرضها.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")
يُنشئ الكود التالي تغييرات عديدة على هذه الدائرة ويعرض أحدها.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")
يمكنك العثور على قائمة المعاملات غير المُعرَّفة في الدائرة من خلال سمة parameters الخاصة بها.
qc.parameters
ParameterView([Parameter(angle)])
تغيير اسم المعامل
افتراضيًا، تبدأ أسماء المعاملات في الدوائر ذات المعاملات بالبادئة x- مثلًا x[0]. يمكنك تغيير الأسماء بعد تعريفها، كما هو موضح في المثال التالي.
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)
# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)
# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)
الخطوات التالية
- لتعلم الخوارزميات الكمومية قصيرة المدى، خذ دورة تصميم الخوارزميات التغايرية.
- اطلع على مثال للدوائر المستخدمة في درس خوارزمية غروفر.
- تعامل مع دوائر بسيطة باستخدام IBM Quantum Composer.