2021년 6월 21일 월요일

Qiskit tutorial - 1. Getting started

이 글은 Qiskit 공식 홈페이지에서 제공하는 튜토리얼을 공부하고 요약하는 글입니다. 원문[1]은 링크를 참조 바랍니다. Anaconda 의 Jupyter notebook 을 사용하지 않고, Windows OS와 순수 python 에서 실행 가능하도록 소스코드를 변형하여 구현하였습니다. 제가 작성한 소스코드는 Github[2] 에 공개합니다.

1.1. 키스킷 시작하기

키스킷에서 양자 컴퓨터 프로그래밍에 필요한 기본 구성 요소를 제공하는 필수 패키지는 테라다. 키스킷의 기본적인 내용은 quantum circuit[3] 에서 확인할 수 있다. 키스킷을 사용하는 기본 작업 방식은 빌드(Build)와 실행(Execute)으로 구성된다. 빌드는 해결하고자 하는 문제를 표현하는 몇 가지의 다른 양자 회로들을 만들 수 있으며, 실행은 이 회로들을 각기 다른 후위처리 장치(backend, 이후 백엔드)에서 실행하도록 한다. 작업이 실행된 후에는 원하는 출력에 따라 데이터를 수집하고 후처리한다. 기본적인 import 문은 다음과 같다.


코드1.1. 기본 import

1.2. 회로 기초

1.2.1. 회로 만들기

첫 프로그램을 위한 기본 요소는 QuantumCircuit 이며, 세 개의 큐비트로 구성된 QuantumCircuit 을 만드는 것으로 시작한다.

코드1.2. 큐비트 선언

레지스터를 가진 회로를 만들고 나서, 그 레지스터를 조작하기 위해 게이트(연산자)를 추가할 수 있다. 튜토리얼을 수행하면서 더 많은 게이트와 회로를 발견하게 될 것이다. 아래에 3-큐비트 GHZ 상태[4]를 만드는 예시가 있다.

이러한 상태를 만들기 위해서는 우선 세 개의 큐비트로 구성된 양자 레지스터를 구성한다. 기본적으로 레지스터의 각 큐비트는 |0〉으로 초기화된다. GHZ 상태를 만들기 위해 다음 게이트를 적용한다. - 큐비트0을 중첩 상태( (|0〉 + |1〉) / √2 )로 만드는 하다마드 게이트 H 를 큐비트 0에 적용한다. 다음, 제어된 반전 게이트(Controlled Not Gate, CNOT)를 사용하여 큐비트 0을 제어 큐비트, 큐비트 1을 타겟 큐비트로 적용한다. 다시 CNOT 게이트를 제어 큐비트 0과 타겟 큐비트 2에 적용한다. 이상적인 양자 컴퓨터에서 이 회로에 의해 만들어진 상태가 GHZ 상태이다. 키스킷에서는 아래와 같이 연산을 회로에 하나씩 추가할 수 있다.

코드1.3. GHZ 상태 적용

1.3. 회로 시각화하기

키스킷의 QuantumCircuit.draw() 를 사용하여 회로를 시각화 할 수 있으며, 여러 교재에 보여진 형태로 회로가 그려진다. 

코드1.4. 회로 가시화

그림1.1. GHZ 상태 시각화

이 회로에 있는 큐비트들은 순서대로 배치되며 큐비트 0은 위쪽에, 큐비트 2는 아래 쪽에 놓인다. 회로는 왼쪽부터 오른쪽으로 읽는다. 즉, 가장 왼쪽에 배치된 게이트들이 회로에서 먼저 적용된다는 것을 의미한다. 

다중 큐비트 시스템의 상태를 나타낼 때, 키스킷은 대부분의 물리 교재에서 사용되는 텐서(tensor)의 순서와는 반대되는 순서를 사용한다. n 개의 큐비트가 있고, 큐비트 j 는 Qj로 표시된다고 가정하자. 키스킷에서는 기저 벡터들을 Qn-1 ⊗ ...  Q1  Q0 로 표현하기 위하여 n번째 큐비트를 텐서곱의 가장 왼편에 위치하도록 만드는 순서체계를 사용한다. 예를 들어, 0번째 큐비트가 상태 0 이고, 1번째 큐비트가 상태 0이며, 2번째 큐비트가 1 일 때, 키스킷은 이를 |100⟩ 으로 표현하는데, 대부분의 물리 교재들에서는 |001〉로 표현한다. 

이러한 표현의 차이는 다중 큐비트 연산이 매트릭스로 표현될 때 나타나게 된다. 예를 들어 큐비트 0이 제어 큐비트이고, 큐비트 1이 타겟 큐비트일 때, Controlled X(Cx) 연산은 키스킷에서 다음과 같이 표현된다.


1.4. 키스킷 에어(Aer)로 회로 시뮬레이션

키스킷 에어는 양자 회로 시뮬레이션을 위한 패키지이다. 시뮬레이션을 수행하기 위한 다양한 백엔드들을 제공한다. 아래 에제에서는 Aer 를 대체할 수 있는 키스킷 테라의 BasicAer 라는 파이썬 전용 기본 구현도 확인할 수 있다.

1.4.1. 상태벡터 백엔드

