Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/translations/ko/ch-gates/multiple-qubits-entangled-states.ipynb
3855 views
Kernel: Python 3

다중 큐비트와 얽힘 상태

단일 큐비트는 흥미롭긴 하지만, 개별적으로는 계산상의 이점을 제공하지 않습니다. 이제 여러 개의 큐비트를 표현하는 방법과 이러한 큐비트들이 서로 상호 작용할 수 있는 방법을 살펴보겠습니다. 우리는 앞서 2D 벡터를 사용하여 큐비트의 상태를 표현하는 방법을 배웠습니다. 이번 강의에서는 다중 큐비트의 상태를 표현하는 방법을 살펴 보겠습니다.

강의 내용

  1. 다중 큐비트 상태 표현 1.1 연습

  2. 다중 큐비트 상태 벡터에 단일 큐비트 게이트 적용하기
    2.1 연습

  3. 다중 큐비트 게이트
    3.1 CNOT 게이트
    3.2 얽힘 상태
    3.3 얽힘 상태 시각화
    3.4 연습

1. 다중 큐비트의 상태 표현하기

단일 비트에는 두 가지 가능한 상태가 있고, 큐비트 상태에는 두 가지 복소수 진폭이 있습니다. 마찬가지로 2개의 비트에는 4가지 가능한 상태가 있습니다.

00 01 10 11

그리고 두 큐비트의 상태를 설명하려면 4개의 복소수 진폭이 필요합니다. 이러한 진폭을 다음과 같이 4D 벡터에 저장합니다.

a=a0000+a0101+a1010+a1111=[a00 a01 a10 a11]|a\rangle = a_{00}|00\rangle + a_{01}|01\rangle + a_{10}|10\rangle + a_{11}|11\rangle = \begin{bmatrix} a_{00} \ a_{01} \ a_{10} \ a_{11} \end{bmatrix}

측정 규칙은 여전히 동일한 방식으로 작동합니다.

p(00)=00a2=a002p(|00\rangle) = |\langle 00 | a \rangle |^2 = |a_{00}|^2

정규화 조건(확률의 합이 1)도 마찬가지로 만족합니다.

a002+a012+a102+a112=1|a_{00}|^2 + |a_{01}|^2 + |a_{10}|^2 + |a_{11}|^2 = 1

두 개의 서로 다른 큐비트가 있는 경우, 텐서곱을 사용하여 두 큐비트의 결합 상태를 나타낼 수 있습니다.

a=[a0 a1],b=[b0 b1]|a\rangle = \begin{bmatrix} a_0 \ a_1 \end{bmatrix}, \quad |b\rangle = \begin{bmatrix} b_0 \ b_1 \end{bmatrix}ba=ba=[b0×[a0 a1] b1×[a0 a1]]=[b0a0 b0a1 b1a0 b1a1]|ba\rangle = |b\rangle \otimes |a\rangle = \begin{bmatrix} b_0 \times \begin{bmatrix} a_0 \ a_1 \end{bmatrix} \ b_1 \times \begin{bmatrix} a_0 \ a_1 \end{bmatrix} \end{bmatrix} = \begin{bmatrix} b_0 a_0 \ b_0 a_1 \ b_1 a_0 \ b_1 a_1 \end{bmatrix}

동일한 규칙을 적용해서 텐서곱을 사용하면 여러 큐비트의 결합 상태를 설명할 수 있습니다. 다음은 3개의 큐비트에 대한 예입니다.

cba=[c0b0a0 c0b0a1 c0b1a0 c0b1a1 c1b0a0 c1b0a1 c1b1a0 c1b1a1 ]|cba\rangle = \begin{bmatrix} c_0 b_0 a_0 \ c_0 b_0 a_1 \ c_0 b_1 a_0 \ c_0 b_1 a_1 \ c_1 b_0 a_0 \ c_1 b_0 a_1 \ c_1 b_1 a_0 \ c_1 b_1 a_1 \ \end{bmatrix}

