Korean
언어
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

참고

이 페이지는 tutorials/circuits/01_circuit_basics.ipynb 에서 생성되었다.

회로의 기초

여기에서는 Qiskit 사용에 대한 개요를 설명한다. Qiskit은 양자 컴퓨터를 프로그램하기 위해 필수적인 기초 구성 요소들을 제공한다. Qiskit의 기본 단위는 양자 회로 이다. Qiskit의 작업 흐름은 두 단계로 나뉜다: 빌드실행 이다. 빌드 는 해결하고픈 문제를 나타내는 다양한 양자회로들을 구축할 수 있게 하며, 실행 은 이 회로들을 여러 백엔드에서 실행할 수 있게 한다. 작업들이 다 실행되었을 때, 데이터는 원하는 출력에 따라 수집되고 후처리가 된다.

[1]:
import numpy as np
from qiskit import QuantumCircuit


회로 만들기

첫번째 프로그램을 위해 필요한 제일 기초적인 요소는 QuantumCircuit이다. 세 개의 큐비트으로 이루어진 QuantumCircuit 을 만드는 것으로 시작하자.

[2]:
# Create a Quantum Circuit acting on a quantum register of three qubits
circ = QuantumCircuit(3)

After you create the circuit with its registers, you can add gates (《operations》) to manipulate the registers. As you proceed through the tutorials you will find more gates and circuits; below is an example of a quantum circuit that makes a three-qubit GHZ state

\[|\psi\rangle = \left(|000\rangle+|111\rangle\right)/\sqrt{2}.\]

이러한 상태를 만들기 위해서는 우선 세개의 큐비트로 양자 레지스터를 구성한다. 기본적으로 레지스터의 각 큐비트는 \(|0\rangle\) 로 초기화된다. GHZ 상태를 만들기 위해 다음 게이트를 적용한다: - 중첩 상태 \(\left(|0\rangle+|1\rangle\right)/\sqrt{2}\) 로 만들어주는 Hadamard(하다마드) 게이트 \(H\) 를 큐비트 0에 적용한다. - 큐비트 0과 큐비트 1에 Controlled-NOT 연산 (\(C_{X}\))을 적용한다. - 큐비트 0과 큐비트 2에 Controlled-NOT 연산을 적용한다.

이상적인 양자 컴퓨터에서 이 회로를 실행한다면 위의 GHZ 상태가 만들어질 것이다.

Qiskit에서는 아래와 같이 연산들을 회로에 하나씩 추가할 수 있다.

[3]:
# Add a H gate on qubit 0, putting this qubit in superposition.
circ.h(0)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 1, putting
# the qubits in a Bell state.
circ.cx(0, 1)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 2, putting
# the qubits in a GHZ state.
circ.cx(0, 2)
[3]:
<qiskit.circuit.instructionset.InstructionSet at 0x7f7c92288310>

회로 시각화하기

Qiskit QuantumCircuit.draw() 는 회로를 많은 교재에 나오는 형식으로 그려주는데, 이를 이용해 회로를 시각화할 수 있다.

[4]:
circ.draw('mpl')
[4]:
../../_images/tutorials_circuits_01_circuit_basics_7_0.svg

이 회로에서는 큐비트들이 0 큐비트은 위쪽에 1 큐비트는 아래쪽에 놓이도록 순서가 정해져 있다. 회로는 왼쪽에서 오른쪽으로 읽혀지는데, 이것은 가장 왼쪽의 게이트들이 회로에서 먼저 적용된다는 것을 의미한다.

다중 큐비트 시스템의 상태를 나타낼 때, Qiskit은 대부분의 물리 교재에서 사용되는 텐서(tensor)의 순서와는 반대 되는 순서를 사용한다. \(n\) 개의 큐비트가 있고, 큐비트 \(j\)\(Q_{j}\) 로 표시된다고 가정하자. Qiskit에서는 (기저 벡터들을 \(Q_{n-1}\otimes \cdots \otimes Q_1\otimes Q_0\) 로 표현하기 위하여) \(n^{\mathrm{th}}\) 큐비트를 텐서 곱의 가장 왼편에 위치하도록 만드는 순서체계(ordering)를 사용한다.

예를 들어, 큐비트 0이 0 상태에 있고, 큐비트 1이 0 상태, 큐비트 2가 1 상태에 있을 때, Qiskit은 이 상태를 \(|100\rangle\) 로 표현하는데, 대부분의 물리 교과서에서는 \(|001\rangle\) 로 표현한다.

