Lab 3. VQE 최적화와 Bell 상태
실습 실행: Google Colab에서 바로 실행
학습 목표
- 변분 양자 알고리즘(VQE)의 최적화 과정을 이해한다
- cos(θ)의 최솟값을 양자 회로로 찾는 과정을 관찰한다
- Bell 상태를 생성하고 얽힘의 특징을 측정으로 확인한다
핵심 개념
VQE (Variational Quantum Eigensolver)
양자 회로의 파라미터 θ를 조정하여 기댓값 ⟨Z⟩ = cos(θ)를 최소화한다. cos(θ)의 최솟값은 θ = π일 때 -1이다. 옵티마이저가 gradient를 따라 θ를 π로 이동시키는 과정이 VQE의 핵심이다.
Bell 상태와 얽힘
Hadamard + CNOT으로 만든 Bell 상태 \(|\Phi^+\rangle = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)\)는 두 큐비트가 완전히 상관된 상태이다. 측정하면 반드시 |00⟩ 또는 |11⟩만 나오고, |01⟩이나 |10⟩은 나오지 않는다.
VQE 문제 정의
RX(θ) 회로에서 ⟨Z⟩ = cos(θ)이다. 이 값을 최소화하는 θ를 옵티마이저가 자동으로 찾게 한다. 정답은 θ = π (cos(π) = -1)이다.
VQE 회로와 최적화
dev1 = qml.device("default.qubit", wires=1)
@qml.qnode(dev1)
def vqe_cost(params):
qml.RX(params[0], wires=0)
return qml.expval(qml.PauliZ(0))
opt = qml.GradientDescentOptimizer(stepsize=0.4)
params = np.array([0.5], requires_grad=True)
history = []
for step in range(50):
params = opt.step(vqe_cost, params)
cost = float(vqe_cost(params))
history.append(cost)
VQE 시각화: 수렴 과정

해석
초기값 θ = 0.5에서 출발하여, gradient descent가 cos(θ)의 기울기를 따라 θ를 π 방향으로 이동시킨다. 약 30 step 이후 ⟨Z⟩ ≈ -1에 수렴한다. 이것이 VQE의 기본 원리이며, 실제 응용에서는 cos(θ) 대신 분자의 에너지를 최소화한다.
| step | θ | ⟨Z⟩ |
|---|---|---|
| 0 | 0.5 | ~0.88 |
| 20 | ~2.8 | ~-0.94 |
| 50 | ~3.14 | ~-1.00 |
Bell 상태 회로 정의
Hadamard로 큐비트 0을 중첩시킨 뒤, CNOT으로 큐비트 1과 얽는다.
dev2 = qml.device("default.qubit", wires=2)
@qml.qnode(dev2)
def bell_probs():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.probs(wires=[0, 1])
@qml.qnode(dev2)
def bell_corr():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return (
qml.expval(qml.PauliZ(0)),
qml.expval(qml.PauliZ(1)),
qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)),
)
@qml.qnode(dev2)
def bell_sample():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.sample(wires=[0, 1])
Bell 회로 시각화

해석적 확률과 상관관계
| 상태 | 확률 | 의미 |
|---|---|---|
| |00⟩ | 0.5 | 둘 다 0 |
| |01⟩ | 0.0 | 불가능 |
| |10⟩ | 0.0 | 불가능 |
| |11⟩ | 0.5 | 둘 다 1 |
⟨Z₀⟩ = 0, ⟨Z₁⟩ = 0이지만 ⟨Z₀Z₁⟩ = 1이다. 개별 큐비트는 무작위(50:50)이지만, 두 큐비트를 함께 보면 항상 같은 값이 나온다. 이것이 얽힘의 핵심이다.
샘플링 측정
Bell 시각화: 측정 결과

|00⟩과 |11⟩만 관측된다. |01⟩과 |10⟩의 막대는 0이다. 정확히 50:50이 아닌 이유는 유한 샘플링에 의한 통계 변동이며, shots를 늘리면 50:50에 수렴한다.
과제 1: VQE 초기값 변경
VQE의 초기 파라미터를 params = np.array([3.0])으로 변경하라. π에 가까운 값에서 출발하면 수렴이 더 빠른가?
# 학생 수정: params = np.array([3.0], requires_grad=True)
# 재실행 후 수렴 속도 비교
과제 2: stepsize 비교
VQE의 stepsize를 0.1과 0.8로 각각 실행하라. 0.1은 느리지만 안정적이고, 0.8은 빠르지만 진동할 수 있다.
# 학생 수정: opt = qml.GradientDescentOptimizer(stepsize=0.1)
# 다시: opt = qml.GradientDescentOptimizer(stepsize=0.8)
# 두 학습 곡선을 비교하라
과제 3: Bell 상태 shots 비교
shots를 100과 10000으로 각각 실행하라. |01⟩이나 |10⟩이 0회인지 확인하라. shots=100에서도 이 두 상태는 절대 나오지 않는다. 왜 그런가?
# 학생 수정: shots = 100 으로 변경 후 재실행
# 다시 shots = 10000 으로 변경 후 재실행
# |01>과 |10>이 0회인 이유를 생각하라
힌트: |01⟩과 |10⟩의 확률이 정확히 0이기 때문이다. shots를 아무리 늘려도 확률 0인 상태는 나오지 않는다. 이것은 Lab 2의 probs에서 본 "확률이 0이 아닌 상태"만 sample에서 관측되는 것과 같은 원리이다.