큐비트가 nn개 있다면, 2n2^n 개의 복소수 진폭을 나열해야 합니다. 보시는 것처럼 이러한 벡터는 큐비트 수에 따라 기하급수적으로 증가합니다. 아주 많은 큐비트를 가진 양자 컴퓨터를 기존 컴퓨터로 시뮬레이션하기 어려운 것은 이런 이유 때문입니다. 최신 노트북으로도 20 큐비트 정도의 일반적인 양자 상태는 쉽게 시뮬레이션할 수 있지만, 100 큐비트를 시뮬레이션하는 것은 최고의 슈퍼컴퓨터에게도 너무나 어려운 일이지요.

예제 회로를 살펴보겠습니다.

from qiskit import QuantumCircuit, Aer, assemble import numpy as np from qiskit.visualization import plot_histogram, plot_bloch_multivector
qc = QuantumCircuit(3) # Apply H-gate to each qubit: for qubit in range(3): qc.h(qubit) # See the circuit: qc.draw()
Image in a Jupyter notebook

각 큐비트는 +|+\rangle 상태니까, 벡터는 다음과 같이 쓸 수 있겠네요.

+++=18[1 1 1 1 1 1 1 1 ]|{+++}\rangle = \frac{1}{\sqrt{8}}\begin{bmatrix} 1 \ 1 \ 1 \ 1 \ 1 \ 1 \ 1 \ 1 \ \end{bmatrix}
# Let's see the result svsim = Aer.get_backend('aer_simulator') qc.save_statevector() qobj = assemble(qc) final_state = svsim.run(qobj).result().get_statevector() # In Jupyter Notebooks we can display this nicely using Latex. # If not using Jupyter Notebooks you may need to remove the # array_to_latex function and use print(final_state) instead. from qiskit.visualization import array_to_latex array_to_latex(final_state, prefix="\\text{Statevector} = ")
Statevector=[1818181818181818]\text{Statevector} = \begin{bmatrix} \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} & \tfrac{1}{\sqrt{8}} \\ \end{bmatrix}

그리고 우리는 예상한 결과를 얻었습니다.

1.2 간단한 연습:

  1. Write down the kronecker product of the qubits:
    a) 01|0\rangle|1\rangle
    b) 0+|0\rangle|+\rangle
    c) +1|+\rangle|1\rangle
    d) +|-\rangle|+\rangle

  2. 주어진 상태를 두 개의 큐비트로 나타내 보세요 : ψ=1200+i201|\psi\rangle = \tfrac{1}{\sqrt{2}}|00\rangle + \tfrac{i}{\sqrt{2}}|01\rangle

2. 다중 큐비트 상태 벡터에 단일 큐비트 게이트 적용하기

이전 강의에서 X-gate가 다음과 같은 행렬로 표현되는 것을 보았습니다.

X=[0amp;1 1amp;0]X = \begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix}

그리고 0|0\rangle 상태에 이 게이트를 적용하면 다음과 같은 결과를 얻게 되죠.

X0=[0amp;1 1amp;0][1 0]=[0 1]X|0\rangle = \begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix}\begin{bmatrix} 1 \ 0 \end{bmatrix} = \begin{bmatrix} 0 \ 1\end{bmatrix}

그러나 X-gate가 다중 큐비트 벡터의 큐비트에서 어떻게 작동할 지는 명확하게 와닿지 않을 수 있습니다. 다행히 규칙은 매우 간단합니다. 텐서곱을 사용하여 다중 큐비트 상태 벡터를 계산했던 것처럼, 텐서곱을 사용하여 이러한 상태 벡터에 작용하는 행렬을 계산합니다. 예를 들어, 아래 회로에서:

qc = QuantumCircuit(2) qc.h(0) qc.x(1) qc.draw()
Image in a Jupyter notebook

텐서곱을 사용하여 동시 연산(H & X)을 나타낼 수 있습니다.

