الانتشار الخلفي للمؤثرات (OBP) لتقدير قيم التوقع
تقدير الاستخدام: 16 دقيقة على معالج Eagle r3 (ملاحظة: هذا تقدير فحسب. قد يختلف وقت التشغيل الفعلي لديك.)
# Added by doQumentation — installs packages not in the Binder environment
%pip install -q qiskit-addon-obp
# This cell is hidden from users;
# it disables linting rules.
# ruff: noqa
الخلفية النظرية
الانتشار الخلفي للمؤثرات هو أسلوب يقوم على استيعاب العمليات من نهاية الدائرة الكمية في المؤثر المقاس، مما يُقلّص عمق الدائرة بشكل عام على حساب زيادة عدد الحدود في المؤثر. والهدف هو إعادة الانتشار الخلفي لأكبر قدر ممكن من الدائرة دون السماح للمؤثر بالنمو بشكل مفرط. يتوفر تطبيق قائم على Qiskit في إضافة OBP الخاصة بـ Qiskit، ويمكن الاطلاع على مزيد من التفاصيل في التوثيق المقابل مع مثال مبسّط للبدء.
لنأخذ مثالاً لدائرة يُراد فيها قياس المؤثر ، حيث هي عوامل Pauli و هي المعاملات. لنُرمز للدائرة بالوحدوية الأحادية التي يمكن تقسيمها منطقياً إلى كما هو موضح في الشكل أدناه.