이러한 표현의 차이는 다중 큐비트 연산이 행렬로 표현될 때 나타나게 된다. 예를 들어 큐비트 0이 제어 큐비트이고 큐비트 1이 목표 큐비트일 때, controlled-X (\(C_{X}\)) 연산은 Qiskit에서 다음과 같이 표현된다.

\[\begin{split}C_X = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\\end{pmatrix}.\end{split}\]

회로 시뮬레이션하기

회로를 시뮬레이션하고자 Qiskit 의 quant_info 모듈을 사용한다. 이 시뮬레이터는 \(2^n\) 차원의의 복소 벡터인 양자 상태를 반환하는데, 여기서 \(n\) 은 큐비트의 개수이다 (따라서 로컬 머신에서 돌릴 때 순식간에 너무 큰 용량을 차지하게 될 수 있어 주의해야 한다).

시뮬레이터에는 두 가지 단계가 있다. 첫 번째로는 입력 상태를 설정하는 것이고 두 번째는 양자 회로로 상태를 발전시키는 것이다.

[5]:
from qiskit.quantum_info import Statevector

# Set the intial state of the simulator to the ground state using from_int
state = Statevector.from_int(0, 2**3)

# Evolve the state by the quantum circuit
state = state.evolve(circ)

#draw using latex
state.draw('latex')
[5]:
$$ \begin{bmatrix} \tfrac{1}{\sqrt{2}} & 0 & 0 & 0 & 0 & 0 & 0 & \tfrac{1}{\sqrt{2}} \\ \end{bmatrix} $$
[6]:
from qiskit.visualization import array_to_latex

#Alternative way of representing in latex
array_to_latex(state)
[6]:
$$ \begin{bmatrix} \tfrac{1}{\sqrt{2}} & 0 & 0 & 0 & 0 & 0 & 0 & \tfrac{1}{\sqrt{2}} \\ \end{bmatrix} $$

Qiskit은 이러한 결과들을 보여주는 시각화 도구상자를 제공한다.

아래에서는 시각화 함수를 이용해 qsphere와 상태 밀도 행렬 \(\rho\) 의 실수와 허수 부분을 나타내는 힌턴 다이어그램을 그렸다.

[7]:
state.draw('qsphere')
[7]:
../../_images/tutorials_circuits_01_circuit_basics_14_0.svg
[8]:
state.draw('hinton')
[8]:
../../_images/tutorials_circuits_01_circuit_basics_15_0.svg

회로의 유니터리 표현

Qiskit’s quant_info module also has an operator method which can be used to make a unitary operator for the circuit. This calculates the \(2^n \times 2^n\) matrix representing the quantum circuit.

[9]:
from qiskit.quantum_info import Operator

U = Operator(circ)

# Show the results
U.data
[9]:
array([[ 0.70710678+0.j,  0.70710678+0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j],
       [ 0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.70710678+0.j, -0.70710678+0.j],
       [ 0.        +0.j,  0.        +0.j,  0.70710678+0.j,
         0.70710678+0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j],
       [ 0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.70710678+0.j, -0.70710678+0.j,
         0.        +0.j,  0.        +0.j],
       [ 0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.70710678+0.j,  0.70710678+0.j,
         0.        +0.j,  0.        +0.j],
       [ 0.        +0.j,  0.        +0.j,  0.70710678+0.j,
        -0.70710678+0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j],
       [ 0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.70710678+0.j,  0.70710678+0.j],
       [ 0.70710678+0.j, -0.70710678+0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j,  0.        +0.j,
         0.        +0.j,  0.        +0.j]])

OpenQASM 백엔드

이러한 시뮬레이터들은 회로의 행렬 상태를 보여주고 이상적인 회로의 상태 결과에 대한 정보를 주기 때문에 유용하다. 그러나 실제의 실험은 각각의 큐비트(보통 computational \(|0\rangle, |1\rangle\) 기저로 표현된다)를 측정 함으로써 끝난다. 측정이 없다면, 상태에 대한 정보를 얻을 수 없다. 또한 측정을 통해 양자 시스템은 고전적인 비트로 붕괴하게 된다.

예를 들어, 3개의 큐비트를 가진 GHZ 상태의 각각의 큐비트를 독립적으로 측정한다고 가정해 보자.

\[|\psi\rangle = (|000\rangle +|111\rangle)/\sqrt{2},\]

