Skip to main content
IBM Quantum Platform

Desigualdade CHSH

Estimativa de tempo de execução: Dois minutos em um processador Heron r3 (NOTA: Trata-se apenas de uma estimativa.) (O tempo de execução pode variar.)


Resultados do aprendizado

Ao concluir este tutorial, você deverá compreender as seguintes informações:

  • Como construir um circuito CHSH em estado de Bell parametrizado e medir os quatro valores esperados que compõem as testemunhas CHSH.
  • Como calcular os valores esperados de múltiplas variáveis observáveis em uma varredura de parâmetros em uma única chamada à primitiva EstimatorV2 .
  • Como validar um fluxo de trabalho quântico em um simulador local sujeito a ruídos antes de AerSimulator.from_backend enviá-lo para o hardware.
  • Como ampliar um experimento CHSH para um teste de referência de entrelaçamento em todo o dispositivo, executando muitos pares de Bell independentes em paralelo em um hardwar IBM Quantum®.

Pré-requisitos

Recomenda-se que você se familiarize com estes tópicos:


Segundo plano

Neste tutorial, você executará um experimento em um computador quântico para demonstrar a violação da desigualdade CHSH com a primitiva Estimator.

A desigualdade de CHSH, cujo nome é uma referência a Clauser, Horne, Shimony e Holt, é utilizada para testar experimentalmente o teorema de Bell (1969). O teorema afirma que as teorias locais de variáveis ocultas não conseguem explicar algumas consequências do entrelaçamento na mecânica quântica. A demonstração de uma violação da desigualdade de CHSH mostra que a mecânica quântica é incompatível com as teorias locais de variáveis ocultas — um experimento que é fundamental para nossa compreensão da mecânica quântica.

O Prêmio Nobel de Física de 2022 foi concedido a Alain Aspect, John Clauser e Anton Zeilinger, em parte por seu trabalho pioneiro na ciência da informação quântica e, em particular, por seus experimentos com fótons entrelaçados que demonstraram a violação das desigualdades de Bell.

Para este experimento, criaremos um par entrelaçado no qual mediremos cada qubit em duas bases diferentes. Vamos designar as bases do primeiro qubit como AA e aa, e as bases do segundo qubit como BB e bb. Isso nos permite calcular a quantidade CHSH S1S_1 :

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

Cada observável é +1+1 ou 1-1. É evidente que um dos termos B±bB\pm b deve ser 00, e o outro deve ser ±2\pm 2. Portanto, S1=±2S_1 = \pm 2. O valor médio de S1S_1 deve satisfazer a desigualdade:

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

Ao expandir S1S_1 em termos de AA, aa, BB e bb, obtém-se:

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

Você pode definir outra quantidade de CHSH S2S_2 :

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

o que leva a outra desigualdade:

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

Se a mecânica quântica pudesse ser descrita por teorias de variáveis ocultas locais, essas desigualdades seriam sempre válidas. Conforme demonstrado neste tutorial, essas propriedades podem ser violadas em um computador quântico; portanto, a mecânica quântica não é compatível com as teorias de variáveis ocultas locais.

Criamos o par entrelaçado preparando o estado de Bell Φ+=00+112|\Phi^+\rangle = \frac{|00\rangle + |11\rangle}{\sqrt{2}}. Utilizando a primitiva Estimadora, obtemos os valores esperados AB,Ab,aB\langle AB \rangle, \langle Ab \rangle, \langle aB \rangle e ab\langle ab \rangle diretamente, sem precisar reconstruí-los a partir das contagens brutas. Medimos o segundo qubit nas bases ZZ e XX. O primeiro qubit também é medido em bases ortogonais, mas com um ângulo de rotação θ\theta que variamos entre 00 e 2π2\pi. A primitiva Estimator avalia essa variação de parâmetros em um único bloco unificado de primitivas ( PUB ).


Requisitos

Antes de iniciar este tutorial, certifique-se de ter os seguintes itens instalados:

  • Qiskit SDK v2.0 ou versão posterior, com suporte à visualização
  • Qiskit Runtime v0.40 ou posterior (pip install qiskit-ibm-runtime)
  • Qiskit Aer v0.17 ou versão posterior (pip install qiskit-aer)

Instalação

# 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

Output:

'ibm_pittsburgh'

Exemplo de simulador em pequena escala

Antes de enviar uma tarefa de hardware, validamos todo o fluxo de trabalho em um simulador local com ruído. Utilizamos AerSimulator.from_backend(backend) para criar um simulador que herda o modelo de ruído e o mapa de acoplamento do backend selecionado por você, de modo que a resposta do simulador seja qualitativamente semelhante à que esperamos do hardware.

