

2개의 큐비트로부터 얻어지는 4개의 양자 상태 |00>, |01>, |10>, |11> 을 대상으로 그 중 하나를 찾아내기 위한 문제를 고려하자. 양자 상태의 순서는 임의로 섞어 순서가 바뀌어도 된다. 예로서 |01>을 검색하여 찾기로 하자.
4개의 객체를 대상으로 하는 아주 간단한 문제이지만 아직 양자 컴퓨터의 큐비트 수가 최근 100 개 단위로 증강된 상태이지만 2026년 초 현재 큐비트 3개 이상의 양자 컴퓨터는 오차 교정의 신뢰성 문제가 기술적으로 완전히 해결되지 못한 상태이기 때문에 과거 20년에 걸쳐 기본적으로 잘 연구 개발된 Transmon 2개를 사용한 예제를 검토하기로 gkau, 하며, 여기에서 기본적인 양자 게이트로 볼 수 있는 파울리 X 게이트, 아다마르 게이트 H, 제어 Z 게이트가 집중적으로 사용된다.
일단 인공지는 Gemini 에게 다음과 같이 Prompt를 입력하여 샘플 코드를 작성시키자.
Prompt: "Grover algorithm 과 code 를 설명해주세요
작성된 코드는 Colab 에서 잘 작동하지만 각각의 명령 한줄마다 실행 전 과 후 큐비트 상태를 일일히 확인할 필요가 있어서 그 내용을 오른쪽 쏠림 내용으,로 채웠다. 과거 1980녀대 초 8080 one board computer 어셈블리 코드 작성 입력 만큼 까다로웠다. 독자분이 이 코드를 잘 이해하셨다면 이미 양자 컴퓨팅 프로그래밍 1/3 정도는 이해하셨다고 자부심을 가져도 될 것 같습니다.
리눅스 기반 Colab에서 qiskit, qiskit-aer, matplotlib 라이브러리 패키지를 설치 후 코드를 실행시키자. Colab 에서 코드를 작성하는 이유는 IBM 에서 제공하는 오픈소스 Qiskit 라이브러리가 자주 업데이트 되므로 Anaconda 3 의 Spyder 나 PyCharm을 사용할 경우 라입ㅡ러리 제거 및 설치를 반복해야 하는 번거로움을 피하기 위함이다.
!pip install qiskit
!pip install qiskit-aer matplotlib
단계 1: 초기화
from qiskit import QuantumCircuit, Aer, execute
qc = QuantumCircuit(2) # 1. 회로 초기화 (2 큐비트)
qc.h([0, 1]) # range(2) 는 [0,1] -> 0번과 1번 큐비트 모두에 Hadamard 연산 실행
일반적으로 Transmon을 2개 사용하여 양자 회로를 처음 생성하면
즉 어떤 양자 게이트 명령 실행 전 모든 큐비트는 |0> 상태로 초기화된다.

qc.h([0, 1]) 명령처럼 큐비트 0 과 큐비트 1에 각각 텐서 곱 형태에 대해서
아다마르 연산을 실행하면 다음과 같이 중첩된 큐비트 상태가 된다.

# -- 단계 2: 오라클 (Oracle) -- 정답을 |01>로 만들기 위해 qc.x(1)을 사용한다.
qc.x(1) # 1번 큐비트가 0일 때 작동하도록 반전
qc.x(1) 실행 이전 즉 아다마르 명령을 실행한 직후의 중첩 상태는 다음과 같다.

qc.x(1) 실행 이후에는 1번 큐비트 자리의 값이 0->1 또는 1->0 으로 반대로 바뀐다.

qc.cz(0, 1) # Controlled-Z로 부호 반전
qc.cz(0, 1) 명령 실행 후에는 cz gate 는 2개의 큐비트로
구성된 Transmon에서 큐비트 모두가 1이면
큐비트 상태의 부호 반전(Phase flip)이 일어난다.

음의 부호를 가지는 양자 상태가 나타나도 확률 파동 함수의 진폭은
제곱하여 계산되므로 4개의 양자 상태는 결국 25% 확률값을 갖는다.
하지만 이 음(–)의 부호는 Diffusion 과정에서 중요한 역할을 한다.
qc.x(1) # 다시 원상복구
다시 qc.x(1) 을 실행하게 되면
다시 1번 큐비트의 값을 반전시킨다. (0 ↔ 1)

