Nerovnost CHSH
Odhadovaná spotřeba: dvě minuty na procesoru Heron r3 (POZNÁMKA: Jde pouze o odhad. Skutečná doba výpočtu se může lišit.)
Cíle výuky
Po dokončení tohoto tutoriálu bys měl/a rozumět následujícímu:
- Jak sestavit parametrizovaný CHSH Circuit s Bellovým stavem a změřit čtyři střední hodnoty, jež tvoří svědky CHSH.
- Jak vypočítat střední hodnoty více observabl při prohledávání parametrů v jediném volání primitivy
EstimatorV2. - Jak ověřit kvantový pracovní postup na zašuměném lokálním simulátoru pomocí
AerSimulator.from_backendpřed odesláním na hardware. - Jak rozšířit CHSH experiment na celopřístrojový benchmark provázanosti spouštěním mnoha nezávislých Bellových párů paralelně na hardware IBM Quantum®.
Předpoklady
Doporučujeme seznámit se s těmito tématy:
- Provázanost v praxi, lekce kurzu o Bellových stavech a hře CHSH.
SparsePauliOpa úvod do primitiv Qiskit.
Pozadí
V tomto tutoriálu spustíš experiment na kvantovém počítači a demonstruješ porušení nerovnosti CHSH pomocí primitivy Estimator.
Nerovnost CHSH, pojmenovaná po autorech Clauserovi, Hornovi, Shimonym a Holtovi, slouží k experimentálnímu důkazu Bellova teorému (1969). Tento teorém tvrdí, že teorie lokálních skrytých proměnných nemohou vysvětlit některé důsledky provázanosti v kvantové mechanice. Porušení nerovnosti CHSH se používá k prokázání toho, že kvantová mechanika je neslučitelná s teoriemi lokálních skrytých proměnných. Jde o základní experiment pro pochopení kvantové mechaniky.
Nobelova cena za fyziku za rok 2022 byla udělena Alainu Aspectovi, Johnu Clauserovi a Antonu Zeilingerovi mimo jiné za jejich průkopnickou práci v oblasti kvantové informační vědy, a zejména za jejich experimenty s provázanými fotony demonstrující porušení Bellových nerovností.
Pro tento experiment vytvoříme provázaný pár, na němž změříme každý qubit ve dvou různých bázích. Báze pro první Qubit označíme a a báze pro druhý Qubit a . To nám umožní vypočítat veličinu CHSH :
Každá observabla nabývá hodnoty nebo . Je zřejmé, že jeden z členů musí být a druhý . Proto . Střední hodnota musí splňovat nerovnost:
Rozvinutím do členů , , a dostaneme:
Lze definovat další veličinu CHSH :
z toho plyne další nerovnost:
Pokud by kvantová mechanika mohla být popsána teoriemi lokálních skrytých proměnných, tyto nerovnosti by musely vždy platit. Jak je ukázáno v tomto tutoriálu, mohou být na kvantovém počítači porušeny, a kvantová mechanika tedy není slučitelná s teoriemi lokálních skrytých proměnných.
Provázaný pár vytvoříme přípravou Bellova stavu . Pomocí primitivy Estimator získáme střední hodnoty a přímo, bez rekonstrukce z jednotlivých naměřených výsledků. Druhý Qubit měříme v bázích a . První Qubit je měřen v ortogonálních bázích také, ale s úhlem natočení , který přelaďujeme od do . Primitiva Estimator vyhodnotí toto prohledávání parametrů v jediném primitive unified bloc (PUB).
Požadavky
Před zahájením tohoto tutoriálu se ujisti, že máš nainstalováno následující:
- Qiskit SDK v2.0 nebo novější, s podporou vizualizace
- Qiskit Runtime v0.40 nebo novější (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 nebo novější (
pip install qiskit-aer)
Nastavení
# 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'
Příklad na malém simulátoru
Před odesláním úlohy na hardware ověříme celý pracovní postup na lokálním zašuměném simulátoru. Pomocí AerSimulator.from_backend(backend) sestavíme simulátor, který přejímá šumový model a mapu propojení zvoleného backendu, takže odezva simulátoru je kvalitativně podobná tomu, co očekáváme od hardware.
Krok 1: Mapování klasických vstupů na kvantový problém
Zapíšeme CHSH Circuit s jediným parametrem , který přelaďuje měřicí bázi prvního Qubitu. Primitiva Estimator zjednodušuje analýzu: vrací střední hodnoty observabl přímo a dokáže vyhodnotit parametrizovaný Circuit při mnoha hodnotách parametrů v jediném volání.
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")
Dále vytvoříme seznam 21 hodnot fáze od do , při nichž vyhodnotíme parametrizovaný Circuit (, , , ..., , ).
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]
Nakonec definujeme observably. První Qubit je měřen podél os otočených o ; druhý Qubit je měřen v a . S těmito volbami se čtyři CHSH korelátory zobrazí na Pauliho operátory , , a :
# <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)]
)
Krok 2: Optimalizace problému pro spuštění na kvantovém hardware
Primitivy V2 přijímají pouze Circuity a observably, které odpovídají instrukcím a propojení podporovanému cílovým systémem (ISA — instruction set architecture, Circuity a observably). Sestavíme AerSimulator z backendu a transpilujeme vůči cíli simulátoru, čímž procvičíme celý průchod manažerem pasů od začátku do konce.
# 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")
Dále transformujeme observably tak, aby odpovídaly rozložení Qubitů transpilovaného Circuitu, pomocí SparsePauliOp.apply_layout.
isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)
isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)
Krok 3: Spuštění pomocí primitiv Qiskit
Spustíme prohledávání parametrů pomocí EstimatorV2 v režimu aer_sim. Metoda run() Estimatoru přijímá iterovatelnou kolekci PUBů. Každý PUB má formát (circuit, observables, parameter_values, precision). Předáme obě observably společně, aby sdílely stejné prohledávání parametrů.
# 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()
Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu
Estimator vrátí střední hodnoty pro obě observably. Vyneseme je do grafu v závislosti na společně s klasickou mezí () a Tsirelsonovou mezí (). Šedé oblasti vymezují mezeru mezi oběma. Body, které leží uvnitř těchto pásem, porušují nerovnost 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)",
)
Svědci CHSH simulátoru již při několika hodnotách překračují klasickou mez , a to i se šumovým modelem backendu. Vrcholy těsně nedosahují Tsirelsonovy meze kvůli simulovanému šumu zařízení. Po ověření pracovního postupu přejdeme na skutečný hardware.
Příklad na velkém hardware
Test CHSH je ze své podstaty dvoQubitový experiment, takže se nerozšiřuje tím, že by byl jeden Circuit větší. Místo toho se rozšiřuje spouštěním mnoha testů paralelně. Zde pokryjeme backend co největším počtem disjunktních Bellových párů, jaké dovoluje jeho propojení (matching mapy propojení), a na každém páru spustíme nezávislý CHSH podCircuit, a to vše v jediné úloze.
Tím se CHSH stane celoplošným benchmarkem kvality provázanosti: místo jediného ručně vybraného páru testujeme provázanost napříč velkou částí čipu najednou, za reálných podmínek, kdy každý pár soutěží se svými sousedy o přeslechy a chyby paralelních operací. Porušení nerovnosti na každém páru současně certifikuje, že na celém zařízení je k dispozici skutečná provázanost.
# -------------------------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)

