อสมการ CHSH
ประมาณการการใช้งาน: สองนาทีบนโปรเซสเซอร์ Heron r3 (หมายเหตุ: นี่เป็นเพียงการประมาณการ ระยะเวลาจริงอาจแตกต่างกัน)
ผลลัพธ์การเรียนรู้
หลังจากเรียนจบบทแนะนำนี้ คุณจะเข้าใจข้อมูลต่อไปนี้:
- วิธีสร้าง Bell-state CHSH Circuit ที่มีพารามิเตอร์และวัดค่าความคาดหวังสี่ค่าที่ประกอบเป็น CHSH witnesses
- วิธีคำนวณค่าความคาดหวังของ Observable หลายตัวบนการกวาดพารามิเตอร์ด้วยการเรียก
EstimatorV2primitive เพียงครั้งเดียว - วิธีตรวจสอบความถูกต้องของ quantum workflow บน noisy local simulator ด้วย
AerSimulator.from_backendก่อนส่งไปยังฮาร์ดแวร์ - วิธีขยายขนาดการทดลอง CHSH ให้เป็น benchmark การพัวพันครอบคลุมทั้งอุปกรณ์โดยการรัน Bell pairs อิสระจำนวนมากแบบขนานบนฮาร์ดแวร์ IBM Quantum®
ข้อกำหนดเบื้องต้น
แนะนำให้ทำความคุ้นเคยกับหัวข้อเหล่านี้ก่อน:
- Entanglement in action บทเรียนในคอร์สเกี่ยวกับ Bell states และเกม CHSH
SparsePauliOpและ บทนำ ของ Qiskit primitives
พื้นหลัง
ในบทแนะนำนี้ คุณจะรันการทดลองบนคอมพิวเตอร์ควอนตัมเพื่อแสดงให้เห็นการละเมิดอสมการ CHSH ด้วย Estimator primitive
อสมการ CHSH ซึ่งตั้งชื่อตาม Clauser, Horne, Shimony และ Holt ถูกใช้เพื่อทดสอบทฤษฎีบทของเบลล์เชิงทดลอง (ค.ศ. 1969) ทฤษฎีบทนี้ยืนยันว่าทฤษฎีตัวแปรซ่อนเร้นเฉพาะที่ไม่สามารถอธิบายผลที่ตามมาบางประการของการพัวพันในกลศาสตร์ควอนตัมได้ การแสดงให้เห็นการละเมิดอสมการ CHSH พิสูจน์ว่ากลศาสตร์ควอนตัมไม่สอดคล้องกับทฤษฎีตัวแปรซ่อนเร้นเฉพาะที่ ซึ่งเป็นการทดลองที่สำคัญในการทำความเข้าใจรากฐานของกลศาสตร์ควอนตัม
รางวัลโนเบลสาขาฟิสิกส์ปี 2022 มอบให้แก่ Alain Aspect, John Clauser และ Anton Zeilinger ส่วนหนึ่งเนื่องจากผลงานบุกเบิกของพวกเขาในสาขาวิทยาศาสตร์สารสนเทศควอนตัม และโดยเฉพาะอย่างยิ่งสำหรับการทดลองด้วยโฟตอนที่พัวพันกันซึ่งแสดงให้เห็นการละเมิดอสมการของเบลล์
สำหรับการทดลองนี้ เราจะสร้างคู่ที่พัวพันกันซึ่งเราวัด Qubit แต่ละตัวบนสองฐานที่แตกต่างกัน เราจะกำหนดชื่อฐานสำหรับ Qubit แรกว่า และ และฐานสำหรับ Qubit ที่สองว่า และ ซึ่งช่วยให้เราคำนวณปริมาณ CHSH ได้:
Observable แต่ละตัวมีค่าเป็น หรือ เห็นได้ชัดว่าหนึ่งในเทอม ต้องเป็น และอีกเทอมต้องเป็น ดังนั้น ค่าเฉลี่ยของ ต้องเป็นไปตามอสมการ:
การกระจาย ในรูปของ , , และ ให้ผลลัพธ์:
คุณสามารถกำหนดปริมาณ CHSH อีกค่าหนึ่งคือ :
ซึ่งนำไปสู่อสมการอีกข้อหนึ่ง:
หากกลศาสตร์ควอนตัมสามารถอธิบายได้ด้วยทฤษฎีตัวแปรซ่อนเร้นเฉพาะที่ อสมการเหล่านี้จะต้องเป็นจริงเสมอ ดังที่แสดงในบทแนะนำนี้ อสมการเหล่านี้สามารถถูกละเมิดได้ในคอมพิวเตอร์ควอนตัม ดังนั้นกลศาสตร์ควอนตัมจึงไม่สอดคล้องกับทฤษฎีตัวแปรซ่อนเร้นเฉพาะที่
เราสร้างคู่ที่พัวพันกันโดยเตรียมสถานะเบลล์ โดยใช้ Estimator primitive เราได้ค่าความคาดหวัง และ โดยตรง โดยไม่ต้องสร้างขึ้นมาจากผลนับดิบ เราวัด Qubit ที่สองในฐาน และ ส่วน Qubit แรกวัดในฐานตั้งฉากเช่นกัน แต่มีมุมการหมุน ที่เรากวาดระหว่าง ถึง Estimator primitive ประเมินการกวาดพารามิเตอร์นี้ใน primitive unified bloc (PUB) เพียงครั้งเดียว
ข้อกำหนด
ก่อนเริ่มบทแนะนำนี้ ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งสิ่งต่อไปนี้แล้ว:
- Qiskit SDK v2.0 หรือใหม่กว่า พร้อมรองรับ visualization
- Qiskit Runtime v0.40 หรือใหม่กว่า (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 หรือใหม่กว่า (
pip install qiskit-aer)
ตั้งค่า
# 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'
ตัวอย่างบน simulator ขนาดเล็ก
ก่อนส่งงานไปยังฮาร์ดแวร์ เราตรวจสอบความถูกต้องของ workflow ทั้งหมดบน local noisy simulator เราใช้ AerSimulator.from_backend(backend) เพื่อสร้าง simulator ที่รับ noise model และ coupling map จาก backend ที่คุณเลือก เพื่อให้การตอบสนองของ simulator มีลักษณะใกล้เคียงกับที่คาดหวังจากฮาร์ดแวร์
ขั้นตอนที่ 1: แปลงอินพุตแบบคลาสสิกเป็นปัญหาควอนตัม
เราเขียน CHSH Circuit ที่มีพารามิเตอร์ เพียงตัวเดียว ซึ่งกวาดฐานการวัดของ Qubit แรก Estimator primitive ช่วยลดความซับซ้อนของการวิเคราะห์: มันส่งคืนค่าความคาดหวังของ Observable โดยตรง และสามารถประเมิน Circuit ที่มีพารามิเตอร์ที่ค่าพารามิเตอร์หลายค่าในการเรียกครั้งเดียว
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")
ต่อไป เราสร้างรายการค่าเฟส 21 ค่าในช่วง ถึง เพื่อประเมิน Circuit ที่มีพารามิเตอร์ (, , , ..., , )
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]
สุดท้าย เรากำหนด Observable Qubit แรกวัดตามแกนที่หมุนด้วย ; Qubit ที่สองวัดใน และ ด้วยตัวเลือกเหล่านั้น ตัวสหสัมพันธ์ CHSH ทั้งสี่ตัวสอดคล้องกับตัวดำเนินการ Pauli , , และ :
# <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 primitives รับเฉพาะ Circuit และ Observable ที่สอดคล้องกับคำสั่งและการเชื่อมต่อที่รองรับโดยระบบเป้าหมาย (instruction set architecture หรือ ISA, circuits และ observables) เราสร้าง AerSimulator จาก backend และ transpile กับ target ของ simulator เพื่อให้ pass manager ถูกใช้งานตั้งแต่ต้นจนจบ
# 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")
เรายังแปลง Observable ให้ตรงกับ qubit layout ของ Circuit ที่ผ่านการ transpile โดยใช้ 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
รันการกวาดพารามิเตอร์ด้วย EstimatorV2 ในโหมด aer_sim เมธอด run() ของ Estimator รับ iterable ของ PUBs แต่ละ PUB มีรูปแบบ (circuit, observables, parameter_values, precision) เราส่ง Observable ทั้งสองพร้อมกันเพื่อให้ใช้การกวาดพารามิเตอร์เดียวกัน
# 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 ส่งคืนค่าความคาดหวังสำหรับ Observable ทั้งสองตัว เราพล็อตเทียบกับ พร้อมกับขอบเขตคลาสสิก () และขอบเขต Tsirelson () พื้นที่สีเทาแสดงช่องว่างระหว่างสองค่า จุดที่อยู่ในแถบเหล่านี้ละเมิดอสมการ 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)",
)
CHSH witnesses ของ simulator เกินขอบเขตคลาสสิก ที่ค่า หลายค่าแล้ว แม้จะมี noise model ของ backend ยอดสูงสุดตกลงมาก่อนถึงขอบเขต Tsirelson เนื่องจาก device noise ที่จำลองขึ้น เมื่อ workflow ผ่านการตรวจสอบแล้ว เราก็พร้อมไปยังฮาร์ดแวร์จริง
ตัวอย่างบนฮาร์ดแวร์ขนาดใหญ่
การทดสอบ CHSH เป็นการทดลองที่ใช้ สอง Qubit โดยเนื้อแท้ ดังนั้นจึงไม่ขยายขนาดด้วยการทำ Circuit ใหญ่ขึ้น แต่ขยายขนาดโดยการรันการทดสอบหลายครั้งแบบขนาน ที่นี่เราวาง Bell pairs อิสระให้มากที่สุดเท่าที่ connectivity ของ backend อนุญาต (การ matching ของ coupling map) และรัน CHSH sub-circuit อิสระบนทุกคู่ ทั้งหมดในงานเดียว
นี่จะเปลี่ยน CHSH ให้เป็น benchmark คุณภาพการพัวพันครอบคลุมทั้งอุปกรณ์: แทนที่จะเป็นคู่ที่เลือกมือเดียว เราทดสอบการพัวพันทั่วส่วนใหญ่ของชิปพร้อมกัน ภายใต้สภาพจริงที่แต่ละคู่ต้องแข่งขันกับ crosstalk ของเพื่อนบ้านและข้อผิดพลาดจาก Gate แบบขนาน การละเมิดอสมการบนทุกคู่ พร้อมกัน รับรองว่าการพัวพันที่แท้จริงมีอยู่ทั่วทั้งอุปกรณ์
# -------------------------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)