키스킷 에어에서 가장 일반적으로 사용되는 백엔드는 statevector_simulator 이다. 이 시뮬레이터는 양자 상태를 반환하는 데, 이는 큐비트의 갯수가 n 일 때 2²의 차원을 가지는 복소수 벡터이다. 따라서 실행 시 빠르게 그 크기가 늘어나기 때문에 주의해야 한다.

상태벡터 시뮬레이터를 이용하여 위의 회로를 실행하려면, 우선 에어를 import 하고 백엔드를 statevector_simulator 로 설정해야 한다.

코드1.5. Aer 시뮬레이터의 backend 선언

이제 백엔드를 정했으니, 양자 회로를 컴파일하고 실행할 시간이다. 키스킷에서는 이를 위해 execute 함수를 제공한다. execute 는 백엔드에 제출된 작업에 대한 정보를 함축하고 있는 job 객체를 되돌려 준다.

코드1.6. 코드 실행과 결과 리턴

코드를 실행할 때, 작업 객체는 다음의 두 메소드 job.status() 와 job.result() 를 가지는 데, 각각은 작업에 대한 상태와 그 결과를 돌려준다. 작업은 비동기화 방식으로 실행되지만, 결과 메소드가 호출되면 동기화 방식으로 전환되어, 다른 작업으로 옮겨가기 전에 작업이 끝날 때까지 기다리게 된다. 결과 객체는 데이터를 가지고 있으며, 키스킷은 양자 회로에 대한 상태 벡터를 돌려주는 result.get_statevector(circ) 메소드를 제공한다. 


코드1.7. 실행 결과 출력

그림1.2. 상태 벡터 출력 결과 (0.707 은 1/√2 의 근사값이다.)

또한 키스킷은 이러한 결과를 확인할 수 있도록 시각화 도구상자를 제공한다. 아래는 상태 밀도 매트릭스 ρ ('로' 라고 읽는다.) 의 실수와 허수를 보여주는 시각화 함수를 사용하였다.

코드1.8. 실행 결과 시각화

그림1.3. 상태 밀도 매트릭스의 실수와 허수 시각화

1.4.2. 유니타리 백엔드(Unitary backend)

또한 키스킷 에어는 회로의 모든 요소가 유니타리 연산일 때 작동하는 unitary_simulator 를 포함하고 있다. 이 백엔드는 양자 회로에서 게이트를 나타내는 2ⁿ x 2ⁿ 행렬을 계산한다.

코드1.9. 유니타리 시뮬레이터 실행 및 출력

그림1.3. 유니타리 행렬 출력 결과

1.4.3. OpenQASM 백엔드

이러한 시뮬레이터들은 회로의 행렬 상태를 나타내고 이상적인 회로의 결과에 대한 정보를 주기 때문에 유용하다. 그러나 실제의 실험은 보통 계산적인 |0〉, |1〉 으로 표현되는 각각의 큐비트를 측정(measuring)하면서 종료된다. 측정 없이는, 상태에 대한 정보를 얻을 수없다. 그 이유는 특정을 통해서 양자 시스템은 전통적인 비트로 변환되기 때문이다.

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

그리고 xyz 가 각 비트문자열이라고 하자. 이 경우, 키스킷의 비트 순서에  따라 x 는 큐비트2, y는 큐비트1, z는 큐비트 0에 해당함을 기억하자. 이러한 비트열 표기는 MSB 를 왼쪽에, LSB를 오른쪽에 둔다. 이는 이진 비트열을 표기하는 일반적인 순서이다. 키스킷은 이 규칙에 따라 배열을 한다. 따라서 MSB에 해당하는 큐비트는 0번째 큐비트이며, 일반적인 텐서 곱 순서와는 다르다.

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

Pr(xyz) = |(xyz|ψ〉|²

그리고 GHZ 상태에서 000 또는 111 상태를 얻을 확률은 둘 다 1/2 이다. (큐비트0 이 하다마드 게이트를 통해 0과 1이 50% 확률로 중첩되었고, 0의 측정 결과를 큐비트1과 큐비트2가 따라가도록 Cx 연산자를 적용했기 때문이다.)

측정이 포함된 회로를 시뮬레이션하기 위해서는 원래의 회로에 측정 모듈을 추가해야 하며, 이를 위해 다른 에어 백엔드를 사용한다.

코드1.10. GHZ 상태 측정

그림1.4. GHZ 상태 측정 결과 시각화

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

이 회로를 시뮬레이션하기 위해서는 키스킷 에어에 있는 qasm_simulator 를 사용해야 한다. 이 회로 각각의 실행은 비트 문자열 000 또는 111을 생성하며, 또한 비트 문자열의 분포에 대한 통계를 얻기 위해서는 회로를 여러 번 실행해야 한다. 회로가 반복되는 횟수를 결정하기 위해서는 execute 함수에 있는 shots 키워드를 조정하면 된다.

코드1.11. QASM 시뮬레이터를 이용한 회로 측정

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

코드1.12. 회로 측정 결과 출력

그림1.5. 회로 측정 결과

약 50%의 확률로 000의 결과 비트 문자열을 가진다 또한 키스킷의 plot_histogram 함수를 통해 결과를 시각화할 수 있다.

그림1.6. 회로 측정 결과 시각화

예측 값인 확률 Pr(000)과 Pr(111)은 유효 카운트를 모두 더한 후에 회로 실행 횟수로 나누어 계산된다.

댓글 없음:

댓글 쓰기