Inégalité CHSH
Estimation de la durée d'exécution : deux minutes sur un processeur Heron r3 (REMARQUE : il s'agit uniquement d'une estimation. (La durée d'exécution peut varier.)
Acquis d'apprentissage
À l'issue de ce tutoriel, vous devriez être en mesure de comprendre les éléments suivants :
- Comment construire un circuit CHSH à état de Bell paramétré et mesurer les quatre valeurs d'espérance qui constituent les témoins CHSH.
- Comment calculer les valeurs attendues de plusieurs observables lors d'un balayage de paramètres en un seul appel à la
EstimatorV2primitive. - Comment valider un workflow quantique sur un simulateur local sujet au bruit avant de
AerSimulator.from_backendle soumettre au matériel. - Comment étendre une expérience CHSH à un test de référence sur l'intrication à l'échelle d'un dispositif en exécutant en parallèle de nombreuses paires de Bell indépendantes sur le matériel d' IBM Quantum®.
Prérequis
Nous vous recommandons de vous familiariser avec les sujets suivants :
- L'intrication en action : un cours sur les états de Bell et le jeu CHSH.
SparsePauliOpet l 'introduction à l' Qiskit primitives.
Arrière-plan
Dans ce tutoriel, vous ferez une expérience sur un ordinateur quantique pour démontrer la violation de l'inégalité CHSH avec la primitive Estimator.
L'inégalité de CHSH, qui tire son nom de Clauser, Horne, Shimony et Holt, sert à vérifier expérimentalement le théorème de Bell (1969). Ce théorème affirme que les théories locales à variables cachées ne permettent pas d'expliquer certaines conséquences de l'intrication en mécanique quantique. La démonstration d'une violation de l'inégalité de CHSH montre que la mécanique quantique est incompatible avec les théories des variables cachées locales; il s'agit d'une expérience fondamentale pour notre compréhension de la mécanique quantique.
Le prix Nobel de physique 2022 a été décerné à Alain Aspect, John Clauser et Anton Zeilinger, notamment pour leurs travaux pionniers dans le domaine de l'informatique quantique, et plus particulièrement pour leurs expériences sur des photons intriqués démontrant la violation des inégalités de Bell.
Pour cette expérience, nous allons créer une paire intriquée sur laquelle nous mesurerons chaque qubit selon deux bases différentes. Nous désignerons les bases du premier qubit par et , et celles du deuxième qubit par et . Cela nous permet de calculer la quantité CHSH :
Chaque grandeur observable est soit , soit . De toute évidence, l’un des termes doit être , et l’autre doit être . Par conséquent, . La valeur moyenne de doit satisfaire l’inégalité suivante :
En développant en fonction de , , et , on obtient :
Vous pouvez définir une autre quantité CHSH :
ce qui conduit à une autre inégalité :
Si la mécanique quantique pouvait être décrite par des théories des variables cachées locales, ces inégalités seraient toujours valables. Comme le montre ce tutoriel, ces principes peuvent être enfreints sur un ordinateur quantique; la mécanique quantique n'est donc pas compatible avec les théories des variables cachées locales.
Nous créons la paire intriquée en préparant l'état de Bell . À l'aide de la primitive « Estimator », nous obtenons directement les valeurs d'espérance et , sans avoir à les reconstruire à partir des comptages bruts. Nous mesurons le deuxième qubit dans les bases et . Le premier qubit est également mesuré dans des bases orthogonales, mais avec un angle de rotation que nous balayons entre et . La primitive Estimator évalue ce balayage de paramètre dans un seul bloc unifié primitif ( PUB ).
Exigences
Avant de commencer ce tutoriel, assurez-vous d'avoir installé les éléments suivants :
- Qiskit SDK v2.0 ou version ultérieure, avec prise en charge de la visualisation
- Qiskit Runtime v0.40 ou version ultérieure (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 ou version ultérieure (
pip install qiskit-aer)
Configuration
# 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-ibm-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.nameOutput:
'ibm_pittsburgh'
Exemple de simulateur à petite échelle
Avant de soumettre une tâche sur le matériel, nous validons l'ensemble du flux de travail sur un simulateur local présentant des perturbations. Nous utilisons AerSimulator.from_backend(backend) pour créer un simulateur qui hérite du modèle de bruit et de la carte de couplage du backend que vous avez sélectionné, de sorte que la réponse du simulateur soit qualitativement similaire à celle que l'on attend du matériel.
Étape 1 : Mettre en correspondance les entrées classiques avec un problème quantique
Nous décrivons le circuit CHSH à l'aide d'un seul paramètre , qui balaye la base de mesure du premier qubit. Cette Estimator primitive simplifie l'analyse : elle renvoie directement les valeurs attendues des observables et permet d'évaluer un circuit paramétré pour de nombreuses valeurs de paramètres en un seul appel.
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:
Ensuite, nous créons une liste de 21 valeurs de phase, allant de à , pour lesquelles nous allons évaluer le circuit paramétré ( , , , …, , ).
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]Enfin, nous définissons les observables. Le premier qubit est mesuré selon des axes tournés d’ ; le deuxième qubit est mesuré selon et . Avec ces choix, les quatre corrélateurs CHSH correspondent aux opérateurs de Pauli , , et :
# <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)]
)Étape 2 : Optimiser le problème pour l'exécution sur du matériel quantique
V2 Les primitives n'acceptent que les circuits et les observables conformes aux instructions et à la connectivité prises en charge par le système cible (architecture du jeu d'instructions, ou ISA, circuits et observables). Nous construisons le AerSimulator à partir du backend et le transpilons en fonction de la cible du simulateur, afin que le même gestionnaire de passes soit utilisé de bout en bout.
# 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:
Nous transformons également les observables afin qu'elles correspondent à la disposition des qubits du circuit transpilé à l'aide de SparsePauliOp.apply_layout.
isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)
isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)Étape 3 : Exécutez à l'aide d' Qiskit primitives
Lancez le balayage des paramètres en aer_sim``EstimatorV2 mode. La méthode Estimator run() prend en paramètre un itérable de PUB. Chaque fichier « PUB » a le format (circuit, observables, parameter_values, precision). Nous transmettons les deux observables ensemble afin qu'elles partagent le même balayage de paramètres.
# 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()Étape 4 : Post-traitement et restitution du résultat dans le format classique souhaité
L'estimateur renvoie les valeurs attendues pour les deux grandeurs observables. Nous les représentons graphiquement sur , aux côtés de la borne classique ( ) et de la borne de Tsirelson ( ). Les zones grisées indiquent l'écart entre les deux. Les points situés à l'intérieur de ces intervalles ne satisfont pas à l'inégalité de 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:
Les témoins CHSH du simulateur dépassent déjà la limite classique de pour plusieurs valeurs de , même avec le modèle de bruit du backend. Les pics sont légèrement inférieurs à la limite de Tsirelson en raison du bruit simulé du dispositif. Une fois le processus validé, nous passons à la mise en place du matériel proprement dit.
Exemple de matériel à grande échelle
Un test CHSH est, par nature, une expérience à deux qubits; il n'est donc pas possible d'en augmenter l'échelle en agrandissant simplement le circuit. Au contraire, il s'adapte en exécutant de nombreux tests en parallèle. Ici, nous divisons le backend en autant de paires de Bell disjointes que le permet sa connectivité (une correspondance de la carte de couplage) et nous exécutons un sous-circuit CHSH indépendant sur chaque paire, le tout dans une seule tâche.
Le CHSH devient ainsi une référence à l'échelle du dispositif pour évaluer la qualité de l'intrication : plutôt que de nous limiter à une seule paire sélectionnée manuellement, nous testons l'intrication sur une grande partie de la puce en même temps, dans des conditions réalistes où chaque paire doit composer avec la diaphonie de ses voisines et les erreurs liées aux portes parallèles. Le fait de violer simultanément l'inégalité pour chaque paire atteste qu'un véritable enchevêtrement est présent partout sur le dispositif.
# -------------------------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()Output:
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)
Les courbes en trait fin représentent les paires de Bell individuelles, tandis que les courbes en trait épais correspondent à leur moyenne sur l'ensemble du dispositif. Chaque paire suit la même sinusoïde prévue par la mécanique quantique, et l'écart entre ces courbes à faible amplitude reflète la variation du bruit d'une paire à l'autre. Chaque fois qu'une courbe pénètre dans les bandes grises, cela signifie qu'elle a franchi la limite classique de l' ; le résumé imprimé confirme que pratiquement toutes les paires enfreignent simultanément l'inégalité de CHSH.
Les pics sont inférieurs à la limite de Tsirelson en raison du bruit du dispositif, mais la conclusion est sans équivoque : le backend maintient un enchevêtrement authentique sur l'ensemble de la puce simultanément, et pas seulement sur une seule paire choisie au hasard. C'est en ce sens que l'expérience du CHSH « s'étend » : non pas sous la forme d'un circuit plus grand, mais comme une référence parallèle qui certifie l'intrication partout et en même temps.
Etapes suivantes
Si ce travail vous a paru intéressant, les documents suivants pourraient vous intéresser :
- L'intrication en action : un cours dispensé par John Watrous sur les états de Bell et le jeu CHSH.
- Premiers pas avec la primitive « Estimator » : guide sur les PUB et les balayages de paramètres.
- Évaluation comparative en temps réel pour la sélection des qubits : une autre méthode pour caractériser la qualité des qubits et de l'intrication au sein d'un dispositif.
SparsePauliOpRéférence de l'API.