본문 바로가기

Quantum Computing

Qiskit을 이용한 양자 컴퓨팅 예제 (1) - 파울리 게이트(Pauli Gate)

반응형

이번 포스팅에서는 양자 컴퓨팅에서 가장 기본적인 게이트 중 하나인 파울리 게이트 (Pauli Gates)에 대해 알아보겠습니다.

 

양자 컴퓨터란 무엇인가?

양자 컴퓨터는 "큐비트(Qubit)"라는 단위를 정보의 기본 단위로 사용합니다. 고전 컴퓨터의 비트(Bit)는 0 또는 1의 값을 가지지만, 큐비트는 "양자 중첩(Superposition)"을 통해 0과 1의 상태를 동시에 가질 수 있습니다. 이러한 특성으로 인해 양자 컴퓨팅은 복잡한 문제에 대해서 빠른 계산을 수행할 수 있습니다. 

Qiskit 설치

양자 컴퓨팅에 대한 알고리즘을 개발하기 위해 다양한 프레임워크가 존재합니다. 그 중에서도 Qiskit은 IBM 에서 개발한 오픈소스 양자 컴퓨팅 프레임워크로, 양자 알고리즘을 설계하고, 시뮬레이션하며, 실제 양자 하드웨어에서 실행할 수 있도록 지원합니다. Python을 기반으로 하며, 양자 컴퓨팅의 학습, 연구, 실험에 널리 사용됩니다. Python을 기반으로 하기 때문에 Qiskit은 아래와 같이 간단하게 pip install을 통해 설치할 수 있습니다:

pip install qiskit

 

양자 컴퓨팅을 시뮬레이션하기 위해 Qiskit Aer도 아래와 같이 설치해 줍니다:

pip install qiskit-aer

 

출력한 결과들은 시각화하기 위한 도구로 pylatexenc도 설치해 줍니다:

pip install pylatexenc

 

자, 그럼 파울리 게이트에 대한 설명과 함께 예제를 실행해 보겠습니다:

 

파울리 게이트

양자 컴퓨터에서 큐비트의 상태를 조작하기 위해 양자 게이트를 사용합니다. 이 중 파울리 게이트는 가장 기본적인 단일 큐비트 게이트로, 큐비트의 상태를 반전하거나 회전하는 연산을 수행합니다. 파울리 게이트는 아래와 같이 Pauli-X, Pauli-Y, Pauli-Z 등 세 가지 종류로 나뉩니다: 

 

Pauli-X 게이트 (양자 NOT 게이트)

Pauli-X 게이트 연산자는 아래와 같이 행렬로 표현이 가능합니다.

\begin{eqnarray} {\pmb X} = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}\end{eqnarray}

그럼 일반적으로 $|0\rangle$과 $|1\rangle$ 상태가 아래와 같은 행렬로 표현이 가능하므로,

\begin{eqnarray} |0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix}, \ \ \ |1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix} \end{eqnarray}

X 연산자는 아래와 같은 결과를 줍니다:

$$ {\pmb X} | 0 \rangle = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 0 \\ 1 \end{pmatrix} = | 1\rangle.$$

혹은

$$ {\pmb X} | 1 \rangle = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} 0 \\ 1 \end{pmatrix} = \begin{pmatrix} 1 \\ 0 \end{pmatrix} = | 0 \rangle.$$

즉, X-게이트는 주어진 큐비트의 상태를 뒤집는 역할을 합니다.

 

이것을 Qiskit을 통해 구현해 보겠습니다.

from qiskit import QuantumCircuit

# 1. 양자 회로 생성
qc = QuantumCircuit(1) # 1개의 큐비트 생성

# 2. Pauli-X 게이트 적용
qc.x(0)

print(qc)

 

"QuantumCircuit" 함수는 큐비트를 생성하는 함수입니다. "QuantumCircuit(1)"은 1개의 큐비트를 생성하겠다는 것을 의미하며, 이는 $|0\rangle$ 상태를 만들어 줍니다. 생성된 큐비트는 0번, 1번, 2번 등의 번호를 갖습니다. 따라서, 우리는 0번이라는 번호를 갖는 큐비트 하나를 생성한 것입니다.

 

그럼 "qc.x(0)"라는 명령어를 통해 우리가 만들어낸 "qc"의 0번 큐비트에 X-게이트를 적용할 수 있습니다. 위의 코드를 조금 더 구체화 해보겠습니다.

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
 
# 1. 양자 회로 생성
qc = QuantumCircuit(1)  # 1개의 큐비트 생성
 
# 2. Pauli-X 게이트 적용
qc.x(0)  # 첫 번째 큐비트를 |1⟩ 상태로 변환
 
# 3. 상태 벡터 저장
qc.save_statevector()

# 3. 시뮬레이터 초기화
simulator = AerSimulator()
 