Jemné křivky představují jednotlivé Bellovy páry a tučné křivky jejich průměr napříč zařízením. Každý pár sleduje stejnou sinusoidu předpovězenou kvantovou mechanikou a rozptyl mezi jemnými křivkami odráží variabilitu šumu od páru k páru. Tam, kde křivka vstoupí do šedých pásem, překročila klasickou mez a tištěný souhrn potvrzuje, že prakticky každý pár porušuje nerovnost CHSH současně.
Vrcholy nedosahují Tsirelsonovy meze kvůli šumu zařízení, ale závěr je jednoznačný: backend udržuje skutečnou provázanost napříč celým čipem současně, nejen na jediném ručně vybraném páru. V tom spočívá smysl „rozšiřování" experimentu CHSH: ne jako jeden větší Circuit, ale jako paralelní benchmark certifikující provázanost všude najednou.
Další kroky
Pokud tě toto téma zaujalo, mohly by tě zajímat i tyto materiály:
- Provázanost v praxi: lekce kurzu od Johna Watrousa o Bellových stavech a hře CHSH.
- Začínáme s primitivou Estimator: průvodce PUBy a prohledáváním parametrů.
- Benchmarking v reálném čase pro výběr Qubitů: další způsob, jak charakterizovat kvalitu Qubitů a provázanosti napříč zařízením.
- Referenční dokumentace
SparsePauliOp.