Xq1Hq0=(XH)q1q0X|q_1\rangle \otimes H|q_0\rangle = (X\otimes H)|q_1 q_0\rangle

연산 결과는 다음과 같습니다.

XH=[0amp;1 1amp;0]12[1amp;1 1amp;1]X\otimes H = \begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix} \otimes \tfrac{1}{\sqrt{2}}\begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix}=12[0×[1amp;1 1amp;1]amp;1×[1amp;1 1amp;1] 1×[1amp;1 1amp;1]amp;0×[1amp;1 1amp;1]]= \frac{1}{\sqrt{2}} \begin{bmatrix} 0 \times \begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix} & 1 \times \begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix} \ 1 \times \begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix} & 0 \times \begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix} \end{bmatrix}=12[0amp;0amp;1amp;1 0amp;0amp;1amp;1 1amp;1amp;0amp;0 1amp;1amp;0amp;0 ]= \frac{1}{\sqrt{2}} \begin{bmatrix} 0 & 0 & 1 & 1 \ 0 & 0 & 1 & -1 \ 1 & 1 & 0 & 0 \ 1 & -1 & 0 & 0 \ \end{bmatrix}

그런 다음 이것을 4D 상태벡터 q1q0|q_1 q_0\rangle에 적용하면 됩니다. 그런데 연산 결과가 꽤 지저분해 보이네요. 좀 더 깔끔하게 표기할 수도 있습니다.

XH=[0amp;H Hamp;0 ]X\otimes H = \begin{bmatrix} 0 & H \ H & 0\ \end{bmatrix}

이 작업을 손으로 일일이 하는 대신, Qiskit의 unitary_simulator 를 사용하여 연산할 수 있습니다. 유니터리 시뮬레이터는 회로에 있는 모든 게이트를 곱해서 양자 회로 전체를 한번에 수행할 수 있는 단일 유니터리 행렬로 컴파일합니다.

usim = Aer.get_backend('aer_simulator') qc.save_unitary() qobj = assemble(qc) unitary = usim.run(qobj).result().get_unitary()

결과 보기:

# In Jupyter Notebooks we can display this nicely using Latex. # If not using Jupyter Notebooks you may need to remove the # array_to_latex function and use print(unitary) instead. from qiskit.visualization import array_to_latex array_to_latex(unitary, prefix="\\text{Circuit = }\n")
$$\text{Circuit = } [001212001212121200121200]\begin{bmatrix} 0 & 0 & \tfrac{1}{\sqrt{2}} & \tfrac{1}{\sqrt{2}} \\ 0 & 0 & \tfrac{1}{\sqrt{2}} & -\tfrac{1}{\sqrt{2}} \\ \tfrac{1}{\sqrt{2}} & \tfrac{1}{\sqrt{2}} & 0 & 0 \\ \tfrac{1}{\sqrt{2}} & -\tfrac{1}{\sqrt{2}} & 0 & 0 \\ \end{bmatrix}$$

한 번에 하나의 큐비트에만 게이트를 적용하려고 할 때는(예: 아래 회로), 아래 예시처럼 단위 행렬과 텐서곱을 함께 사용하면 됩니다.

