דלג לתוכן הראשי

אי-שוויון CHSH

הערכת שימוש: שתי דקות על מעבד Heron r3 (הערה: זוהי הערכה בלבד. זמן הריצה בפועל עשוי להשתנות.)

תוצאות למידה

לאחר השלמת מדריך זה, תוכל להבין את המידע הבא:

  • כיצד לבנות מעגל CHSH עם מצב בל מפורמטר ולמדוד את ארבעת ערכי הציפייה המרכיבים את עדי CHSH.
  • כיצד לחשב ערכי ציפייה של צפיות מרובות על סריקת פרמטרים בקריאה בודדת לפרימיטיב EstimatorV2.
  • כיצד לאמת זרימת עבודה קוונטית על סימולטור מקומי רועש עם AerSimulator.from_backend לפני שליחה לחומרה.
  • כיצד לשדרג ניסוי CHSH למדד-רוחב-מכשיר לאיכות שזירה על ידי הרצת זוגות בל רבים ועצמאיים במקביל על חומרת IBM Quantum®.

דרישות מקדימות

מומלץ להכיר את הנושאים הבאים:

רקע

במדריך זה, תריץ ניסוי על מחשב קוונטי כדי להדגים את הפרת אי-שוויון CHSH עם הפרימיטיב Estimator.

אי-שוויון CHSH, הנקרא על שם Clauser, Horne, Shimony ו-Holt, משמש להוכחה ניסויית של משפט בל (1969). המשפט קובע שתיאוריות של משתנים נסתרים מקומיים אינן יכולות להסביר חלק מהתוצאות של שזירה קוונטית במכניקת הקוונטים. הפרת אי-שוויון CHSH מראה שמכניקת הקוונטים אינה תואמת לתיאוריות של משתנים נסתרים מקומיים, ניסוי שהוא יסודי להבנתנו את מכניקת הקוונטים.

פרס נובל לפיזיקה לשנת 2022 הוענק לאלן אספה, ג'ון קלאוזר ואנטון זיילינגר, בין היתר בזכות עבודתם החלוצית במדעי המידע הקוונטי, ובפרט על ניסוייהם עם פוטונים שזורים המדגימים הפרה של אי-שוויוני בל.

לניסוי זה, ניצור זוג שזור שעליו נמדוד כל Qubit בשני בסיסים שונים. נסמן את הבסיסים של ה-Qubit הראשון ב-AA ו-aa ואת הבסיסים של ה-Qubit השני ב-BB ו-bb. זה מאפשר לנו לחשב את כמות CHSH S1S_1:

S1=A(Bb)+a(B+b).S_1 = A(B-b) + a(B+b).

כל צפייה היא +1+1 או 1-1. ברור שאחד מהאיברים B±bB\pm b חייב להיות 00, והשני חייב להיות ±2\pm 2. לכן, S1=±2S_1 = \pm 2. ערך הציפייה הממוצע של S1S_1 חייב לקיים את אי-השוויון:

S12.|\langle S_1 \rangle|\leq 2.

פיתוח S1S_1 במונחי AA, aa, BB, ו-bb נותן:

S1=ABAb+aB+ab2.|\langle S_1 \rangle| = |\langle AB \rangle - \langle Ab \rangle + \langle aB \rangle + \langle ab \rangle| \leq 2.

ניתן להגדיר כמות CHSH נוספת S2S_2:

S2=A(B+b)a(Bb),S_2 = A(B+b) - a(B-b),

מה שמוביל לאי-שוויון נוסף:

S2=AB+AbaB+ab2.|\langle S_2 \rangle| = |\langle AB \rangle + \langle Ab \rangle - \langle aB \rangle + \langle ab \rangle| \leq 2.

אם מכניקת הקוונטים ניתנת לתיאור על ידי תיאוריות של משתנים נסתרים מקומיים, אי-השוויונות הללו יתקיימו תמיד. כפי שמוכח במדריך זה, ניתן להפר אותם על מחשב קוונטי, ולכן מכניקת הקוונטים אינה תואמת לתיאוריות של משתנים נסתרים מקומיים.

