Skip to main content
IBM Quantum Platform

Disuguaglianza CHSH

Stima del tempo di esecuzione: due minuti su un processore Heron r3 (NOTA: si tratta solo di una stima. (La durata potrebbe variare.)


Risultati di apprendimento

Al termine di questo tutorial, avrai acquisito le seguenti conoscenze:

  • Come costruire un circuito CHSH a stato di Bell parametrizzato e misurare i quattro valori attesi che costituiscono i testimoni CHSH.
  • Come calcolare i valori attesi di più osservabili lungo un intervallo di variazioni dei parametri con una singola chiamata alla EstimatorV2 primitiva.
  • Come verificare la validità di un flusso di lavoro quantistico su un simulatore locale soggetto a rumore prima di AerSimulator.from_backend trasferirlo all'hardware.
  • Come trasformare un esperimento CHSH in un benchmark sull’entanglement a livello di dispositivo, eseguendo in parallelo numerose coppie di Bell indipendenti su un hardwar IBM Quantum®.

Prerequisiti

Si consiglia di approfondire i seguenti argomenti:


Sfondo

In questa esercitazione verrà eseguito un esperimento su un computer quantistico per dimostrare la violazione della disuguaglianza CHSH con la primitiva Estimator.

La disuguaglianza di CHSH, che prende il nome da Clauser, Horne, Shimony e Holt, viene utilizzata per verificare sperimentalmente il teorema di Bell (1969). Il teorema afferma che le teorie locali delle variabili nascoste non sono in grado di spiegare alcune conseguenze dell'entanglement nella meccanica quantistica. Dimostrare una violazione della disuguaglianza di CHSH dimostra che la meccanica quantistica è incompatibile con le teorie delle variabili nascoste locali: si tratta di un esperimento fondamentale per la nostra comprensione della meccanica quantistica.

Il Premio Nobel per la Fisica 2022 è stato assegnato ad Alain Aspect, John Clauser e Anton Zeilinger, in parte per il loro lavoro pionieristico nel campo della scienza dell'informazione quantistica e, in particolare, per i loro esperimenti con fotoni intrecciati che hanno dimostrato la violazione delle disuguaglianze di Bell.

Per questo esperimento, creeremo una coppia di qubit intrecciati, sui quali misureremo ciascun qubit in due basi diverse. Indicheremo le basi del primo qubit con AA e aa e quelle del secondo qubit con BB e bb. Questo ci permette di calcolare la quantità CHSH S1S_1 :

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

Ogni grandezza osservabile è o +1+1 oppure 1-1. Chiaramente, uno dei termini B±bB\pm b deve essere 00, mentre l’altro deve essere ±2\pm 2. Pertanto, S1=±2S_1 = \pm 2. Il valore medio di S1S_1 deve soddisfare la disuguaglianza:

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

Espandendo S1S_1 in termini di AA, aa, BB e bb si ottiene:

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

È possibile definire un'altra quantità di CHSH S2S_2 :

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

il che porta a un'altra disuguaglianza:

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

Se la meccanica quantistica potesse essere descritta da teorie locali delle variabili nascoste, queste disuguaglianze sarebbero sempre valide. Come dimostrato in questo tutorial, tali principi possono essere violati su un computer quantistico; pertanto, la meccanica quantistica non è compatibile con le teorie delle variabili nascoste locali.

Creiamo la coppia intrecciata preparando lo stato di Bell Φ+=00+112|\Phi^+\rangle = \frac{|00\rangle + |11\rangle}{\sqrt{2}}. Utilizzando la primitiva Estimator, otteniamo direttamente i valori attesi AB,Ab,aB\langle AB \rangle, \langle Ab \rangle, \langle aB \rangle e ab\langle ab \rangle, senza doverli ricostruire dai conteggi grezzi. Misuriamo il secondo qubit nelle basi ZZ e XX. Anche il primo qubit viene misurato in basi ortogonali, ma con un angolo di rotazione θ\theta che viene variato tra 00 e 2π2\pi. La primitiva Estimator valuta questa variazione del parametro in un unico blocco primitivo unificato ( PUB ).


Requisiti

Prima di iniziare questo tutorial, assicurati di avere installato quanto segue:

  • Qiskit SDK v2.0 o versioni successive, con supporto alla visualizzazione
  • Qiskit Runtime v0.40 o versioni successive (pip install qiskit-ibm-runtime)
  • Qiskit Aer v0.17 o versione successiva (pip install qiskit-aer)

Configura

# 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.name

Output:

'ibm_pittsburgh'

Esempio di simulatore su piccola scala

Prima di inviare un’elaborazione hardware, verifichiamo l’intero flusso di lavoro su un simulatore locale soggetto a rumore. Utilizziamo AerSimulator.from_backend(backend) per creare un simulatore che erediti il modello di rumore e la mappa di accoppiamento del backend selezionato, in modo che la risposta del simulatore sia qualitativamente simile a quella che ci aspettiamo dall'hardware.

Fase 1: mappare gli input classici su un problema quantistico

Scriviamo il circuito CHSH con un unico parametro θ\theta, che varia la base di misura del primo qubit. La Estimator primitiva semplifica l'analisi: restituisce direttamente i valori attesi delle grandezze osservabili e consente di valutare un circuito parametrizzato per molti valori dei parametri con una singola chiamata.

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:

Output of the previous code cell

Successivamente, creiamo un elenco di 21 valori di fase compresi tra 00 e 2π2\pi, ai quali valutare il circuito parametrizzato ( 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]

Infine definiamo le grandezze osservabili. Il primo qubit viene misurato lungo assi ruotati di un angolo pari a θ\theta; il secondo qubit viene misurato lungo gli assi ZZ e XX. Con queste scelte, i quattro correlatori CHSH corrispondono agli operatori di Pauli ZZZZ, ZXZX, XZXZ e 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)]
)