XIX \otimes I
qc = QuantumCircuit(2) qc.x(1) qc.draw()
Image in a Jupyter notebook
# Simulate the unitary usim = Aer.get_backend('aer_simulator') qc.save_unitary() qobj = assemble(qc) unitary = usim.run(qobj).result().get_unitary() # Display the results: array_to_latex(unitary, prefix="\\text{Circuit = } ")
Circuit = [0010000110000100]\text{Circuit = } \begin{bmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ \end{bmatrix}

Qiskit이 텐서곱을 수행한 것을 볼 수 있습니다. XI=[0amp;I Iamp;0 ]=[0amp;0amp;1amp;0 0amp;0amp;0amp;1 1amp;0amp;0amp;0 0amp;1amp;0amp;0 ] X \otimes I = \begin{bmatrix} 0 & I \ I & 0\ \end{bmatrix} = \begin{bmatrix} 0 & 0 & 1 & 0 \ 0 & 0 & 0 & 1 \ 1 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 \ \end{bmatrix}

2.1 간단한 연습:

  1. 게이트 배열 U=XZHU = XZH 을 단일 큐비트 유니터리(UU)가 되도록 연산합니다. Qiskit의 유니터리 시뮬레이터를 사용하여 결과를 확인하십시오.

  2. 위의 회로에서 게이트를 변경해 보세요. 텐서곱을 연산한 다음, 유니터리 시뮬레이터를 사용하여 답을 확인해 보세요.

참고: 책, 소프트웨어, 웹사이트마다 큐비트 순서가 다를 수 있습니다. 이것은 동일한 회로일지라도 텐서곱이 서로 다르게 보일 수 있음을 의미합니다. 다른 출처를 참조할 때는 이 점을 염두에 두십시오.

3. 다중 큐비트 게이트

이제 다중 큐비트의 상태를 나타내는 방법을 알게 되었으니, 큐비트가 서로 상호 작용하는 방법을 배울 준비가 되었습니다. 중요하게 사용되는 2큐비트 게이트로 CNOT 게이트가 있습니다.

3.1 CNOT 게이트

계산의 기본 요소(원자)들에서 이 게이트를 본 적이 있습니다. 이 게이트는 첫 번째 큐비트(제어)의 상태가 1|1\rangle인 경우 두 번째 큐비트(대상)에 대해 X-gate를 수행하는 조건부 게이트입니다. 게이트는 다음과 같이 회로에 그려지며 q0 이 제어이고 q1 이 대상입니다.

qc = QuantumCircuit(2) # Apply CNOT qc.cx(0,1) # See the circuit: qc.draw()
Image in a Jupyter notebook

큐비트가 0|0\rangle 또는 1|1\rangle의 중첩이 아닐 때는 (고전적인 비트처럼 동작) 매우 간단하고 직관적으로 이 게이트를 이해할 수 있습니다. 고전적인 진리표로 나타내 보죠:

입력(t,c)출력(t,c)
0000
0111
1010
1101

그리고 우리의 4D 상태 벡터에 적용하면 아래 두 행렬 중 하나를 갖게 됩니다.

CNOT=[1amp;0amp;0amp;0 0amp;0amp;0amp;1 0amp;0amp;1amp;0 0amp;1amp;0amp;0 ],CNOT=[1amp;0amp;0amp;0 0amp;1amp;0amp;0 0amp;0amp;0amp;1 0amp;0amp;1amp;0 ]\text{CNOT} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 \ 0 & 0 & 1 & 0 \ 0 & 1 & 0 & 0 \ \end{bmatrix}, \quad \text{CNOT} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 1 \ 0 & 0 & 1 & 0 \ \end{bmatrix}

어떤 큐비트가 제어이고 어떤 큐비트가 대상인지에 따라 달라집니다. 다른 책이나 시뮬레이터, 논문에서는 큐비트를 다른 순서로 정렬할 수도 있지만, 우리의 경우는 왼쪽 행렬이 위 회로의 CNOT에 해당합니다. 이 행렬은 우리의 상태 벡터에서 01|01\rangle11|11\rangle의 진폭을 맞교환합니다.

a=[a00 a01 a10 a11],CNOTa=[a00 a11 a10 a01]   |a\rangle = \begin{bmatrix} a_{00} \ a_{01} \ a_{10} \ a_{11} \end{bmatrix}, \quad \text{CNOT}|a\rangle = \begin{bmatrix} a_{00} \ a_{11} \ a_{10} \ a_{01} \end{bmatrix} \begin{matrix} \ \leftarrow \ \ \leftarrow \end{matrix}

지금까지는 고전적인 상태에서 어떻게 작용하는지 살펴 보았습니다. 이제 중첩 상태의 큐비트에서 어떻게 작용하는지 봅시다. 큐비트 하나를 +|+\rangle 상태로 둡니다.

qc = QuantumCircuit(2) # Apply H-gate to the first: qc.h(0) qc.draw()
Image in a Jupyter notebook
# Let's see the result: svsim = Aer.get_backend('aer_simulator') qc.save_statevector() qobj = assemble(qc) final_state = svsim.run(qobj).result().get_statevector() # Print the statevector neatly: array_to_latex(final_state, prefix="\\text{Statevector = }")
Statevector = [121200]\text{Statevector = } \begin{bmatrix} \tfrac{1}{\sqrt{2}} & \tfrac{1}{\sqrt{2}} & 0 & 0 \\ \end{bmatrix}

예상대로 0+=0+|0\rangle \otimes |{+}\rangle = |0{+}\rangle 상태를 생성합니다.

0+=12(00+01)|0{+}\rangle = \tfrac{1}{\sqrt{2}}(|00\rangle + |01\rangle)

CNOT 게이트를 적용하면 어떤 일이 발생하는지 봅시다.

qc = QuantumCircuit(2) # Apply H-gate to the first: qc.h(0) # Apply a CNOT: qc.cx(0,1) qc.draw()
Image in a Jupyter notebook
# Let's get the result: qc.save_statevector() qobj = assemble(qc) result = svsim.run(qobj).result() # Print the statevector neatly: final_state = result.get_statevector() array_to_latex(final_state, prefix="\\text{Statevector = }")
Statevector = [120012]\text{Statevector = } \begin{bmatrix} \tfrac{1}{\sqrt{2}} & 0 & 0 & \tfrac{1}{\sqrt{2}} \\ \end{bmatrix}

상태가 다음과 같이 표시됩니다.

CNOT0+=12(00+11)\text{CNOT}|0{+}\rangle = \tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle)

