CHSH 부등식
예상 소요 시간: Heron r3 프로세서에서 2분 (참고: 이는 단지 추정치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)
학습 성과
- 매개변수화된 벨 상태 CHSH 회로를 구성하고, CHSH 증인을 구성하는 네 가지 기대값을 측정하는 방법.
- 프라이머리 함수를
EstimatorV2한 번 호출하여 매개변수 스윕 시 여러 관측량의 기대값을 계산하는 방법. - 하드웨어에 제출하기 전에 잡음이 있는 로컬 시뮬레이터에서 양자 워크플로우를 검증하는 방법.
AerSimulator.from_backend - IBM Quantum® 하드웨어에서 다수의 독립적인 벨 쌍을 병렬로 실행하여 CHSH 실험을 장치 전체에 걸친 얽힘 벤치마크로 확장하는 방법.
전제조건
- 실전 얽힘 : 벨 상태와 CHSH 게임에 관한 강의.
SparsePauliOp그리고 ‘ Qiskit primitives ’ 소개.
배경
이 튜토리얼에서는 양자 컴퓨터에서 실험을 실행하여 추정기 프리미티브가 CHSH 부등식을 위반하는 것을 증명합니다.
클라우저(Clauser), 호른(Horne), 시모니(Shimony), 홀트(Holt)의 이름을 딴 CHSH 부등식은 벨의 정리(1969)를 실험적으로 검증하는 데 사용된다. 이 정리는 국소적 숨은 변수 이론으로는 양자역학에서 얽힘이 초래하는 일부 결과를 설명할 수 없다고 주장한다. CHSH 부등식의 위반을 입증하는 것은 양자역학이 국소적 숨은 변수 이론과 양립할 수 없음을 보여주는 것으로, 이는 양자역학을 이해하는 데 있어 기초가 되는 실험이다.
2022년 노벨 물리학상은 알랭 아스펙트, 존 클라우저, 안톤 자이링거에게 수여되었는데, 이는 부분적으로 양자 정보 과학 분야의 선구적인 업적, 특히 얽힌 광자를 이용한 실험을 통해 벨 부등식의 위반을 입증한 공로를 인정받은 결과이다.
이번 실험에서는 얽힘 쌍을 생성한 뒤, 각 큐비트를 서로 다른 두 가지 기저에서 측정할 것입니다. 첫 번째 큐비트의 기저를 와 로, 두 번째 큐비트의 기저를 와 로 표기하겠습니다. 이를 통해 CHSH 양 을 계산할 수 있습니다:
각 관측값은 또는 중 하나입니다. 분명히, 중 한 항은 이어야 하고, 다른 한 항은 이어야 합니다. 따라서, 입니다. 의 평균값은 다음 부등식을 만족해야 합니다:
를 , , , 에 대해 전개하면 다음과 같습니다:
다른 CHSH 수량을 정의할 수 있습니다 :
이로 인해 또 다른 부등식이 도출되는데:
만약 양자역학이 국소적 숨은 변수 이론으로 설명될 수 있다면, 이러한 부등식은 항상 성립할 것이다. 이 튜토리얼에서 보여준 바와 같이, 양자 컴퓨터에서는 이러한 원리가 위반될 수 있으므로, 양자역학은 국소 숨겨진 변수 이론과 양립할 수 없다.
우리는 벨 상태 를 준비하여 얽힌 쌍을 생성합니다. ‘Estimator’ 기본 기능을 사용하여, 원시 계수값으로부터 재구성할 필요 없이 기대값 및 를 직접 구합니다. 우리는 와 기저에서 두 번째 큐비트를 측정합니다. 첫 번째 큐비트 역시 직교 기저에서 측정되지만, 회전 각도 를 와 사이에서 스윕합니다. Estimator 프리미티브는 이 매개변수 스윕을 단일 프리미티브 통합 블록( PUB ) 에서 평가합니다.
요구사항
이 튜토리얼을 시작하기 전에 다음 항목이 설치되어 있는지 확인하십시오:
- Qiskit SDK v2.0 또는 그 이후 버전, 시각화 기능 지원
- Qiskit Runtime v0.40 또는 그 이후 (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 이상 (
pip install qiskit-aer)
설정
# 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'
소규모 시뮬레이터 예시
하드웨어 작업을 제출하기 전에, 로컬의 노이즈가 포함된 시뮬레이터에서 전체 워크플로를 검증합니다. 우리는 를 AerSimulator.from_backend(backend) 사용하여 사용자가 선택한 백엔드의 노이즈 모델과 커플링 맵을 상속하는 시뮬레이터를 구축하므로, 시뮬레이터의 응답은 하드웨어에서 예상되는 결과와 질적으로 유사합니다.
1단계: 고전적 입력을 양자 문제에 매핑하기
CHSH 회로는 단일 매개변수 로 표현되며, 이 매개변수는 첫 번째 큐비트의 측정 기저를 훑어 나갑니다. 이 Estimator 프리미티브는 분석을 단순화합니다. 관측 가능한 변수의 기대값을 직접 반환하며, 단 한 번의 호출로 다양한 매개변수 값에 대해 매개변수화된 회로를 평가할 수 있습니다.
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:
다음으로, 매개변수화된 회로( , , ,..., , )를 평가할 부터 까지의 21개 위상 값 목록을 생성합니다.
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]마지막으로 관측량을 정의합니다. 첫 번째 큐비트는 로 회전된 축을 따라 측정되며, 두 번째 큐비트는 및 에서 측정됩니다. 이러한 선택을 바탕으로, 네 개의 CHSH 상관함수는 파울리 연산자 , , 및 에 대응됩니다:
# <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)]
)2단계: 양자 하드웨어 실행을 위한 문제 최적화
V2 프리미티브는 대상 시스템이 지원하는 명령어 및 연결 방식(명령어 집합 아키텍처, 즉 ISA, 회로 및 관측 가능 변수)에 부합하는 회로와 관측 가능 변수만 허용합니다. 우리는 백엔드에서 를 AerSimulator 빌드하고 시뮬레이터의 대상 환경에 맞춰 트랜스파일링하여, 동일한 패스 매니저가 엔드투엔드 방식으로 실행되도록 합니다.
# 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:
SparsePauliOp.apply_layout또한,.를 사용하여 관측 가능한 양을 트랜스파일된 회로의 큐비트 배열에 맞게 변환합니다.
isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)
isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)3단계: Qiskit primitives 명령어로 실행합니다
모드에서 aer_sim``EstimatorV2 매개변수 스윕을 실행합니다. Estimator run() 메서드는 PUB의 반복 가능한 객체를 매개변수로 받습니다. (circuit, observables, parameter_values, precision)각 PUB 파일은 다음과 같은 형식을 갖습니다. 두 관측 변수를 함께 전달하여 동일한 매개변수 스윕을 공유하도록 합니다.
# 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()4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환
Estimator는 두 관측 가능 변수에 대한 기대값을 반환합니다. 이 값들을 에 그래프로 표시하고, 여기에 고전적 상한( )과 치렐슨 상한( )을 함께 표시했습니다. 회색 음영 처리된 영역은 이 두 상한 사이의 차이를 나타냅니다. 이 대역 안에 있는 점들은 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:
이 시뮬레이터의 CHSH 증인은, 백엔드의 잡음 모델을 적용한 상태에서도 의 여러 값에서 이미 고전적 한계인 를 초과하고 있다. 시뮬레이션된 소자 잡음으로 인해 피크 값은 Tsirelson 상한 에 약간 미치지 못합니다. 워크플로우 검증이 완료되었으므로, 이제 실제 하드웨어 단계로 넘어갑니다.
대규모 하드웨어 예시
CHSH 검정은 본질적으로 2-큐비트 실험이므로, 회로 하나를 더 크게 만든다고 해서 확장성이 향상되지는 않습니다. 대신, 여러 테스트를 병렬로 실행함으로써 확장성을 확보합니다. 여기서는 연결성이 허용하는 한도 내에서 백엔드를 서로 겹치지 않는 벨 쌍으로 최대한 많이 타일링하고(결합 맵의 매칭 ), 각 쌍에 대해 독립적인 CHSH 하위 회로를 실행하며, 이 모든 과정을 단일 작업 내에서 수행합니다.
이를 통해 CHSH는 장치 전체를 아우르는 얽힘 품질 벤치마크로 기능하게 됩니다. 즉, 개별적으로 선별된 단일 쌍이 아닌, 칩의 상당 부분에 걸쳐 얽힘을 한 번에 테스트하며, 모든 쌍이 인접 쌍의 크로스톡 및 병렬 게이트 오류와 경쟁하는 현실적인 조건 하에서 수행됩니다. 모든 쌍에 대해 불평등 조건을 동시에 위반하는 것은 장치의 모든 곳에서 진정한 얽힘이 존재함을 입증한다.
# -------------------------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)
희미한 곡선들은 개별 벨 쌍을 나타내며, 굵은 곡선들은 장치 전체에 걸친 이들의 평균값을 나타냅니다. 모든 쌍은 양자역학이 예측한 것과 동일한 사인 곡선을 그리며, 희미한 곡선들 사이의 편차는 쌍마다 다른 잡음의 변동을 반영한다. 곡선이 회색 띠 영역에 들어가는 지점마다, 그 곡선은 의 고전적 경계를 넘어선 것이며, 인쇄된 요약본을 보면 사실상 모든 쌍이 동시에 CHSH 부등식을 위반한다는 사실이 확인된다.
피크는 소자 잡음으로 인해 치렐슨 상한 에는 미치지 못하지만, 결론은 분명하다. 즉, 백엔드는 단순히 미리 선정된 한 쌍의 입자뿐만 아니라 칩 전체에 걸쳐 동시에 진정한 얽힘 상태를 유지한다는 것이다. CHSH 실험이 “확장”되는 것은 바로 이러한 의미에서입니다. 즉, 하나의 더 큰 회로가 아니라, 모든 곳에서 동시에 얽힘을 검증하는 병렬 벤치마크로서 확장되는 것입니다.
다음 단계
이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:
- 실전 얽힘 : 존 왓루스가 진행하는 벨 상태와 CHSH 게임에 관한 강의.
- Estimator 기본 요소 시작하기 : PUB 및 매개변수 스윕에 대한 가이드.
- 큐비트 선별을 위한 실시간 벤치마킹 : 장치 전반에 걸쳐 큐비트 및 얽힘의 품질을 평가하는 또 다른 방법.
SparsePauliOpAPI 참조.