Inegalitatea CHSH
Estimare utilizare: Două minute pe un procesor Heron r3 (NOTĂ: Aceasta este doar o estimare. Timpul de rulare poate varia.)
Rezultate ale învățării
După finalizarea acestui tutorial, te aștepți să înțelegi următoarele:
- Cum să construiești un circuit CHSH parametrizat cu stări Bell și să măsori cele patru valori de așteptare care alcătuiesc martorii CHSH.
- Cum să calculezi valorile de așteptare ale mai multor observabile pe un interval de parametri într-un singur apel la primitivul
EstimatorV2. - Cum să validezi un flux de lucru cuantic pe un simulator local cu zgomot folosind
AerSimulator.from_backendînainte de a trimite jobul pe hardware. - Cum să scalezi un experiment CHSH într-un benchmark de entanglement la nivelul întregului dispozitiv, rulând multe perechi Bell independente în paralel pe hardware-ul IBM Quantum®.
Cerințe preliminare
Se recomandă să te familiarizezi cu aceste subiecte:
- Entanglementul în acțiune, o lecție de curs despre stările Bell și jocul CHSH.
SparsePauliOpși introducerea în primitivele Qiskit.
Fundal
În acest tutorial, vei rula un experiment pe un calculator cuantic pentru a demonstra violarea inegalității CHSH cu primitivul Estimator.
Inegalitatea CHSH, denumită după Clauser, Horne, Shimony și Holt, este folosită pentru a testa experimental teorema lui Bell (1969). Teorema afirmă că teoriile cu variabile ascunse locale nu pot explica unele consecințe ale entanglementului în mecanica cuantică. Demonstrarea unei violări a inegalității CHSH arată că mecanica cuantică este incompatibilă cu teoriile cu variabile ascunse locale — un experiment fundamental pentru înțelegerea mecanicii cuantice.
Premiul Nobel pentru Fizică din 2022 a fost acordat lui Alain Aspect, John Clauser și Anton Zeilinger parțial pentru munca lor de pionierat în știința informației cuantice și, în special, pentru experimentele cu fotoni entanglați care demonstrează violarea inegalităților lui Bell.
Pentru acest experiment, vom crea o pereche entanglată pe care vom măsura fiecare qubit în două baze diferite. Vom eticheta bazele pentru primul qubit cu și , iar bazele pentru al doilea qubit cu și . Aceasta ne permite să calculăm cantitatea CHSH :
Fiecare observabil este fie , fie . Evident, unul dintre termenii trebuie să fie , iar celălalt trebuie să fie . Prin urmare, . Valoarea medie a lui trebuie să satisfacă inegalitatea:
Expandând în termenii lui , , și rezultă:
Poți defini o altă cantitate CHSH :
care conduce la o altă inegalitate:
Dacă mecanica cuantică ar putea fi descrisă prin teorii cu variabile ascunse locale, aceste inegalități ar fi întotdeauna respectate. Așa cum este demonstrat în acest tutorial, ele pot fi violate pe un calculator cuantic, deci mecanica cuantică nu este compatibilă cu teoriile cu variabile ascunse locale.
Vom crea perechea entanglată prin pregătirea stării Bell . Folosind primitivul Estimator, obținem direct valorile de așteptare și , fără a le reconstitui din numărătorile brute. Vom măsura al doilea qubit în bazele și . Primul qubit este măsurat, de asemenea, în baze ortogonale, dar cu un unghi de rotație pe care îl variăm între și . Primitivul Estimator evaluează această variație de parametri într-un singur bloc unificat primitiv (PUB).
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalate următoarele:
- Qiskit SDK v2.0 sau ulterior, cu suport pentru vizualizare
- Qiskit Runtime v0.40 sau ulterior (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 sau ulterior (
pip install qiskit-aer)
Configurare
# 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'
Exemplu la scară mică cu simulator
Înainte de a trimite un job pe hardware, validăm întregul flux de lucru pe un simulator local cu zgomot. Folosim AerSimulator.from_backend(backend) pentru a construi un simulator care moștenește modelul de zgomot și harta de conectivitate a backend-ului selectat, astfel încât răspunsul simulatorului să fie calitativ similar cu cel așteptat de la hardware.
Pasul 1: Maparea intrărilor clasice la o problemă cuantică
Scriem circuitul CHSH cu un singur parametru , care variază baza de măsurare a primului qubit. Primitivul Estimator simplifică analiza: returnează direct valorile de așteptare ale observabilelor și poate evalua un circuit parametrizat la mai multe valori de parametri într-un singur apel.
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")
Apoi, creăm o listă de 21 de valori de fază de la la la care să evaluăm circuitul parametrizat (, , , ..., , ).
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]
În final, definim observabilele. Primul qubit este măsurat de-a lungul axelor rotite cu ; al doilea qubit este măsurat în și . Cu aceste alegeri, cei patru corelatori CHSH corespund operatorilor Pauli , , și :
# <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)]
)
Pasul 2: Optimizarea problemei pentru execuția pe hardware cuantic
Primitivele V2 acceptă doar circuite și observabile care respectă instrucțiunile și conectivitatea suportate de sistemul țintă (circuite și observabile cu arhitectura setului de instrucțiuni, sau ISA). Construim AerSimulator pe baza backend-ului și transpilăm față de ținta simulatorului, astfel încât același manager de pași să fie exercitat de la capăt la capăt.
# 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")
De asemenea, transformăm observabilele pentru a se potrivi cu aranjamentul de qubiți al circuitului transpilat folosind SparsePauliOp.apply_layout.
isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)
isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)
Pasul 3: Executarea cu primitivele Qiskit
Rulăm variația de parametri cu EstimatorV2 în modul aer_sim. Metoda run() a Estimatorului primește un iterabil de PUBs. Fiecare PUB are formatul (circuit, observables, parameter_values, precision). Transmitem ambele observabile împreună, astfel încât să partajeze aceeași variație de parametri.
# 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()
Pasul 4: Post-procesare și returnarea rezultatului în formatul clasic dorit
Estimatorul returnează valorile de așteptare pentru ambele observabile. Le reprezentăm grafic față de , împreună cu limita clasică () și limita Tsirelson (). Zonele gri haşurate marchează intervalul dintre cele două. Punctele care se află în aceste benzi violează inegalitatea 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)",
)
Martorii CHSH ai simulatorului depășesc deja limita clasică de la mai multe valori ale lui , chiar și cu modelul de zgomot al backend-ului. Vârfurile se opresc chiar sub limita Tsirelson din cauza zgomotului simulat al dispozitivului. Cu fluxul de lucru validat, trecem la hardware-ul real.
Exemplu la scară largă pe hardware
Un test CHSH este în mod intrinsec un experiment pe două qubituri, deci nu scalează prin creșterea unui singur circuit. În schimb, scalează prin rularea multor teste în paralel. Aici acoperim backend-ul cu cât mai multe perechi Bell disjuncte permite conectivitatea sa (o potrivire a hărții de conectivitate) și rulăm un sub-circuit CHSH independent pe fiecare pereche, toate într-un singur job.
Aceasta transformă CHSH într-un benchmark al calității entanglementului la nivelul întregului dispozitiv: în loc de o singură pereche aleasă manual, testăm entanglementul pe o fracțiune mare din chip deodată, în condiții realiste în care fiecare pereche se confruntă cu crosstalk-ul vecinilor și erorile de porți paralele. Violarea inegalității pe fiecare pereche simultan certifică că entanglementul autentic este disponibil pretutindeni pe dispozitiv.
# -------------------------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)

