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

استخدام معايير Lp مختلفة لحذف حدود باولي

ملاحظة: قبل قراءة هذا الدليل، يُفضّل أن تقرأ دليل اقتطاع حدود باولي، الذي يصف اقتطاع حدود باولي ذات الوزن المنخفض المدمج في دالة backpropagate بناءً على TruncationErrorBudget محدَّدة. في هذا الدليل ستتعرف على الوسيط p_norm في دالة backpropagate، الذي يمكن استخدامه لتغيير معيار Lp المستخدم لتقدير الخطأ الناتج عن حدود باولي المقتطعة.

بناء دائرة مثال​

يستخدم هذا الدليل نفس الدائرة المثال المستخدمة في دليل اقتطاع حدود باولي:

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

_needed = {"matplotlib": "matplotlib", "qiskit": "qiskit", "qiskit_addon_obp": "qiskit-addon-obp", "qiskit_addon_utils": "qiskit-addon-utils", "rustworkx": "rustworkx"}
_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")
import rustworkx.generators
from qiskit.synthesis import LieTrotter
from qiskit_addon_utils.problem_generators import (
PauliOrderStrategy,
generate_time_evolution_circuit,
generate_xyz_hamiltonian,
)
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types

# Generate a linear chain of 10 qubits
num_qubits = 10
linear_chain = rustworkx.generators.path_graph(num_qubits)

# Use an arbitrary XY model
hamiltonian = generate_xyz_hamiltonian(
linear_chain,
coupling_constants=(0.05, 0.02, 0.0),
ext_magnetic_field=(0.02, 0.08, 0.0),
pauli_order_strategy=PauliOrderStrategy.InteractionThenColor,
)
# Evolve for some time
circuit = generate_time_evolution_circuit(
hamiltonian, synthesis=LieTrotter(reps=3), time=2.0
)
# slice the circuit by gate type
slices = slice_by_gate_types(circuit)

# For visualization purposes only, recombine the slices with barriers between them and draw the resulting circuit
combine_slices(slices, include_barriers=True).draw("mpl", fold=50, scale=0.6)

Output of the previous code cell

عرّف مرصودًا للمغنطة الكلية:

from qiskit.quantum_info import SparsePauliOp

obs = SparsePauliOp.from_sparse_list(
[("Z", [i], 1.0) for i in range(num_qubits)], num_qubits=num_qubits
)

للمقارنة، احسب القيمة المتوقعة الدقيقة:

from qiskit.primitives import StatevectorEstimator

estimator = StatevectorEstimator()
job = estimator.run([(circuit, obs)])
res = job.result()
exact_exp = res[0].data.evs
print(exact_exp)
9.318197859862146

استخدام معيار L1​

افتراضيًا، وكما رأيت سابقًا في دليل اقتطاع حدود باولي، تكون p_norm=1، أي أن الخطأ يُقدَّر كالتالي:

∣⟨ψ∣Δ∣ψ⟩∣≤∑P∈T∣cP∣|\langle\psi|\Delta|\psi\rangle| \leq \sum_{P\in\mathcal{T}} |c_P|

حيث ψ\psi هي الحالة الكمومية، وΔ\Delta هو الفرق الحقيقي بين المرصود الدقيق والمرصود المقتطع (وهو مجهول)، وT\mathcal{T} هي مجموعة حدود باولي التي اقتُطعت، وcPc_P هو معامل حد باولي. هذه المتباينة حد أعلى صارم لكنه فضفاض جدًا في معظم السيناريوهات. يقوم هذا الدليل بالانتشار العكسي لست شرائح من الدائرة المثال، باستخدام خطأ ثابت لكل شريحة قدره 0.001. يُفهم هذا الرقم على أنه الميزانية ضمن p_norm المعطاة.

from qiskit_addon_obp.utils.truncating import setup_budget

l1_truncation_error_budget = setup_budget(max_error_per_slice=0.001, p_norm=1)
print(l1_truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
from qiskit_addon_obp import backpropagate

max_slices = 6
l1_bp_obs, l1_remaining_slices, l1_metadata = backpropagate(
obs,
slices[-max_slices:],
truncation_error_budget=l1_truncation_error_budget,
)
l1_reduced_circuit = combine_slices(
slices[:-max_slices] + l1_remaining_slices
)
print(
f"Backpropagated {max_slices - len(l1_remaining_slices)} circuit slices."
)
print(
f"New observable contains {len(l1_bp_obs)} terms and {len(l1_bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 6 circuit slices.
New observable contains 116 terms and 10 commuting groups.

يمكننا الآن حساب القيمة المتوقعة للمرصود بعد الانتشار العكسي، وكذلك الخطأ بالنسبة للمرجع الدقيق:

estimator = StatevectorEstimator()
job = estimator.run([(l1_reduced_circuit, l1_bp_obs)])
res = job.result()
l1_exp = res[0].data.evs
l1_error = exact_exp - l1_exp
print(l1_exp, l1_error)
9.317869899338842 0.00032796052330397174

أخيرًا، يمكننا رسم الخطأ الناتج أثناء الانتشار العكسي لكل شريحة، وكذلك الخطأ المتراكم. الخطأ المتراكم هو مجموع أخطاء الشرائح. نلاحظ أن الخطأ المتراكم حد أعلى فضفاض جدًا للخطأ الفعلي.

from matplotlib import pyplot as plt
from qiskit_addon_obp.utils.visualization import (
plot_accumulated_error,
plot_slice_errors,
)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[1].plot([6], [l1_error], "x", color="red", label="actual error")
plot_slice_errors(l1_metadata, axes[0])
plot_accumulated_error(l1_metadata, axes[1])

Output of the previous code cell

استخدام معيار L2​

يمكن القول إن معيار L2 تقريب أفضل للخطأ الناتج من معيار L1. وذلك لأننا نستطيع افتراض أن الحالة الكمومية ∣ψ⟩|\psi\rangle مسحوبة من مجموعة عشوائية وفق قياس هار، وفي هذه الحالة يتبع الخطأ الناتج توزيعًا متوسطه صفري وتباينه يمكن تقييده تقريبًا بمعيار L2:

∣⟨ψ∣Δ∣ψ⟩∣≲(∑P∈T∣cP∣2)1/2|\langle\psi|\Delta|\psi\rangle| \lesssim \left( \sum_{P\in\mathcal{T}} |c_P|^2 \right)^{1/2}

ورغم أن هذا الحد ليس صارمًا، فلن يُنتهك إلا في حالات شاذة. نقوم مرة أخرى بالانتشار العكسي لست شرائح من الدائرة المثال، باستخدام أقصى خطأ لكل شريحة قدره 0.001 (يُفسَّر هذه المرة وفق معيار L2).

l2_truncation_error_budget = setup_budget(max_error_per_slice=0.001, p_norm=2)
print(l2_truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=2)
max_slices = 6
l2_bp_obs, l2_remaining_slices, l2_metadata = backpropagate(
obs,
slices[-max_slices:],
truncation_error_budget=l2_truncation_error_budget,
)
l2_reduced_circuit = combine_slices(
slices[:-max_slices] + l2_remaining_slices
)
print(
f"Backpropagated {max_slices - len(l2_remaining_slices)} circuit slices."
)
print(
f"New observable contains {len(l2_bp_obs)} terms and {len(l2_bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 6 circuit slices.
New observable contains 84 terms and 6 commuting groups.

مرة أخرى، نحسب القيمة المتوقعة للمرصود بعد الانتشار العكسي والخطأ بالنسبة للمرجع الدقيق:

estimator = StatevectorEstimator()
job = estimator.run([(l2_reduced_circuit, l2_bp_obs)])
res = job.result()
l2_exp = res[0].data.evs
l2_error = exact_exp - l2_exp
print(l2_exp, l2_error)
9.317829770853422 0.00036808900872387085

رسم الأخطاء الناتجة لكل شريحة والخطأ المتراكم يعطي صورة مشابهة لما سبق.

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[1].plot([6], [l2_error], "x", color="red", label="actual error")
plot_slice_errors(l2_metadata, axes[0])
plot_accumulated_error(l2_metadata, axes[1])

Output of the previous code cell

لاحظ أن الخطأ المتراكم هو مرة أخرى مجموع أخطاء الشرائح المفردة. وهذا حد فضفاض آخر بسبب متباينة مينكوفسكي، لأننا نحتاج إلى حساب هذا الحد بشكل تكراري:

∣⟨ψ∣Δi∣ψ⟩∣≤∣⟨ψ∣Δ~i−1∣ψ⟩∣+(∑P∈Ti∣cP∣2)1/2=∣⟨ψ∣Δ~i∣ψ⟩∣|\langle\psi|\Delta_{i}|\psi\rangle| \leq |\langle\psi|\tilde{\Delta}_{i-1}|\psi\rangle| + \left( \sum_{P\in\mathcal{T_i}} |c_P|^2 \right)^{1/2} = |\langle\psi|\tilde{\Delta}_{i}|\psi\rangle|

حيث يشير الرمز السفلي الجديد ii إلى تكرار الشريحة الحالية، بحيث يكون Δi\Delta_i هو الخطأ الفعلي عند تكرار الانتشار العكسي ii، وΔ~i−1\tilde{\Delta}_{i-1} هو خطأ الاقتطاع التقريبي من التكرار i−1i-1، وTi\mathcal{T}_i هي مجموعة حدود باولي المقتطعة عند التكرار ii.