콘텐츠로 이동

Lab 4. Angle Encoding과 CNOT

실습 실행: Google Colab에서 바로 실행

학습 목표

  • 고전 데이터를 양자 회로에 넣는 방법(Angle Encoding)을 이해한다
  • 스케일링 없이 인코딩하면 주기 반복 문제가 생기는 것을 확인한다
  • CNOT 게이트가 두 큐비트 사이에 상호작용을 만드는 것을 관찰한다

핵심 개념

Angle Encoding

데이터 값 x를 RY(x) 게이트의 각도로 사용한다. 출력은 ⟨Z⟩ = cos(x)이다.

\[ RY(x)|0\rangle \rightarrow \cos(x/2)|0\rangle + \sin(x/2)|1\rangle \]

문제는 cos()이 주기 함수라는 점이다. x=1과 x=1+2π는 같은 상태가 된다. 따라서 데이터를 [0, π] 범위로 스케일링해야 한다.

CNOT의 역할

CNOT 없이 RY(x₁) ⊗ RY(x₂)를 적용하면 두 큐비트는 독립이다. CNOT을 추가하면 확률분포가 재배치되면서 x₁과 x₂ 사이의 상호작용이 생긴다.

데이터 준비

홀수 수열(x₁)과 짝수 수열(x₂)을 사용한다. 범위가 1~100으로 넓어서 스케일링 문제를 직접 체감할 수 있다.

x1 = np.array([2*i + 1   for i in range(50)])   # 홀수: 1, 3, ..., 99
x2 = np.array([2*(i + 1) for i in range(50)])   # 짝수: 2, 4, ..., 100

홀수와 짝수 수열 데이터

Min-Max 스케일링

데이터를 [0, π] 범위로 변환하면, cos() 함수의 단조 감소 구간만 사용하게 된다.

시각화

스케일링 전후 기댓값 비교

해석

스케일링 후에는 x₁이 커질수록 ⟨Z⟩가 단조 감소한다. 주기 반복이 사라지고, 모든 데이터가 고유한 양자 상태로 매핑된다.

스케일링 x₁=1 x₁=99 패턴
없음 0.5403 -0.0390 주기 반복, 구별 불가
[0, π] ~1.0 ~-1.0 단조 감소, 구별 가능

scale_max를 2π로 바꾸면 주기 반복이 다시 나타난다. 이것은 학생 수정 구간에서 직접 확인할 수 있다.

회로 정의: CNOT 유무 비교

두 데이터(x₁, x₂)를 각각 큐비트 0, 1에 RY로 인코딩한다. CNOT이 없으면 두 큐비트는 독립이고, CNOT을 추가하면 상호작용이 생긴다.

회로 시각화

확률분포 비교

시각화

CNOT 유무에 따른 확률분포 비교

해석

CNOT 없이는 P(|00⟩) = P₀(0) × P₁(0)으로, 두 큐비트의 확률이 곱으로 분해된다. 독립적이다.

CNOT을 추가하면 확률이 재배치된다. 특정 상태의 확률이 올라가고 다른 상태는 내려간다. 이것이 "큐비트 간 상호작용"이며, IQP Embedding의 교차항(ZZ)과 같은 역할을 한다.

CNOT 없음 CNOT 있음
큐비트 관계 독립 (곱으로 분해) 상호작용 (재배치)
표현력 1차원 × 1차원 2차원 결합
QML 활용 불충분 feature 간 관계 포착

과제 1: scale_max = 2π

학생 수정 구간에서 scale_max = 2 * np.pi로 변경하고 4-2를 재실행하라. 단조 감소가 유지되는가, 주기 반복이 다시 나타나는가?

# 학생 수정: scale_max = 2 * np.pi
# 4-2 재실행 후 그래프 관찰

과제 2: idx_sample 변경

idx_sample을 0(가장 작은 값)과 49(가장 큰 값)로 각각 실행하라. CNOT의 효과가 데이터 값에 따라 달라지는가?

# 학생 수정: idx_sample = 0 으로 변경 후 4-3 재실행
# 다시: idx_sample = 49 로 변경 후 4-3 재실행
# CNOT 없음과 있음의 차이가 달라지는지 관찰

과제 3: CNOT 방향 반전

encode_with_cnot에서 CNOT의 방향을 [0, 1]에서 [1, 0]으로 바꾸면 확률분포가 달라지는가?

@qml.qnode(dev2)
def encode_cnot_reversed(x1_val, x2_val):
    qml.RY(x1_val, wires=0)
    qml.RY(x2_val, wires=1)
    qml.CNOT(wires=[1, 0])   # 방향 반전
    return qml.probs(wires=[0, 1])

p_rev = encode_cnot_reversed(x1_sc, x2_sc)
print(f"  CNOT [0→1]: {[f'{v:.3f}' for v in p_yes]}")
print(f"  CNOT [1→0]: {[f'{v:.3f}' for v in p_rev]}")

control 큐비트와 target 큐비트의 역할이 바뀌면 확률분포도 달라진다. "어느 큐비트가 다른 큐비트를 제어하는가"가 회로 설계의 중요한 선택이다.