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

التغذية الراجعة الكلاسيكية وتدفق التحكم (الدوائر الديناميكية)

إصدارات الحزم

تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. ننصح باستخدام هذه الإصدارات أو ما هو أحدث منها.

qiskit[all]~=2.4.0

الدوائر الديناميكية أدوات قوية تتيح لك قياس الـ Qubits في منتصف تنفيذ دائرة كمومية ثم إجراء عمليات منطقية كلاسيكية داخل الدائرة بناءً على نتائج قياسات منتصف الدائرة. تُعرف هذه العملية أيضاً بـ التغذية الراجعة الكلاسيكية. وعلى الرغم من أننا في بداية فهم كيفية الاستفادة القصوى من الدوائر الديناميكية، فقد رصد مجتمع البحث الكمي عدداً من حالات الاستخدام، منها:

جملة if

تُستخدم جملة if لتنفيذ عمليات بشكل شرطي بناءً على قيمة بت كلاسيكي أو سجل كلاسيكي.

في المثال التالي، نطبّق بوابة هادامار على Qubit ونقيسه. إذا كانت النتيجة 1، نطبّق بوابة X على الـ Qubit مما يعيده إلى الحالة 0. ثم نقيس الـ Qubit مرة أخرى. يجب أن تكون نتيجة القياس 0 باحتمالية 100%.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister

qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
circuit = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits

circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)):
circuit.x(q0)
circuit.measure(q0, c0)
circuit.draw("mpl")

# example output counts: {'0': 1024}

Output of the previous code cell

يمكن إعطاء جملة with هدف إسناد يكون بحد ذاته مدير سياق يمكن تخزينه واستخدامه لاحقاً لإنشاء كتلة else، التي تُنفَّذ في كل مرة لا تُنفَّذ فيها محتويات كتلة if.

في المثال التالي، نُهيئ سجلات تحتوي على Qubitين وبتّين كلاسيكيين. نطبّق بوابة هادامار على الـ Qubit الأول ونقيسه. إذا كانت النتيجة 1، نطبّق بوابة هادامار على الـ Qubit الثاني؛ وإلا نطبّق بوابة X عليه. وأخيراً، نقيس الـ Qubit الثاني أيضاً.

qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits

circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q1)
with else_:
circuit.x(q1)
circuit.measure(q1, c1)

circuit.draw("mpl")

# example output counts: {'01': 260, '11': 272, '10': 492}

Output of the previous code cell

بالإضافة إلى الاشتراط على بت كلاسيكي واحد، يمكن أيضاً الاشتراط على قيمة سجل كلاسيكي مؤلف من عدة بتات.

في المثال التالي، نطبّق بوابات هادامار على Qubitين ونقيسهما. إذا كانت النتيجة 01، أي أن الـ Qubit الأول هو 1 والـ Qubit الثاني هو 0، نطبّق بوابة X على Qubit ثالث. وأخيراً، نقيس الـ Qubit الثالث. لاحظ أننا اخترنا لوضوح الكود تحديد حالة البت الكلاسيكي الثالث وهي 0 في شرط if. في رسم الدائرة، يُشار إلى الشرط بالدوائر على البتات الكلاسيكية المشروط عليها. تُشير الدائرة المصمتة إلى الاشتراط على 1، بينما تُشير الدائرة المفرغة إلى الاشتراط على 0.

qubits = QuantumRegister(3)
clbits = ClassicalRegister(3)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1, q2) = qubits
(c0, c1, c2) = clbits

circuit.h([q0, q1])
circuit.measure(q0, c0)
circuit.measure(q1, c1)
with circuit.if_test((clbits, 0b001)):
circuit.x(q2)
circuit.measure(q2, c2)

circuit.draw("mpl")

# example output counts: {'101': 269, '011': 260, '000': 252, '010': 243}

Output of the previous code cell

التعبيرات الكلاسيكية

تحتوي وحدة التعبيرات الكلاسيكية في Qiskit qiskit.circuit.classical على تمثيل استكشافي للعمليات التي تُنفَّذ في وقت التشغيل على القيم الكلاسيكية أثناء تنفيذ الدائرة. بسبب قيود الأجهزة، يُدعم حالياً شرط QuantumCircuit.if_test() فقط.

يُظهر المثال التالي كيف يمكنك استخدام حساب التكافؤ لإنشاء حالة GHZ بـ n Qubit باستخدام الدوائر الديناميكية. أولاً، أنشئ n/2n/2 زوج من أزواج Bell على الـ Qubits المتجاورة. ثم ألصق هذه الأزواج ببعضها باستخدام طبقة من بوابات CNOT بين الأزواج. بعد ذلك تقيس الـ Qubit الهدف لجميع بوابات CNOT السابقة وتُعيد تعيين كل Qubit مقيس إلى الحالة 0\vert 0 \rangle. تطبّق XX على كل موقع غير مقيس حيث يكون تكافؤ جميع البتات السابقة فردياً. وأخيراً، تُطبَّق بوابات CNOT على الـ Qubits المقيسة لاستعادة التشابك الضائع بسبب القياس.

في حساب التكافؤ، يتضمن العنصر الأول للتعبير المُنشأ رفع كائن Python mr[0] إلى عقدة Value (يُستخدم lift لتحويل الكائنات التعسفية إلى تعبيرات كلاسيكية). هذا غير ضروري لـ mr[1] والسجل الكلاسيكي التالي المحتمل، إذ أنهما مدخلات لـ expr.bit_xor، ويُجرى أي رفع ضروري تلقائياً في هذه الحالات. يمكن بناء مثل هذه التعبيرات في حلقات وهياكل أخرى.

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr

num_qubits = 8
if num_qubits % 2 or num_qubits < 4:
raise ValueError("num_qubits must be an even integer ≥ 4")
meas_qubits = list(range(2, num_qubits, 2)) # qubits to measure and reset

qr = QuantumRegister(num_qubits, "qr")
mr = ClassicalRegister(len(meas_qubits), "m")
qc = QuantumCircuit(qr, mr)

# Create local Bell pairs
qc.reset(qr)
qc.h(qr[::2])
for ctrl in range(0, num_qubits, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])

# Glue neighboring pairs
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])

# Measure boundary qubits between pairs,reset to 0
for k, q in enumerate(meas_qubits):
qc.measure(qr[q], mr[k])
qc.reset(qr[q])

# Parity-conditioned X corrections
# Each non-measured qubit gets flipped iff the parity (XOR) of all
# preceding measurement bits is 1
for tgt in range(num_qubits):
if tgt in meas_qubits: # skip measured qubits
continue
# all measurement registers whose physical qubit index < tgt
left_bits = [k for k, q in enumerate(meas_qubits) if q < tgt]
if not left_bits: # skip if list empty
continue

# build XOR-parity expression
parity = expr.lift(
mr[left_bits[0]]
) # lift the first bit to Value so it will be treated like a boolean.
for k in left_bits[1:]:
parity = expr.bit_xor(
mr[k], parity
) # calculate parity with all other bits
with qc.if_test(parity): # Add X if parity is 1
qc.x(qr[tgt])

# Re-entangle measured qubits
for ctrl in range(1, num_qubits - 1, 2):
qc.cx(qr[ctrl], qr[ctrl + 1])
qc.draw(output="mpl", style="iqp", idle_wires=False, fold=-1)

Output of the previous code cell

الخطوات التالية

توصيات