Lab 2. 양자 측정 — probs, sample, expval
실습 실행: Google Colab에서 바로 실행
학습 목표
qml.probs(),qml.sample(),qml.expval()세 가지 측정 방식의 차이를 이해한다- shots 수에 따라 샘플 비율이 이론 확률에 수렴하는 과정을 확인한다
- 기댓값 \(\langle Z \rangle = \cos(\theta)\)가 샘플 평균과 같음을 검증한다
환경 설정
Colab에서 최초 1회 실행한다.
!pip install pennylane koreanize_matplotlib -q
라이브러리를 import한다.
import pennylane as qml
import numpy as np
import matplotlib.pyplot as plt
import koreanize_matplotlib
plt.rcParams['axes.unicode_minus'] = False
수정 구간
# ===== 수정 =====
theta = np.pi / 4
# 추천값:
# pi/6 → P(|0>) 매우 높음, 거의 |0> 상태
# pi/4 → 중간 중첩, expval = 0.707
# pi/2 → 완전 중첩, P(|0>)=P(|1>)=0.5, expval = 0
# pi → 완전히 |1> 상태, expval = -1
shots = 1024
# 추천값:
# 10 → 결과 불안정, probs와 큰 차이
# 100 → 어느 정도 수렴
# 1024 → 기본값, 안정적
# 10000 → 이론값에 거의 일치
# ===== 수정 끝 =====
회로 정의
3가지 측정 방식별로 회로를 정의한다. 회로 구조(RX 게이트)는 동일하고 측정만 다르다.
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev)
def circuit_probs(angle):
qml.RX(angle, wires=0)
return qml.probs(wires=0)
@qml.qnode(dev)
def circuit_sample(angle):
qml.RX(angle, wires=0)
return qml.sample(qml.PauliZ(0))
@qml.qnode(dev)
def circuit_expval(angle):
qml.RX(angle, wires=0)
return qml.expval(qml.PauliZ(0))
# PennyLane 0.44 권장: set_shots transform
circuit_probs_s = qml.set_shots(circuit_probs, shots=shots)
circuit_sample_s = qml.set_shots(circuit_sample, shots=shots)
circuit_expval_s = qml.set_shots(circuit_expval, shots=shots)
qml.set_shots는 PennyLane 0.44에서 shots를 회로에 적용하는 권장 방식이다.
확률 측정
양자 상태는 측정 전까지 |0⟩과 |1⟩의 중첩으로 존재한다. qml.probs()는 각 상태가 관측될 확률을 반환한다.
p = circuit_probs_s(theta)
p0_theory = np.cos(theta / 2) ** 2
p1_theory = np.sin(theta / 2) ** 2
print(f" P(|0>) = {p[0]:.4f} 이론: cos²(θ/2) = {p0_theory:.4f}")
print(f" P(|1>) = {p[1]:.4f} 이론: sin²(θ/2) = {p1_theory:.4f}")
시각화

해석
theta = pi/4일 때 P(|0>) ≈ 0.854, P(|1>) ≈ 0.146이다. 큐비트가 |0⟩에 가깝지만 |1⟩도 가능한 상태이다. 이 확률은 "측정하기 전"의 정보이며, 실제 측정하면 반드시 0 또는 1 중 하나로 collapse된다.
샘플링 실행
qml.sample()은 실제 양자컴퓨터처럼 매번 +1(|0⟩) 또는 -1(|1⟩) 중 하나를 반환한다. shots번 반복 측정한 결과를 배열로 받는다.
samples = circuit_sample_s(theta)
cnt_p1 = int(np.sum(samples == 1))
cnt_m1 = int(np.sum(samples == -1))
ratio_p1 = cnt_p1 / shots
print(f" +1(|0>) 횟수: {cnt_p1} 비율: {ratio_p1:.4f} probs P(|0>): {p[0]:.4f}")
print(f" -1(|1>) 횟수: {cnt_m1} 비율: {cnt_m1/shots:.4f} probs P(|1>): {p[1]:.4f}")
시각화 1: 개별 측정 결과
처음 50번의 측정 결과를 막대로 표시한다. +1(파랑)과 -1(빨강)이 무작위로 나타난다.

시각화 2: sample 비율 vs probs 비교
sample의 비율이 probs의 이론 확률에 수렴하는지 확인한다.

해석
매 측정은 +1 또는 -1 중 하나만 나온다. 이것이 양자 측정의 "collapse"이다. 하지만 충분히 많이 반복하면(shots↑), +1이 나온 비율은 P(|0⟩)에, -1이 나온 비율은 P(|1⟩)에 수렴한다. shots=10이면 비율이 크게 벗어나고, shots=10000이면 거의 일치한다.
기댓값 측정
qml.expval()은 sample 결과의 평균이다. +1과 -1의 가중 평균이 cos(θ)와 일치하는지 검증한다.
ev = float(circuit_expval_s(theta))
ev_theory = np.cos(theta)
시각화: cos(θ) 곡선 위에 회로 결과 표시

3단계 연결
| 단계 | 측정 | theta=pi/4 결과 | 의미 |
|---|---|---|---|
| 1 | probs | [0.854, 0.146] | 측정 전 확률분포 |
| 2 | sample | +1, -1, +1, +1, ... | 측정 순간 collapse |
| 3 | expval | 0.707 | sample의 평균 = cos(θ) |
probs → sample → expval 순서는 "확률 → 실현 → 통계"의 흐름이다. 양자컴퓨터에서는 probs를 직접 볼 수 없고, sample을 반복해서 probs와 expval을 추정한다.
과제 1: theta = pi/2 (완전 중첩)
theta를 pi/2로 변경하고 전체를 다시 실행하라. P(|0⟩) = P(|1⟩) = 0.5가 되는지, expval이 0에 가까운지 확인하라.
# 수정: theta = np.pi / 2 로 변경 후 전체 재실행
과제 2: shots = 10 vs 10000
theta = pi/4를 유지하고, shots를 10과 10000으로 각각 실행하라. 2-2의 "sample 비율 vs probs 비교" 그래프에서 차이가 얼마나 나는지 관찰하라.
# 수정: shots = 10 으로 변경 후 재실행
# 다시 shots = 10000 으로 변경 후 재실행
# 두 결과를 비교하라
과제 3: 3단계 관계 검증
sample 결과에서 직접 평균을 계산하여 expval과 같은 값이 나오는지 확인하라.
세 값이 유사하면, sample의 평균 = expval = cos(θ)라는 관계가 성립하는 것이다.