ניצור את הזוג השזור על ידי הכנת מצב בל Φ+=00+112|\Phi^+\rangle = \frac{|00\rangle + |11\rangle}{\sqrt{2}}. באמצעות הפרימיטיב Estimator, נקבל ישירות את ערכי הציפייה AB,Ab,aB\langle AB \rangle, \langle Ab \rangle, \langle aB \rangle ו-ab\langle ab \rangle, מבלי לשחזר אותם מספירות גולמיות. נמדוד את ה-Qubit השני בבסיסי ZZ ו-XX. ה-Qubit הראשון יימדד אף הוא בבסיסים אורתוגונליים, אך עם זווית סיבוב θ\theta שנסרוק בין 00 ל-2π2\pi. הפרימיטיב Estimator מעריך סריקת פרמטרים זו בבלוק מאוחד יחיד (PUB).

דרישות

לפני תחילת מדריך זה, ודא שהדברים הבאים מותקנים:

  • Qiskit SDK גרסה v2.0 ומעלה, עם תמיכה ב-visualization
  • Qiskit Runtime גרסה v0.40 ומעלה (pip install qiskit-ibm-runtime)
  • Qiskit Aer גרסה v0.17 ומעלה (pip install qiskit-aer)

הגדרה

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
# General
import numpy as np

# Qiskit imports
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

# Qiskit Runtime imports
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Qiskit Aer for local noisy simulation
from qiskit_aer import AerSimulator

# Plotting routines
import matplotlib.pyplot as plt
import matplotlib.ticker as tck
# Select an IBM Quantum backend.
service = QiskitRuntimeService()
backend = service.least_busy(
min_num_qubits=127, operational=True, simulator=False
)
backend.name
'ibm_pittsburgh'

דוגמה בסימולטור בקנה מידה קטן

לפני שליחת משימת חומרה, נאמת את זרימת העבודה כולה על סימולטור מקומי רועש. נשתמש ב-AerSimulator.from_backend(backend) כדי לבנות סימולטור שיורש את מודל הרעש ומפת הקישוריות של ה-Backend שבחרת, כך שתגובת הסימולטור דומה באופן איכותני למה שנצפה מהחומרה.

שלב 1: מיפוי קלטים קלאסיים לבעיה קוונטית

נכתוב את מעגל ה-CHSH עם פרמטר יחיד θ\theta, שסורק את בסיס המדידה של ה-Qubit הראשון. הפרימיטיב Estimator מפשט את הניתוח: הוא מחזיר ערכי ציפייה של צפיות ישירות, ויכול להעריך מעגל מפורמטר בערכי פרמטרים רבים בקריאה בודדת.

theta = Parameter(r"$\theta$")

chsh_circuit = QuantumCircuit(2)
chsh_circuit.h(0)
chsh_circuit.cx(0, 1)
chsh_circuit.ry(theta, 0)
chsh_circuit.draw(output="mpl", idle_wires=False, style="iqp")

Output of the previous code cell

לאחר מכן, ניצור רשימה של 21 ערכי פאזה מ-00 עד 2π2\pi שבה נעריך את המעגל המפורמטר (00, 0.1π0.1\pi, 0.2π0.2\pi, ..., 1.9π1.9\pi, 2π2\pi).

number_of_phases = 21
phases = np.linspace(0, 2 * np.pi, number_of_phases)
# Phases need to be expressed as a list of lists for the Estimator PUB
individual_phases = [[ph] for ph in phases]

לבסוף, נגדיר את הצפיות. ה-Qubit הראשון נמדד לאורך צירים המסובבים ב-θ\theta; ה-Qubit השני נמדד ב-ZZ ו-XX. עם בחירות אלה, ארבעת מתאמי CHSH ממופים לאופרטורי פאולי ZZZZ, ZXZX, XZXZ ו-XXXX:

S1=ZZZX+XZ+XX,\langle S_1 \rangle = \langle ZZ \rangle - \langle ZX \rangle + \langle XZ \rangle + \langle XX \rangle, S2=ZZ+ZXXZ+XX.\langle S_2 \rangle = \langle ZZ \rangle + \langle ZX \rangle - \langle XZ \rangle + \langle XX \rangle.
# <S_1> = <ZZ> - <ZX> + <XZ> + <XX>
observable1 = SparsePauliOp.from_list(
[("ZZ", 1), ("ZX", -1), ("XZ", 1), ("XX", 1)]
)