그리고 \(xyz\) 를 결과의 비트 문자열이라고 하자. Qiskit에서 사용되는 큐비트 표기로는 \(x\) 가 큐비트 2의 결과에 해당하고, \(y\) 는 큐비트 1, 그리고 \(z\) 는 큐비트 0에 해당한다는 사실을 기억하자.

참고: 이러한 비트열 표기는 most significant bit (MSB) 를 왼쪽에 두고 least significant bit (LSB) 를 오른쪽에 둔다. 이는 이진 비트열을 표기하는 일반적인 순서이다. 우리는 큐비트도 이 규칙에 따라 배열한다 (MSB에 해당하는 큐비트는 0으로 인덱스된다). 따라서 Qiskit은 일반적이지 않은 텐서 곱 순서를 사용한다.

\(xyz\) 의 결과를 얻는 확률은 다음과 같이 주어진다.

\[\mathrm{Pr}(xyz) = |\langle xyz | \psi \rangle |^{2}\]

따라서 GHZ 상태에서 000 혹은 111의 결과를 얻을 확률은 둘 다 1/2이다.

측정을 포함하는 회로를 시뮬레이트하기 위해서는 원래의 회로에 측정들을 추가해야 하고, 다른 Aer 백엔드를 사용해야 한다.

[10]:
# Create a Quantum Circuit
meas = QuantumCircuit(3, 3)
meas.barrier(range(3))
# map the quantum measurement to the classical bits
meas.measure(range(3), range(3))

# The Qiskit circuit object supports composition.
# Here the meas has to be first and front=True (putting it before)
# as compose must put a smaller circuit into a larger one.
qc = meas.compose(circ, range(3), front=True)

#drawing the circuit
qc.draw('mpl')
[10]:
../../_images/tutorials_circuits_01_circuit_basics_21_0.svg

이 회로는 고전 레지스터와, 큐비트의 결과를 고전 비트에 연결하기 위한 세 개의 측정들을 추가한다.

이 회로를 시뮬레이트하기 위해서 Qiskit Aer 에 있는 qasm_simulator 를 사용한다. 이 회로의 각각의 실행은 비트 문자열 000 혹은 111을 생성한다. 비트 문자열 (예를 들어 \(\mathrm{Pr}(000)\) )의 분포에 대한 통계를 얻기 위해서는 회로를 여러번 실행해야 한다. 회로가 반복되는 횟수를 결정하기 위해서는 execute 함수에 있는 shots 키워드를 조정하면 된다.

[11]:
# Adding the transpiler to reduce the circuit to QASM instructions
# supported by the backend
from qiskit import transpile

# Use AerSimulator
from qiskit_aer import AerSimulator

backend = AerSimulator()

# First we have to transpile the quantum circuit
# to the low-level QASM instructions used by the
# backend
qc_compiled = transpile(qc, backend)

# Execute the circuit on the qasm simulator.
# We've set the number of repeats of the circuit
# to be 1024, which is the default.
job_sim = backend.run(qc_compiled, shots=1024)

# Grab the results from the job.
result_sim = job_sim.result()

결과 객체를 얻은 후에는 이러한 시뮬레이션 횟수를 get_counts(circuit) 함수를 통해 접근할 수 있다. 이를 통해서 지금까지 실행했던 시뮬레이션의 합산된 결과 값을 구할 수 있다.

[12]:
counts = result_sim.get_counts(qc_compiled)
print(counts)
{'111': 522, '000': 502}

대략 50 퍼센트 정도는 결과 비트 문자열이 000인 값을 가진다. 또한 Qiskit은 결과를 보여주는 plot_histogram 함수를 제공한다.

[13]:
from qiskit.visualization import plot_histogram
plot_histogram(counts)
[13]:
../../_images/tutorials_circuits_01_circuit_basics_27_0.svg

예측값인 확률 \(\mathrm{Pr}(000)\)mathrm{Pr}(111)`는 유효 카운트를 모두 더한 후에 (회로가 몇번 실행되었는지를 가르키는) 시뮬레이션 숫자로 나누어서 계산되어진다. execute 함수에 있는 shots 키워드를 수정해 보면서 예측 확률값이 어떻게 변하는지 살펴보라.

[14]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.26.2
Terra0.17.4
Aer0.8.2
Ignis0.6.0
Aqua0.9.1
IBM Q Provider0.13.1
System information
Python3.8.5 (default, Sep 4 2020, 07:30:14) [GCC 7.3.0]
OSLinux
CPUs2
Memory (Gb)7.523967742919922
Fri Jun 04 17:48:05 2021 IST

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.