두 번째 |01> 의 부호가 반전된 qc.x(1) 을 다음과 같이 변형하자.

qc.h([0, 1]) 와 qc.x(1)을 비교하면 4개의 양자 상태는 동일하게 각 25% 확률값을 갖는다.
qc.x(1)을 연산의 편의를 위해서 다음과 같이 조작한다.
qc.x(1)=(1/2)(|00>+|01>+|10>+|11>)-|01>=|s>-|01>
# --- 단계 3: 확산 연산자 (Diffusion) --- 평균에 대한 반전을 수행.
qc.h([0, 1])
qc.h([0,1]) 은 2개의 그룹으로 묶은 후 텐서 곱 형태들에 대해 아다마르 연산을 적용한다.
앞부분은 H의 제곱을 적용하면 연산 결과는 |s> =|00> 이 된다. |01> 은 별도 처리하자

부호가 반전된 qc.x(1) 에 qc.h([0,1])을 적용하면
두 번째 |01> 과 세 번째 |10> 의 부호가 반전됨을 알 수 있다.
qc.x([0, 1]) # 여기서도 x 게이트를 사용하여 |00> 상태를 타겟팅-> |11>
다시 qc.x([0, 1])를 적용하면

|00> 이 |11> 로 바뀌었다.
qc.cz(0, 1)
qc.cz(0, 1)을 적용하면 첫 번째 |11>항의 부호가 반전된다.

qc.x([0, 1])
qc.x([0, 1]) 명령을 적용하면 결국 qc.h([0, 1]) 의 항들에서
첫 번째 |00> 항과 세 번째 |10> 항 부호가 반전되었다.

qc.h([0, 1])
마지막으로 qc.h([0, 1]) 연산을 수행하자.

|00>, |10>, |11> 의 진폭은 모두 0 이 되어 사라지고 |01>만 1 이 된다.
# 마지막 단계: 측정
qc.measure_all()
# 실행 및 결과 출력
backend = Aer.get_backend('qasm_simulator')
result = execute(qc, backend, shots=1024).result()
print(result.get_counts())
실행 결과는 다음과 같다.

# 회로출력

마지막으로 회로 출력 결과가 상당히 길어 보이는데 각 명령 전후로 큐비트 상태를 모니터링 했듯이 중간에 qc.draw() 명령을 사용하면 해당 부분의 회로를 관찰할 수 있다.
이 양자 회로의 이해를 돕기 위해서 가로형으로 출력된 회로와 각 회로별 명령에 따른 양자 상태를 다음 블로그에서 관찰해보자.
2 Qubits Grover algorithm Circuits, States, Logic Gate Command Table
https://ejleep1.tistory.com/1695
grover algorithm circuit 으로 Yahoo.com 애서 이미지 검색을 해보면 다양한 회로들을 볼 수 있을 것이다. 엇 비슷하긴 하지만 각각의 명령들을 어떻게 조합하느냐에 달려 있다.
첨부된 파일을 다운 받은 후 Colab 에 업로드 시켜 실행시켜 보자.
추가로 |01> 만이 아니라 |00>, |10>, |11> 이 정답인 경우 코드가 어떻게 바뀌어야 하는지 살펴보자. |01>을 찾는 현재의 코드에서 CZ({0, 1}) 전 후에 X(1) logic gate 명령이 사용되었다. 만약 |11>을 찾으려면 X(1)을 전후로 제거하면 되고, |10>을 찾으려면 X(1) 전후를 X(0) 으로 대체하면 되며, |00>을 찾으려면 X(1) 전후를 X([0, 1])로 대체하면 된다.
Under Construction
'양자컴퓨팅 알고리듬' 카테고리의 다른 글
| Grover Algorithm 3큐비트 8개의 양자 상태 |000>에서 |111> 까지 예제 (0) | 2026.02.03 |
|---|---|
| 양자 알고리듬 첫번째 관문: Deutsch–Jozsa algorithm (0) | 2026.01.08 |