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

قطع البوابات لتقليل عرض الدائرة

في هذا الدفتر، سنتناول خطوات نمط Qiskit مع استخدام قطع الدائرة لتقليل عدد الـ qubits في الدائرة. سنقطع البوابات لنتمكن من إعادة بناء قيمة التوقع لدائرة من أربعة qubits باستخدام تجارب ثنائية الـ qubit فحسب.

هذه هي الخطوات التي سنتبعها:

  • الخطوة 1: تعيين المسألة على دوائر كمومية ومؤثرات:

    • تعيين الهاميلتونيان على دائرة كمومية.
  • الخطوة 2: التحسين للأجهزة المستهدفة [يستخدم الإضافة الخاصة بالقطع]:

    • قطع الدائرة والعنصر القابل للرصد.
    • تحويل (transpile) التجارب الفرعية لتلائم الأجهزة.

  • الخطوة 3: التنفيذ على الأجهزة المستهدفة:

    • تشغيل التجارب الفرعية المستخرجة من الخطوة 2 باستخدام الأداة الأولية Sampler.
  • الخطوة 4: معالجة النتائج [يستخدم الإضافة الخاصة بالقطع]:

    • دمج نتائج الخطوة 3 لإعادة بناء قيمة التوقع للعنصر القابل للرصد المعني.

الخطوة 1: التعيين​

إنشاء دائرة للقطع​

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

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_cutting": "qiskit-addon-cutting", "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")
from qiskit.circuit.library import efficient_su2

qc = efficient_su2(4, entanglement="linear", reps=2)
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)

qc.draw("mpl", scale=0.8)

مخطط الدائرة الكمومية

تحديد عنصر قابل للرصد​

from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])

الخطوة 2: التحسين​

فصل الدائرة والعنصر القابل للرصد وفق تقسيم qubit محدد​

تتوافق كل تسمية في partition_labels مع qubit الـ circuit في الفهرس نفسه. ستُجمَّع الـ qubits التي تشترك في تسمية قسم واحدة معًا، وستُقطع البوابات غير المحلية التي تمتد على أكثر من قسم.

ملاحظة: الوسيطة observables لـ partition_problem من النوع PauliList. تُتجاهل معاملات حدود العناصر القابلة للرصد وأطوارها خلال تحليل المسألة وتنفيذ التجارب الفرعية. ويمكن إعادة تطبيقها أثناء إعادة بناء قيمة التوقع.

from qiskit_addon_cutting import partition_problem

partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=observable.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

تصور المسألة المحللة​

subobservables
{'A': PauliList(['II', 'ZI', 'ZZ', 'XI', 'ZZ', 'IX']),
'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}
subcircuits["A"].draw("mpl", scale=0.8)

مخطط الدائرة الكمومية

subcircuits["B"].draw("mpl", scale=0.8)

مخطط الدائرة الكمومية

حساب العبء الإضافي للأخذ بالعينات عند القطوع المختارة​

نقطع هنا بوابتَي CNOT، مما يُفضي إلى عبء إضافي للأخذ بالعينات مقداره 929^2.

لمزيد من التفاصيل حول العبء الإضافي الناجم عن قطع الدائرة، راجع المادة التفسيرية.

import numpy as np

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 81.0

توليد التجارب الفرعية للتشغيل على Backend​

تقبل generate_cutting_experiments الوسيطتين circuits/observables على شكل قواميس تُعيّن تسميات أقسام الـ qubit إلى الـ subcircuit/subobservables المقابلة لها.

لمحاكاة قيمة التوقع للدائرة الكاملة، تُولَّد تجارب فرعية كثيرة من التوزيع الشبه-احتمالي المشترك للبوابات المحللة، ثم تُنفَّذ على Backend واحد أو أكثر. يتحكم num_samples في عدد العينات المأخوذة من التوزيع، ويُعطى معامل مدمج واحد لكل عينة فريدة. لمزيد من المعلومات حول طريقة حساب المعاملات، راجع المادة التفسيرية.

from qiskit_addon_cutting import generate_cutting_experiments

subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)

اختيار Backend​

نستخدم هنا Backend وهميًا، مما سيُشغّل Qiskit Runtime في الوضع المحلي (أي على محاكٍ محلي).

from qiskit_ibm_runtime.fake_provider import FakeManilaV2

backend = FakeManilaV2()

إعداد التجارب الفرعية للـ Backend​

يجب نقل الدوائر عبر Transpiler مع تحديد Backend كهدف قبل إرسالها إلى Qiskit Runtime.

from qiskit.transpiler import generate_preset_pass_manager

# Transpile the subexperiments to ISA circuits
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_subexperiments = {
label: pass_manager.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}

الخطوة 3: التنفيذ​

تشغيل التجارب الفرعية باستخدام الأداة الأولية Sampler في Qiskit Runtime​

from qiskit_ibm_runtime import SamplerV2, Batch

# Submit each partition's subexperiments to the Qiskit Runtime Sampler
# primitive, in a single batch so that the jobs will run back-to-back.
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
/home/garrison/Qiskit/qiskit-ibm-runtime/qiskit_ibm_runtime/session.py:157: UserWarning: Session is not supported in local testing mode or when using a simulator.
warnings.warn(
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}

الخطوة 4: معالجة النتائج​

إعادة بناء قيمة التوقع​

إعادة بناء قيم التوقع لكل حد من حدود العنصر القابل للرصد ودمجها لإعادة بناء قيمة التوقع للعنصر القابل للرصد الأصلي.

from qiskit_addon_cutting import reconstruct_expectation_values

# Get expectation values for each observable term
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)

# Reconstruct final expectation value
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)

مقارنة قيمة التوقع المعاد بناؤها بقيمة التوقع الدقيقة من الدائرة والعنصر القابل للرصد الأصليَّين​

from qiskit_aer.primitives import EstimatorV2

estimator = EstimatorV2()
exact_expval = estimator.run([(qc, observable)]).result()[0].data.evs
print(f"Reconstructed expectation value: {np.real(np.round(reconstructed_expval, 8))}")
print(f"Exact expectation value: {np.round(exact_expval, 8)}")
print(f"Error in estimation: {np.real(np.round(reconstructed_expval-exact_expval, 8))}")
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expval-exact_expval) / exact_expval, 8))}"
)
Reconstructed expectation value: 0.6991539
Exact expectation value: 0.56254612
Error in estimation: 0.13660778
Relative error in estimation: 0.24283836