# 4. 회로 컴파일 및 실행
compiled_circuit = transpile(qc, simulator)
result = simulator.run(compiled_circuit).result()
 
# 5. 상태 벡터 확인
statevector = result.get_statevector()
print("Statevector:", statevector)

 

이 코드는 "큐비트 1개 생성 -> X-게이트 적용 -> 이에 대한 상태 벡터 저장 -> 시뮬레이터 초기화 -> 컴파일 및 회로 실행 -> 상태 벡터 확인" 등의 과정을 거칩니다. 이 코드에 대한 결과값은 아래와 같이 주어집니다:

Statevector: Statevector([0.+0.j, 1.+0.j],
            dims=(2,))

예상한 것처럼 $|0\rangle$의 상태가 X-게이트로 인해 $|1\rangle$ 상태로 변화한 것을 볼 수 있습니다. 

 

그럼 이번에는 X 게이트를 두 번 적용해 보겠습니다. 

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
 
# 1. 양자 회로 생성
qc = QuantumCircuit(1)  # 1개의 큐비트 생성
 
# 2. Pauli-X 게이트 2번 적용
qc.x(0)  # 첫 번째 큐비트를 |1⟩ 상태로 변환
qc.x(0)  # 변환된 큐비트에 X 연산자를 한 번 더 적용

# 3. 상태 벡터 저장
qc.save_statevector()

# 3. 시뮬레이터 초기화
simulator = AerSimulator()
 
# 4. 회로 컴파일 및 실행
compiled_circuit = transpile(qc, simulator)
result = simulator.run(compiled_circuit).result()
 
# 5. 상태 벡터 확인
statevector = result.get_statevector()
print("Statevector:", statevector)

 

이 코드에 대한 실행값은 아래와 같이 $|1\rangle$ 상태를 줍니다:

Statevector: Statevector([1.+0.j, 0.+0.j],
            dims=(2,))

 

 

Pauli-Y 게이트

Pauli-Y 게이트는 아래와 같이 행렬로 표현됩니다:

\begin{eqnarray} {\pmb Y} = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix} \end{eqnarray}

이러한 Y 게이트는 주어진 큐비트를 아래와 같이 변화한합니다:

\begin{eqnarray} {\pmb Y} |0\rangle = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \end{pmatrix} = i \begin{pmatrix} 0 \\ 1 \end{pmatrix} = i  |1 \rangle   \end{eqnarray}

또는 

\begin{eqnarray} {\pmb Y} |1\rangle = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix} \begin{pmatrix} 0 \\ 1 \end{pmatrix} = -i \begin{pmatrix} 1 \\ 0 \end{pmatrix} = -i  |0 \rangle   \end{eqnarray}

즉, Y 게이트는 큐비트를 x-y 평면에서 180도 회전하며, 회전을 통해 위상을 변화시키는 역할을 합니다. 

 

Y 게이트를 입력하는 명령어는 "큐빗변수.y(큐빗 넘버)"입니다. 따라서, 위에 코드에서 "qc.x(0)"를 "qc.y(0)"로 바꿔주면, Y 연산자를 생성된 큐비트에 적용할 수 있습니다. 출력 결과는 아래와 같습니다:

Statevector: Statevector([0.-0.j, 0.+1.j],
            dims=(2,))

$|0\rangle$ 상태가 $i|1\rangle$ 상태로 변환한 것을 알 수 있습니다.

 

Pauli-Z 게이트

파울리 Z 연산자는 아래와 같이 행렬로 표현됩니다:

\begin{eqnarray} {\pmb Z} = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix} \end{eqnarray}

이러한 연산자는 주어진 상태에 대해서 아래와 같은 결과를 줍니다:

\begin{eqnarray} {\pmb Z} |0 \rangle = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix} \begin{pmatrix} 1 \\ 0\end{pmatrix}  = \begin{pmatrix} 1 \\ 0 \end{pmatrix} = | 0 \rangle \end{eqnarray}

\begin{eqnarray} {\pmb Z} |1 \rangle = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix} \begin{pmatrix} 0 \\ 1 \end{pmatrix}  = - \begin{pmatrix} 1 \\ 0 \end{pmatrix} = - | 1 \rangle \end{eqnarray}

즉, $|0\rangle$ 상태는 변환하지 않는 반면, $| 1 \rangle$ 상태는 위상을 -1 만큼 변화시킵니다. 

 

Z 게이트는 위에 주어진 코드에서 "큐빗변수.z(큐빗 넘버)" 명령어를 통해 적용해볼 수 있습니다. ("qc.z(0)" 명령어를 이용해 위 코드에서 그 결과값을 확인해보시기 바랍니다.) 

 

결국 이러한 게이트 들은 양자 회로를 구성하는 데 기본 블럭같은 역할을 합니다. 이러한 게이트들을 조합해 풀고 싶은 문제에 대한 복잡한 회로들을 구성할 수 있습니다. 

반응형