이것이 얽힘 상태라는 것은 매우 흥미로운 점입니다. 이제 자연스럽게 다음 섹션으로 넘어가 보겠습니다.

3.2 얽힘 상태

이전 섹션에서 다음 상태가 생성된 것을 보았습니다.

12(00+11)\tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle)

이것을 상태라고 합니다. 이것은 00|00\rangle 상태에서 측정될 확률이 50%이고 11|11\rangle 상태에서 측정될 확률이 50%임을 의미합니다. 정말 흥미로운 것은 01|01\rangle 또는 10|10\rangle 상태에서 측정될 확률은 0% 라는 점입니다. Qiskit에서 확인해 보실 수 있습니다:

plot_histogram(result.get_counts())
Image in a Jupyter notebook

이 결합된 상태는 두 개의 개별 큐비트 상태로는 만들어 낼 수 없으며 꽤 흥미로운 의미를 지니고 있습니다. 우리의 큐비트는 중첩되어 있긴 하지만, 하나를 측정하면 다른 큐비트의 상태를 알려주고 중첩이 붕괴됩니다. 예를 들어, 위쪽 큐비트를 측정하고 1|1\rangle 상태를 얻은 경우 큐비트의 결합 상태는 다음과 같아집니다.

12(00+11)measure11\tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle) \quad \xrightarrow[]{\text{measure}} \quad |11\rangle

이 큐비트를 몇 광년 거리 떨어진 곳으로 보내더라도 하나의 큐비트를 측정하면 중첩이 붕괴되고 다른 큐비트에 즉각적인 영향을 미치게 될 것입니다. 이것이 바로 20세기 초 많은 물리학자들을 화나게 했던 '유령 같은 원거리 작용' 입니다.

측정 결과는 무작위적이며 한 큐비트의 측정 통계는 다른 큐비트의 작업에 영향을 받지 않는다는 점에 유의하는 것이 중요합니다. 이 때문에 공유 양자 상태를 사용하여 통신 할 수 있는 방법이 없습니다. 이것은 비통신 정리로 알려져 있습니다.[1]

3.3 얽힘 상태 시각화