يستوعب الانتشار الخلفي للمؤثرات الوحدوية في المؤثر عن طريق تطويرها على النحو . بمعنى آخر، يُنفَّذ جزء من الحساب كلاسيكياً عبر تطور المؤثر من إلى . يمكن الآن إعادة صياغة المسألة الأصلية على أنها قياس المؤثر للدائرة ذات العمق الأصغر التي وحدويتها .
تُمثَّل الوحدوية كعدد من الشرائح . وتوجد طرق متعددة لتعريف الشريحة؛ فعلى سبيل المثال في الدائرة أعلاه، يمكن اعتبار كل طبقة من بوابات وكل طبقة من بوابات شريحةً مستقلة. يشمل الانتشار الخلفي حساب كلاسيكياً. يمكن تمثيل كل شريحة على النحو ، حيث هو عامل Pauli على كيوبت و هو قيمة عددية. ومن السهل التحقق من أن:
في المثال أعلاه، إذا كان ، فإننا نحتاج إلى تنفيذ دائرتين كميتين بدلاً من واحدة لحساب قيمة التوقع. لذا، قد يزيد الانتشار الخلفي عدد الحدود في المؤثر، مما يؤدي إلى عدد أكبر من عمليات تنفيذ الدوائر. إحدى الطرق للسماح بانتشار خلفي أعمق في الدائرة مع منع نمو المؤثر بشكل مفرط هي اقتطاع الحدود ذات المعاملات الصغيرة بدلاً من إضافتها إلى المؤثر. فعلى سبيل المثال في المثال أعلاه، قد يُختار اقتطاع الحد المتضمن شريطة أن يكون صغيراً بما يكفي. يؤدي اقتطاع الحدود إلى تقليل عدد الدوائر الكمية الواجب تنفيذها، غير أن ذلك يُحدث خطأً في حساب قيمة التوقع النهائية يتناسب مع حجم معاملات الحدود المقتطعة.
يُنفّذ هذا الدليل التعليمي نمط Qiskit لمحاكاة الديناميكا الكمية لسلسلة دوران Heisenberg باستخدام qiskit-addon-obp.
المتطلبات
قبل البدء في هذا الدليل التعليمي، تأكد من تثبيت ما يلي:
- Qiskit SDK الإصدار 1.2 أو أحدث (
pip install qiskit) - Qiskit Runtime الإصدار 0.28 أو أحدث (
pip install qiskit-ibm-runtime) - إضافة OBP الخاصة بـ Qiskit (
pip install qiskit-addon-obp) - أدوات إضافية لـ Qiskit (
pip install qiskit-addon-utils)
الإعداد
import numpy as np
import matplotlib.pyplot as plt
from qiskit.primitives import StatevectorEstimator as Estimator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import CouplingMap
from qiskit.synthesis import LieTrotter
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit_addon_utils.slicing import slice_by_gate_types, combine_slices
from qiskit_addon_obp.utils.simplify import OperatorBudget
from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.truncating import setup_budget
from rustworkx.visualization import graphviz_draw
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2, EstimatorOptions
الجزء الأول: سلسلة دوران Heisenberg صغيرة الحجم
الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمية
تحويل التطور الزمني لنموذج Heisenberg الكمي إلى تجربة كمية.
توفر حزمة qiskit_addon_utils وظائف قابلة ل إعادة الاستخدام لأغراض متعددة.
يوفر وحدتها qiskit_addon_utils.problem_generators دوالَّ لتوليد هاملتونيات شبيهة بـ Heisenberg على رسم بياني لشبكة اتصال محددة. يمكن أن يكون هذا الرسم البياني إما rustworkx.PyGraph أو CouplingMap، مما يجعل استخدامه سلساً في سير عمل Qiskit.
فيما يلي، نُنشئ خريطة اقتران CouplingMap خطية مكوّنة من 10 كيوبتات.
num_qubits = 10
layout = [(i - 1, i) for i in range(1, num_qubits)]
# Instantiate a CouplingMap object
coupling_map = CouplingMap(layout)
graphviz_draw(coupling_map.graph, method="circo")
بعد ذلك، نُولّد مؤثر Pauli يُمثّل هاملتونيان Heisenberg XYZ.
حيث هو الرسم البياني لخريطة الاقتران المُعطاة.
# Get a qubit operator describing the Heisenberg XYZ model
hamiltonian = generate_xyz_hamiltonian(
coupling_map,
coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),
ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),
)
print(hamiltonian)
SparsePauliOp(['IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIIIX', 'IIIIIIIIIY', 'IIIIIIIIIZ', 'IIIIIIIIXI', 'IIIIIIIIYI', 'IIIIIIIIZI', 'IIIIIIIXII', 'IIIIIIIYII', 'IIIIIIIZII', 'IIIIIIXIII', 'IIIIIIYIII', 'IIIIIIZIII', 'IIIIIXIIII', 'IIIIIYIIII', 'IIIIIZIIII', 'IIIIXIIIII', 'IIIIYIIIII', 'IIIIZIIIII', 'IIIXIIIIII', 'IIIYIIIIII', 'IIIZIIIIII', 'IIXIIIIIII', 'IIYIIIIIII', 'IIZIIIIIII', 'IXIIIIIIII', 'IYIIIIIIII', 'IZIIIIIIII', 'XIIIIIIIII', 'YIIIIIIIII', 'ZIIIIIIIII'],
coeffs=[0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j,
0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j,
1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j,
0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j,
0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j,
1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j,
0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j,
1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j,
1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j,
0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j,
0.34906585+0.j])
انطلاقاً من مؤثر الكيوبت، يمكننا توليد دائرة كمية تُنمذج تطوره الزمني. وتُتيح وحدة qiskit_addon_utils.problem_generators دالةً مناسبة تؤدي هذا الغرض تحديداً:
circuit = generate_time_evolution_circuit(
hamiltonian,
time=0.2,
synthesis=LieTrotter(reps=2),
)
circuit.draw("mpl", style="iqp", scale=0.6)
الخطوة 2: تحسين المسألة لتنفيذها على العتاد الكمي
إنشاء شرائح الدائرة لإجراء الانتشار الخلفي
تذكّر أن دالة backpropagate ستُعيد الانتشار الخلفي لشرائح كاملة في كل مرة، لذا فإن طريقة تقسيم الدائرة إلى شرائح قد تؤثر في كفاءة الانتشار الخلفي لمسألة بعينها. هنا سنُجمّع البوابات من النوع نفسه في شرائح باستخدام دالة slice_by_gate_types.
للاطلاع على نقاش أكثر تفصيلاً حول تقسيم الدوائر إلى شرائح، راجع دليل كيفية الخاص بحزمة qiskit-addon-utils.
slices = slice_by_gate_types(circuit)
print(f"Separated the circuit into {len(slices)} slices.")
Separated the circuit into 18 slices.
تقييد الحد الأقصى لنمو المؤثر خلال الانتشار الخلفي
خلال الانتشار الخلفي، سيتجه عدد الحدود في المؤثر عموماً نحو بسرعة، حيث هو عدد الكيوبتات. عندما لا يتبادل حدّان في المؤثر التبديل على مستوى الكيوبتات، نحتاج إلى دوائر منفصلة للحصول على قيم التوقع المقابلة لكل منهما. فعلى سبيل المثال، إذا كان لدينا مؤثر يعمل على كيوبتين ، فبما أن ، يكفي قياس واحد في أساس واحد لحساب قيم التوقع لهذين الحدّين. غير أن يُضاد التبادل مع الحدّين الآخرين، لذا نحتاج إلى قياس في أساس منفصل لحساب قيمة التوقع لـ . بمعنى آخر، نحتاج إلى دائرتين بدلاً من واحدة لحساب . مع تزايد عدد الحدود في المؤثر، يرتفع احتمال زيادة العدد المطلوب من تنفيذات الدائرة أيضاً.
يمكن تحديد حد أقصى لحجم المؤثر عبر تمرير الوسيط operator_budget إلى دالة backpropagate، الذي يقبل نسخة من OperatorBudget.
للتحكم في الموارد الإضافية (الوقت) المُخصَّصة، نحدّد الحد الأقصى لعدد مجموعات Pauli المتبادلة كيوبتياً التي يُسمح للمؤثر المُعاد انتشاره الخلفي بامتلاكها. هنا نُحدّد أن الانتشار الخلفي يجب أن يتوقف حين يتجاوز عدد مجموعات Pauli المتبادلة كيوبتياً في المؤثر الحد 8.
op_budget = OperatorBudget(max_qwc_groups=8)