# <S_2> = <ZZ> + <ZX> - <XZ> + <XX>
observable2 = SparsePauliOp.from_list(
[("ZZ", 1), ("ZX", 1), ("XZ", -1), ("XX", 1)]
)

שלב 2: אופטימיזציה של הבעיה לביצוע על חומרה קוונטית

פרימיטיבים מגרסה V2 מקבלים רק מעגלים וצפיות התואמות להוראות ולקישוריות הנתמכות על ידי המערכת היעד (ארכיטקטורת קבוצת הוראות — ISA, מעגלים וצפיות). נבנה את ה-AerSimulator מה-Backend ונבצע טרנספיל כנגד יעד הסימולטור כדי שאותו מנהל מעברים יופעל מקצה לקצה.

# Build a noisy simulator from the ibm_pittsburgh backend
aer_sim = AerSimulator.from_backend(backend)

pm = generate_preset_pass_manager(target=aer_sim.target, optimization_level=3)
chsh_isa_circuit = pm.run(chsh_circuit)
chsh_isa_circuit.draw(output="mpl", idle_wires=False, style="iqp")

Output of the previous code cell

נבצע גם טרנספורמציה של הצפיות כדי להתאים אותן לפריסת ה-Qubit של ה-Circuit המטורנספל באמצעות SparsePauliOp.apply_layout.

isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)
isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)

שלב 3: ביצוע באמצעות פרימיטיבים של Qiskit

הרץ את סריקת הפרמטרים עם EstimatorV2 במצב aer_sim. שיטת run() של Estimator מקבלת אוסף של PUBs. לכל PUB יש את הפורמט (circuit, observables, parameter_values, precision). נעביר את שתי הצפיות יחד כדי שהן ישתפו את אותה סריקת פרמטרים.

# Use the AerSimulator-backed Estimator to validate the workflow locally
estimator_sim = Estimator(mode=aer_sim)

pub = (
chsh_isa_circuit, # ISA circuit
[[isa_observable1], [isa_observable2]], # ISA observables
individual_phases, # Parameter values
)

sim_result = estimator_sim.run(pubs=[pub]).result()

שלב 4: עיבוד לאחר-מדידה והצגת תוצאה בפורמט קלאסי

ה-Estimator מחזיר ערכי ציפייה עבור שתי הצפיות. נציג אותם כנגד θ\theta יחד עם הגבול הקלאסי (±2\pm 2) וגבול Tsirelson (±22\pm 2\sqrt{2}). האזורים האפורים המוצללים מסמנים את הפער בין השניים. נקודות הנמצאות בתוך הרצועות הללו מפרות את אי-שוויון CHSH.

chsh1_sim = sim_result[0].data.evs[0]
chsh2_sim = sim_result[0].data.evs[1]

def plot_chsh(phases, chsh1, chsh2, title):
fig, ax = plt.subplots(figsize=(10, 6))

ax.plot(
phases / np.pi, chsh1, "o-", label=r"$\langle S_1 \rangle$", zorder=3
)
ax.plot(
phases / np.pi, chsh2, "o-", label=r"$\langle S_2 \rangle$", zorder=3
)

# classical bound +-2
ax.axhline(y=2, color="0.9", linestyle="--")
ax.axhline(y=-2, color="0.9", linestyle="--")

# quantum bound, +-2*sqrt(2)
ax.axhline(y=np.sqrt(2) * 2, color="0.9", linestyle="-.")
ax.axhline(y=-np.sqrt(2) * 2, color="0.9", linestyle="-.")
ax.fill_between(phases / np.pi, 2, 2 * np.sqrt(2), color="0.6", alpha=0.7)
ax.fill_between(
phases / np.pi, -2, -2 * np.sqrt(2), color="0.6", alpha=0.7
)

ax.xaxis.set_major_formatter(tck.FormatStrFormatter("%g $\\pi$"))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=0.5))