Curbele estompate reprezintă perechile Bell individuale, iar curbele îngroșate reprezintă media lor pe tot dispozitivul. Fiecare pereche urmează același sinusoid prezis de mecanica cuantică, iar răspândirea dintre curbele estompate reflectă variația zgomotului de la o pereche la alta. Oriunde o curbă intră în benzile gri, a depășit limita clasică de , iar rezumatul afișat confirmă că practic fiecare pereche violează inegalitatea CHSH în același timp.
Vârfurile se opresc sub limita Tsirelson din cauza zgomotului dispozitivului, dar concluzia este fără echivoc: backend-ul menține entanglement autentic pe întregul chip simultan, nu doar pe o singură pereche aleasă manual. Acesta este sensul în care experimentul CHSH „scalează": nu ca un circuit mai mare, ci ca un benchmark paralel care certifică entanglementul pretutindeni deodată.
Pași următori
Dacă ai găsit acest material interesant, s-ar putea să te intereseze și:
- Entanglementul în acțiune: o lecție de curs a lui John Watrous despre stările Bell și jocul CHSH.
- Începe cu primitivul Estimator: un ghid despre PUBs și variații de parametri.
- Benchmarking în timp real pentru selecția qubiturilor: o altă modalitate de a caracteriza calitatea qubiturilor și a entanglementului pe un dispozitiv.
- Referință API
SparsePauliOp.