เส้นจางๆ คือ Bell pairs แต่ละคู่ และเส้นหนาคือค่าเฉลี่ยของทุกคู่ทั่วทั้งอุปกรณ์ ทุกคู่ติดตาม sinusoid เดียวกันที่กลศาสตร์ควอนตัมทำนายไว้ และการกระจายระหว่างเส้นจางสะท้อนถึงความแปรปรวนของ noise ในแต่ละคู่ เมื่อใดก็ตามที่เส้นเข้าสู่แถบสีเทา เส้นนั้นได้ข้ามขอบเขตคลาสสิก และสรุปที่พิมพ์ออกมายืนยันว่าแทบทุกคู่ละเมิดอสมการ CHSH พร้อมกัน
ยอดสูงสุดตกลงมาก่อนถึงขอบเขต Tsirelson เนื่องจาก device noise แต่ข้อสรุปนั้นชัดเจน: backend รักษาการพัวพันที่แท้จริงทั่วทั้งชิปพร้อมกัน ไม่ใช่แค่บนคู่ที่เลือกมือเดียว นี่คือความหมายที่การทดลอง CHSH "ขยายขนาด": ไม่ใช่ในรูป Circuit ที่ใหญ่ขึ้น แต่เป็น benchmark แบบขนานที่รับรองการพัวพันในทุกที่พร้อมกัน
ขั้นตอนถัดไป
หากคุณพบว่าเนื้อหานี้น่าสนใจ คุณอาจสนใจเนื้อหาต่อไปนี้:
- Entanglement in action: บทเรียนในคอร์สโดย John Watrous เกี่ยวกับ Bell states และเกม CHSH
- Get started with the Estimator primitive: คู่มือเกี่ยวกับ PUBs และการกวาดพารามิเตอร์
- Real-time benchmarking for qubit selection: อีกวิธีในการประเมินคุณภาพ Qubit และการพัวพันทั่วทั้งอุปกรณ์
SparsePauliOpAPI reference