Fase 2: Ottimizzazione del problema per l'esecuzione su hardware quantistico

V2 Le primitive accettano solo circuiti e osservabili conformi alle istruzioni e alla connettività supportate dal sistema di destinazione (architettura del set di istruzioni, o ISA, circuiti e osservabili). Compiliamo il codice AerSimulator dal backend e lo transpiliamo in base alla destinazione del simulatore, in modo che lo stesso gestore di passaggi venga eseguito dall'inizio alla fine.

# 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:

Output of the previous code cell

Inoltre, trasformiamo gli osservabili in modo che corrispondano alla disposizione dei qubit del circuito transpilato utilizzando SparsePauliOp.apply_layout.

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

Passaggio 3: eseguire utilizzando Qiskit primitives

Eseguire la scansione dei parametri in aer_sim``EstimatorV2 modalità. Il metodo Estimator run() accetta un iterabile di PUB. Ogni PUB ha il formato (circuit, observables, parameter_values, precision). Passiamo entrambi gli osservabili insieme, in modo che condividano lo stesso intervallo di variazione dei 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()

Fase 4: Post-elaborazione e restituzione del risultato nel formato classico desiderato

La funzione Estimator restituisce i valori attesi per entrambe le grandezze osservabili. Li rappresentiamo graficamente su θ\theta insieme al limite classico ( ±2\pm 2 ) e al limite di Tsirelson ( ±22\pm 2\sqrt{2} ). Le aree ombreggiate in grigio indicano la differenza tra i due. I punti che si trovano all'interno di queste bande violano la disuguaglianza di 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:

Output of the previous code cell

I valori di CHSH rilevati dal simulatore superano già il limite classico di ±2\pm 2 per diversi valori di θ\theta, anche con il modello di rumore del backend. I picchi risultano leggermente inferiori al limite di Tsirelson ±22\pm 2\sqrt{2} a causa del rumore simulato del dispositivo. Una volta convalidato il flusso di lavoro, passiamo all'hardware vero e proprio.


Esempio di hardware su larga scala

Un test CHSH è intrinsecamente un esperimento a due qubit, quindi non è possibile aumentarne la scalabilità semplicemente ingrandendo un circuito. Al contrario, la sua efficienza aumenta grazie all'esecuzione di numerosi test in parallelo. In questo caso suddividiamo il backend in tante coppie di Bell disgiunte quante ne consente la sua connettività (una corrispondenza della mappa di accoppiamento) ed eseguiamo un sottocircuito CHSH indipendente su ogni coppia, il tutto in un unico processo.

Ciò trasforma il CHSH in un parametro di riferimento per la qualità dell'entanglement a livello dell'intero dispositivo : anziché una singola coppia selezionata con cura, testiamo l'entanglement su un'ampia porzione del chip contemporaneamente, in condizioni realistiche in cui ogni coppia deve fare i conti con il crosstalk dei vicini e con gli errori dei gate paralleli. La violazione simultanea della disuguaglianza su ogni coppia dimostra che l’entanglement autentico è presente ovunque nel dispositivo.

# -------------------------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)
Output of the previous code cell

Le curve più sottili rappresentano le singole coppie di Bell, mentre quelle in grassetto ne indicano la media su tutto il dispositivo. Ogni coppia descrive la stessa sinusoide prevista dalla meccanica quantistica, e la dispersione tra le curve poco evidenti riflette la variazione del rumore da una coppia all’altra. Ogni volta che una curva entra nelle bande grigie, significa che ha superato il limite classico di ±2\pm 2, e il riepilogo stampato conferma che, in sostanza, ogni coppia viola contemporaneamente la disuguaglianza di CHSH.

I picchi non raggiungono il limite di Tsirelson ±22\pm 2\sqrt{2} a causa del rumore del dispositivo, ma la conclusione è inequivocabile: il backend mantiene un vero e proprio intreccio quantistico su tutto il chip contemporaneamente, non solo su una singola coppia selezionata ad hoc. È in questo senso che l’esperimento CHSH si “estende”: non come un unico circuito più grande, ma come un punto di riferimento parallelo che certifica l’entanglement ovunque contemporaneamente.


Passi successivi

Suggerimenti

Se questo lavoro ti è sembrato interessante, potrebbero interessarti anche i seguenti contenuti:

Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.