Passo 1: Mapear entradas clássicas para um problema quântico

Escrevemos o circuito CHSH com um único parâmetro θ\theta, que varre a base de medição do primeiro qubit. A Estimator primitiva simplifica a análise: ela retorna diretamente os valores esperados das grandezas observáveis e pode avaliar um circuito parametrizado para vários valores de parâmetros em uma única chamada.

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

Em seguida, criamos uma lista de 21 valores de fase, que vão de 00 a 2π2\pi, nos quais avaliaremos o circuito parametrizado ( 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]

Por fim, definimos as grandezas observáveis. O primeiro qubit é medido ao longo de eixos girados em θ\theta; o segundo qubit é medido em ZZ e XX. Com essas escolhas, os quatro correladores CHSH correspondem aos operadores de 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)]
)

Etapa 2: Otimizar o problema para execução em hardware quântico

V2 As primitivas aceitam apenas circuitos e observáveis que estejam em conformidade com as instruções e a conectividade suportadas pelo sistema de destino (arquitetura de conjunto de instruções, ou ISA, circuitos e observáveis). Nós compilamos o AerSimulator no backend e fazemos a transpilagem para o destino do simulador, de modo que o mesmo gerenciador de passagens seja executado de ponta a ponta.

# 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

Também transformamos os observáveis para que correspondam ao layout de qubits do circuito transpilado usando SparsePauliOp.apply_layout.

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

Passo 3: Execute usando Qiskit primitives

Execute a varredura de parâmetros no aer_sim``EstimatorV2 modo. O método Estimator run() recebe um iterável de PUBs. Cada PUB tem o formato (circuit, observables, parameter_values, precision). Passamos os dois observáveis juntos para que compartilhem a mesma variação de parâmetros.

# 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()

Etapa 4: Pós-processamento e retorno do resultado no formato clássico desejado

O Estimador retorna os valores esperados para ambas as variáveis observáveis. Nós as representamos graficamente em θ\theta, juntamente com o limite clássico ( ±2\pm 2 ) e o limite de Tsirelson ( ±22\pm 2\sqrt{2} ). As regiões sombreadas em cinza indicam a diferença entre os dois. Os pontos que se encontram dentro dessas faixas violam a desigualdade 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:

Output of the previous code cell

Os testemunhos CHSH do simulador já excedem o limite clássico de ±2\pm 2 em vários valores de θ\theta, mesmo com o modelo de ruído do backend. Os picos ficam um pouco abaixo do limite de Tsirelson ±22\pm 2\sqrt{2} devido ao ruído simulado do dispositivo. Com o fluxo de trabalho validado, passamos para o hardware propriamente dito.


Exemplo de hardware em grande escala

Um teste CHSH é, por natureza, um experimento com dois qubits; portanto, não é possível aumentá-lo simplesmente ampliando um circuito. Em vez disso, ele alcança escalabilidade executando muitos testes em paralelo. Aqui, dividimos o backend em tantos pares de Bell disjuntos quanto sua conectividade permitir (uma correspondência do mapa de acoplamento) e executamos um subcircuito CHSH independente em cada par, tudo em um único trabalho.

Isso transforma o CHSH em um parâmetro de referência para a qualidade do entrelaçamento em todo o dispositivo : em vez de um único par selecionado manualmente, testamos o entrelaçamento em uma grande parte do chip de uma só vez, em condições realistas nas quais cada par enfrenta a interferência dos vizinhos e erros de portas paralelas. A violação simultânea da desigualdade em todos os pares comprova que o entrelaçamento genuíno está presente em todos os pontos do 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

As curvas mais tênues representam os pares de Bell individuais, e as curvas em negrito representam a média deles em todo o dispositivo. Cada par traça a mesma sinusoide prevista pela mecânica quântica, e a dispersão entre as curvas pouco marcantes reflete a variação no ruído de um par para outro. Sempre que uma curva entra nas faixas cinzas, isso significa que ela ultrapassou o limite clássico de ±2\pm 2, e o resumo impresso confirma que, essencialmente, todos os pares violam a desigualdade de CHSH ao mesmo tempo.

Os picos ficam aquém do limite de Tsirelson ±22\pm 2\sqrt{2} devido ao ruído do dispositivo, mas a conclusão é inequívoca: o backend mantém um entrelaçamento genuíno em todo o chip simultaneamente, e não apenas em um único par selecionado manualmente. É nesse sentido que o experimento do CHSH “se expande”: não como um único circuito maior, mas como um parâmetro de referência paralelo que certifica o entrelaçamento em todos os lugares ao mesmo tempo.


Próximas etapas

Recomendações

Se você achou este trabalho interessante, talvez se interesse pelo material a seguir:

Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.