ax.set_xlabel(r"$\theta$")
ax.set_ylabel("CHSH witness")
ax.set_title(title)
ax.legend()
plt.show()

plot_chsh(
phases,
chsh1_sim,
chsh2_sim,
"CHSH witnesses from AerSimulator (ibm_pittsburgh noise model)",
)

Output of the previous code cell

עדי ה-CHSH של הסימולטור כבר חורגים מהגבול הקלאסי ±2\pm 2 בכמה ערכי θ\theta, אפילו עם מודל הרעש של ה-Backend. הפסגות נמצאות מעט מתחת לגבול Tsirelson ±22\pm 2\sqrt{2} בשל רעש המכשיר המדומה. עם אימות זרימת העבודה, נמשיך לחומרה האמיתית.

דוגמה בחומרה בקנה מידה גדול

בדיקת CHSH היא מהותה ניסוי דו-קיוביטי, לכן היא אינה מתרחבת על ידי הגדלת Circuit אחד. במקום זאת, היא מתרחבת על ידי הרצת בדיקות רבות במקביל. כאן נרצף את ה-Backend בכמה שיותר זוגות בל נפרדים שמאפשרת הקישוריות שלו (התאמה של מפת הקישוריות) ונריץ Circuit-משנה CHSH עצמאי על כל זוג, הכל במשימה אחת.

זה הופך את ה-CHSH למדד-רוחב-מכשיר לאיכות שזירה: במקום זוג יחיד שנבחר ידנית, נבדוק את השזירה על פני חלק גדול מהשבב בבת אחת, בתנאים ריאליסטיים שבהם כל זוג מתחרה עם דליפת צלבים ושגיאות שערים מקבילים של שכניו. הפרת אי-השוויון על כל זוג בו-זמנית מאשרת שיש שזירה אמיתית בכל מקום על המכשיר.

# -------------------------Step 1: Map classical inputs to a quantum problem-------------------------
# A CHSH test is bipartite, so we scale up by running one independent CHSH
# experiment on every disjoint Bell pair the device can host. A greedy
# matching of the coupling map gives a set of edges that share no qubits.
num_qubits = backend.num_qubits
used = set()
pairs = []
for qa, qb in backend.coupling_map.get_edges():
if qa not in used and qb not in used:
pairs.append((qa, qb))
used.update((qa, qb))
num_pairs = len(pairs)
print(
f"Tiling {backend.name} with {num_pairs} parallel Bell pairs "
f"({2 * num_pairs} of {num_qubits} qubits)"
)

# One parameterized CHSH sub-circuit per pair, all sharing the angle theta
theta = Parameter(r"$\theta$")
chsh_circuit = QuantumCircuit(num_qubits)
for qa, qb in pairs:
chsh_circuit.h(qa)
chsh_circuit.cx(qa, qb)
chsh_circuit.ry(theta, qa)

# Embed the two CHSH observables onto each pair's qubits (identity elsewhere)
obs1 = SparsePauliOp.from_list([("ZZ", 1), ("ZX", -1), ("XZ", 1), ("XX", 1)])
obs2 = SparsePauliOp.from_list([("ZZ", 1), ("ZX", 1), ("XZ", -1), ("XX", 1)])
observables = []
for qa, qb in pairs:
observables.append([obs1.apply_layout([qa, qb], num_qubits)])
observables.append([obs2.apply_layout([qa, qb], num_qubits)])

number_of_phases = 21
phases = np.linspace(0, 2 * np.pi, number_of_phases)
individual_phases = [[ph] for ph in phases]

# -------------------------Step 2: Optimize problem for quantum hardware execution-------------------------
pm = generate_preset_pass_manager(target=backend.target, optimization_level=3)
chsh_isa_circuit = pm.run(chsh_circuit)
isa_observables = [
[o[0].apply_layout(chsh_isa_circuit.layout)] for o in observables
]

# -------------------------Step 3: Execute using Qiskit primitives-------------------------
estimator_hw = Estimator(mode=backend)
estimator_hw.options.environment.job_tags = ["TUT_CI"]