우리는 두 개의 개별 큐비트 상태로는 이 상태를 만들 수 없다는 것을 보았습니다. 이는 또한 별도의 Bloch 구체에 상태를 그리려고 할 때 정보를 잃는다는 것을 의미합니다.

plot_bloch_multivector(final_state)
Image in a Jupyter notebook

이전 장에서 Bloch 구를 정의한 방법을 감안하면, Qiskit이 이렇게 얽힌 큐비트로 Bloch 벡터를 계산하는 것이 명확하게 이해되지 않을 수 있습니다. 단일 큐비트의 경우 축을 따라 움직이는 Bloch 벡터의 위치와 해당 기반(Basis)에서 측정한 기대값은 잘 일치합니다. Bloch 벡터를 그리는 규칙이 그렇다고 받아 들인다면 이런 결론에 도달할 수 있겠죠. 이것은 특정 측정이 보장되는 단일 큐비트 측정 기반이 없다는 것을 보여줍니다. 이것은 단일 큐비트 상태에서 항상 단일 큐비트 기반을 선택할 수 있었던 것과는 대조되는 얘기죠. 이런 식으로 개별 큐비트를 보면 큐비트 간의 상관관계의 중요한 효과를 놓치게 됩니다. 서로 다른 얽힌 상태를 구별할 수 없습니다. 예를 들어 두 상태는 다음과 같습니다.

12(01+10)and12(00+11)\tfrac{1}{\sqrt{2}}(|01\rangle + |10\rangle) \quad \text{and} \quad \tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle)

서로 다른 측정 결과를 가진 매우 다른 상태에도 불구하고 각각의 Bloch 구체에서 모두 동일하게 보일 것입니다.

이 상태 벡터를 다른 방법으로 시각화할 수 있을까요? 이 상태 벡터는 단순히 4개의 진폭(복소수)의 모음이며 이를 이미지에 매핑할 수 있는 방법은 무한합니다. 그런 시각화 방법 중 하나는 Q-구이며, 여기서 각 진폭은 구 표면의 얼룩으로 표시됩니다. 얼룩의 크기는 진폭의 크기에 비례하고 색상은 진폭의 위상에 비례합니다. 00|00\rangle11|11\rangle의 진폭은 동일하고 다른 모든 진폭은 0입니다.

from qiskit.visualization import plot_state_qsphere plot_state_qsphere(final_state)
Image in a Jupyter notebook

여기에서 큐비트 간의 상관 관계를 명확하게 볼 수 있습니다. Q-구의 모양은 의미가 없으며 단순히 얼룩을 정렬하는 좋은 방법입니다. 상태에서 0 의 수는 Z축의 상태 위치에 비례하므로, 여기에서는 00|00\rangle의 진폭이 구의 맨 위 극에 있고 구의 맨 아래 극에 11|11\rangle 의 진폭이 있습니다.

3.4 연습:

  1. 벨 상태를 생성하는 양자 회로를 만듭니다: 12(01+10)\tfrac{1}{\sqrt{2}}(|01\rangle + |10\rangle). 상태 벡터 시뮬레이터를 사용하여 결과를 확인하십시오.

  2. 질문 1에서 만든 회로에서 00|00\rangle 상태를 12(01+10)\tfrac{1}{\sqrt{2}}(|01\rangle + |10\rangle)로 변환하고 Qiskit 시뮬레이터를 사용하여 이 회로의 유니터리를 연산합니다. 이 유니터리가 실제로 변환을 맞게 수행하는지 확인하십시오.

  3. 상태 벡터를 시각적으로 표현할 수 있는 다른 방법을 생각해 보십시오. 각 진폭의 크기와 위상을 읽을 수 있는 흥미로운 시각화를 설계할 수 있습니까?

4. 참고문헌

[1] Asher Peres, Daniel R. Terno, Quantum Information and Relativity Theory, 2004, https://arxiv.org/abs/quant-ph/0212023

import qiskit.tools.jupyter %qiskit_version_table