pub = (chsh_isa_circuit, isa_observables, individual_phases)
job = estimator_hw.run(pubs=[pub])
print(f"Job ID: {job.job_id()}")
hw_result = job.result()

# -------------------------Step 4: Post-process and return result in desired classical format-------------------------
# evs has shape (2 * num_pairs, number_of_phases); rows alternate S1, S2
evs = np.asarray(hw_result[0].data.evs)
chsh1_all = evs[0::2]
chsh2_all = evs[1::2]

# A pair "violates" CHSH if its strongest witness exceeds the classical bound
peak = np.maximum(
np.abs(chsh1_all).max(axis=1), np.abs(chsh2_all).max(axis=1)
)
n_violate = int(np.sum(peak > 2))
print(
f"{n_violate}/{num_pairs} Bell pairs violated the CHSH inequality "
f"(mean peak witness {peak.mean():.2f}, classical bound 2)"
)

fig, ax = plt.subplots(figsize=(10, 6))

# Faint individual per-pair curves
for row in chsh1_all:
ax.plot(phases / np.pi, row, color="#1f77b4", alpha=0.2, lw=1)
for row in chsh2_all:
ax.plot(phases / np.pi, row, color="#ff7f0e", alpha=0.2, lw=1)

# Bold mean curves across all pairs
ax.plot(
phases / np.pi,
chsh1_all.mean(axis=0),
color="#1f77b4",
lw=2.5,
label=r"$\langle S_1 \rangle$ (mean)",
)
ax.plot(
phases / np.pi,
chsh2_all.mean(axis=0),
color="#ff7f0e",
lw=2.5,
label=r"$\langle S_2 \rangle$ (mean)",
)

# classical bound +-2 and Tsirelson bound +-2*sqrt(2)
ax.axhline(y=2, color="0.9", linestyle="--")
ax.axhline(y=-2, color="0.9", linestyle="--")
ax.axhline(y=np.sqrt(2) * 2, color="0.9", linestyle="-.")
ax.axhline(y=-np.sqrt(2) * 2, color="0.9", linestyle="-.")
ax.fill_between(phases / np.pi, 2, 2 * np.sqrt(2), color="0.6", alpha=0.7)
ax.fill_between(phases / np.pi, -2, -2 * np.sqrt(2), color="0.6", alpha=0.7)

ax.xaxis.set_major_formatter(tck.FormatStrFormatter("%g $\\pi$"))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=0.5))
ax.set_xlabel(r"$\theta$")
ax.set_ylabel("CHSH witness")
ax.set_title(
f"CHSH witnesses for {num_pairs} parallel Bell pairs on {backend.name}"
)
ax.legend()
plt.show()
Tiling ibm_pittsburgh with 64 parallel Bell pairs (128 of 156 qubits)
Job ID: d86efd5g7okc73el0rp0
63/64 Bell pairs violated the CHSH inequality (mean peak witness 2.75, classical bound 2)

Output of the previous code cell

הקווים העמומים הם זוגות הבל הבודדים והקווים המודגשים הם הממוצע שלהם על פני המכשיר. כל זוג עוקב אחר אותו גל סינוס שמכניקת הקוונטים מנבאת, והפיזור בין הקווים העמומים משקף את השונות ברעש מזוג לזוג. בכל מקום שבו קו נכנס לרצועות האפורות, הוא חצה את הגבול הקלאסי ±2\pm 2, והסיכום המודפס מאשר שכמעט כל זוג מפר את אי-שוויון CHSH בו-זמנית.

הפסגות נמצאות מתחת לגבול Tsirelson ±22\pm 2\sqrt{2} בשל רעש המכשיר, אך המסקנה חד-משמעית: ה-Backend שומר על שזירה אמיתית על פני השבב כולו בו-זמנית, ולא רק על זוג יחיד שנבחר ידנית. זה המובן שבו ניסוי ה-CHSH "מתרחב": לא כ-Circuit גדול יותר, אלא כמדד מקביל שמאשר שזירה בכל מקום בבת אחת.

השלבים הבאים

המלצות

אם מצאת עבודה זו מעניינת, ייתכן שתתעניין בחומר הבא: