common.title
Cloud support

Nobisuke

Dekisugi

RAG


autoQAOA
RAG for dev
Fortune telling app
Annealing
DEEPSCORE
Translation

Overview
Service overview
Terms of service

Privacy policy

Contact
Research

Sign in
Sign up
common.title

状態ベクトルともつれ

Yuichiro Minato

2021/01/16 07:58

#量子ゲート

はじめに

量子コンピュータに関する勉強会の中で特に状態ベクトルともつれに関してまとめたいと思います。

量子コンピュータと解の候補

量子コンピュータの実機は通常何度も計算を行って解答の確率分布を求めます。実機では何度も何度も計算をします。

blueqatSDKでは、

Circuit().h[0].m[:].run(shots=100)

のようになります。これを計算すると、0と1が約半分ずつ答えとして出ます。ここで、理想的には50回ずつ出て欲しいのですが、実際には36と64とか、52と48とかみたいに理想的にはいきません。理想的にやりたい場合には、結局計算の回数を増やし、1000回計算して、520と480みたいに回数を増やす必要があります。

これは結構回答の精度にも大きく影響して、現在は量子コンピュータはエラーが多いので、うまくいくことは少ないです。また、問題のサイズが大きくなると、試行回数も多く必要になり、解の候補は指数で増えるため、

2N2^N

の場合の数では、より多くの試行回数が必要になり、試行回数が必要な数は量子ビットが増えるにつれて指数で増えていきます。

状態ベクトル

そこで、数学的にそれらの試行をシミュレーションすることで、量子ビットの数が少ないときにはそれぞれの場合のかずが出る確率を直接計算することができます。その確率を記述しているのが状態ベクトルです。

状態ベクトルは、

0=[10],1=[01]\mid 0 \rangle = \begin{bmatrix}1\\0\end{bmatrix},\mid 1 \rangle = \begin{bmatrix}0\\1\end{bmatrix}

のように、0と1の状態をベクトルとして表記すると、任意の状態は、

ψ=α[10]+β[01]=[αβ]\mid \psi \rangle = \alpha \begin{bmatrix}1\\0\end{bmatrix} + \beta \begin{bmatrix}0\\1\end{bmatrix} = \begin{bmatrix}\alpha\\\beta\end{bmatrix}

のようにかけます。

複数量子ビットの状態ベクトル

複数量子ビットではテンソル積を使って状態ベクトルを表現します。

00\mid 00 \rangle

のように、2量子ビットを使って計算をする際には、テンソル積を利用します。

00=[10][10]=[1000]\mid 00 \rangle = \begin{bmatrix}1\\0\end{bmatrix} \otimes \begin{bmatrix}1\\0\end{bmatrix} = \begin{bmatrix}1\\0\\0\\0\end{bmatrix}

量子ゲートのテンソル積

上記の状態ベクトルは量子ゲートを利用して操作します。

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

2量子ビットの際には、量子ゲートもテンソル積をとります。

|0> --X--
|0> -----

のような回路では、単位行列Iを補完して、

|0> --X--
|0> --I--

の状態で利用します。テンソル積を取ります。

XI=[0110][1001]=[0010000110000100]X\otimes I = \begin{bmatrix}0&1\\1&0\end{bmatrix} \otimes \begin{bmatrix}1&0\\0&1\end{bmatrix} = \begin{bmatrix}0&0&1&0\\0&0&0&1\\1&0&0&0\\0&1&0&0\end{bmatrix}

こちらを状態ベクトルにかけて利用します。

[0010000110000100][1000]=[0010]\begin{bmatrix}0&0&1&0\\0&0&0&1\\1&0&0&0\\0&1&0&0\end{bmatrix} \begin{bmatrix}1\\0\\0\\0\end{bmatrix} = \begin{bmatrix}0\\0\\1\\0\end{bmatrix}

量子もつれ

通常テンソル積で状態ベクトルをかくと、状態ベクトルはテンソル積に分解できますが、もつれるとそれができなくなります。

|0> --H--*--
         |
|0> --I--X--

となります。これを計算すると、

HI=12[1111][1001]=12[1010010110100101]H\otimes I = \frac{1}{\sqrt{2}}\begin{bmatrix}1&1\\1&-1\end{bmatrix} \otimes \begin{bmatrix}1&0\\0&1\end{bmatrix} = \frac{1}{\sqrt{2}}\begin{bmatrix}1&0&1&0\\0&1&0&1\\1&0&-1&0\\0&1&0&-1\end{bmatrix}

こちらを状態ベクトルにかけて利用します。

12[1000010000010010][1010010110100101]=12[1001]\frac{1}{\sqrt{2}} \begin{bmatrix}1&0&0&0\\0&1&0&0\\0&0&0&1\\0&0&1&0\end{bmatrix} \begin{bmatrix}1&0&1&0\\0&1&0&1\\1&0&-1&0\\0&1&0&-1\end{bmatrix} = \frac{1}{\sqrt{2}} \begin{bmatrix}1\\0\\0\\1\end{bmatrix}

00と11のもつれになりました。これは1量子ビット同士のテンソル積には分解することができません。0番目の量子ビットの値は、1番目の量子ビットの値にお互いに依存してしまっていますので、単体での計算結果を取り出すことができません。

アプリケーションで利用する

もつれはアプリケーションの部分空間で利用します。通常量子ビットは、

2N2^N

の解の中から探索をするわけですが、もつれを使うことで解を最初から部分空間に限定して探索をすることができ、正答率を大幅に上げ、計算リソースを節約することができます。

例えば、

ABCから1つだけ1を選び、残りは0という場合、

000 001 010 011 100 101 110 111

の8通りから解を探索する必要はなく、

001 010 100

の3通りの中からだけ解を探索すれば良くなります。これにより、リソースを大幅に削減できます。その際には、

|001> + |010> + |100> の状態を作って探索をすれば良くなります。もつれをつかって実問題に応用ができます。

2量子ビットのもつれ

こちらは基本ですね。blueqatを使います。

from blueqat import Circuit Circuit().h[0].cx[0,1].m[:].run(shots=100) #Counter({'00': 54, '11': 46})
Counter({'11': 56, '00': 44})

00と11のもつれになりました。片方にXをかけると、

Circuit().h[0].cx[0,1].x[0].m[:].run(shots=100) #Counter({'01': 54, '10': 46})
Counter({'10': 54, '01': 46})

001,010,100のもつれ

こちらは確率振幅を13\frac{1}{\sqrt{3}}を作ることを目指します。今回作りたいのは、

001
010
100

のもつれ

Ry(θ)=[cos(θ2)sin(θ2)sin(θ2)cos(θ2)]Ry(\theta) = \begin{bmatrix} \cos\left(\frac{\theta}{2}\right) & -\sin\left(\frac{\theta}{2}\right)\\ \sin\left(\frac{\theta}{2}\right) & \cos\left(\frac{\theta}{2}\right) \end{bmatrix}

これを利用します。

初期状態の

[10]\begin{bmatrix} 1\\ 0 \end{bmatrix}

をRyゲートを使って回転させると、

[cos(θ2)sin(θ2)sin(θ2)cos(θ2)][10]=[cos(θ2)sin(θ2)]\begin{bmatrix} \cos\left(\frac{\theta}{2}\right) & -\sin\left(\frac{\theta}{2}\right)\\ \sin\left(\frac{\theta}{2}\right) & \cos\left(\frac{\theta}{2}\right) \end{bmatrix} \begin{bmatrix} 1\\ 0 \end{bmatrix} = \begin{bmatrix} \cos\left(\frac{\theta}{2}\right)\\ \sin\left(\frac{\theta}{2}\right) \end{bmatrix}

|0>の確率振幅を13\frac{1}{\sqrt{3}}にするには、

cos(θ2)=13\cos\left(\frac{\theta}{2}\right) = \frac{1}{\sqrt{3}}

これは、

arccos(13)arccos(\frac{1}{\sqrt{3}})

を計算すればよく、numpyを使って、

import numpy as np np.arccos(1/np.sqrt(3)) #0.9553166181245092
0.9553166181245092

出ました。そこで、Ryゲートには、この倍の角度を適用すればよく、

Circuit().ry(0.9553166181245092*2)[0].run() #array([0.57735027+0.j, 0.81649658+0.j])
array([0.57735027+0.j, 0.81649658+0.j])

できました。

1/np.sqrt(3) #0.5773502691896258
0.5773502691896258

いい感じです。あとは、残りの確率振幅を等分すればいいので、

np.arccos(1/np.sqrt(2)) #0.7853981633974484
0.7853981633974484

を使って、

Circuit().ry(0.9553166181245092*2)[0].cry(0.7853981633974484*2)[0,1].run() #array([0.57735027+0.j, 0.57735027+0.j, 0. +0.j, 0.57735027+0.j])
array([0.57735027+0.j, 0.57735027+0.j, 0.        +0.j, 0.57735027+0.j])

できました。

Circuit().ry(0.9553166181245092*2)[0].cry(0.7853981633974484*2)[0,1].m[:].run(shots=100) #Counter({'00': 36, '10': 32, '11': 32})
Counter({'10': 34, '11': 28, '00': 38})

この回路に3量子ビット目を追加してみます。

Circuit(3).ry(0.9553166181245092*2)[0].cry(0.7853981633974484*2)[0,1].m[:].run(shots=100) #Counter({'000': 32, '100': 28, '110': 40})
Counter({'100': 40, '000': 35, '110': 25})

あとはこれを調整してみますが、

Circuit(3).ry(0.9553166181245092*2)[0].cry(0.7853981633974484*2)[0,1].x[2].cx[0, 2].cx[1, 0].m[:].run(shots=100) #Counter({'001': 33, '010': 38, '100': 29})
Counter({'001': 34, '010': 27, '100': 39})

でできます。

000
100
110

の状態から、x[2]で、

001
101
111

cx[0,2]で、

001
100
110

cx[1,0]で、

001
100
010

となって無事できました。

0001,0010,0100,1000のもつれ

続いてこの調子で。まずは2量子ビットを使って、00,01,10,11のもつれを

Circuit().h[0,1].m[:].run(shots=100) #Counter({'00': 22, '01': 28, '10': 25, '11': 25})
Counter({'11': 24, '01': 26, '10': 26, '00': 24})

これにより、

00
01
10
11

ができます。ここにさらに2量子ビット付けます。

Circuit(4).h[0,1].m[:].run(shots=100) #Counter({'0000': 17, '0100': 35, '1000': 28, '1100': 20})
Counter({'0100': 24, '1100': 29, '0000': 24, '1000': 23})
0000
0100
1000
1100

続いて、一番最後にXかけて、

0001
0101
1001
1101

二番目をコントロールビットにして四番目CX

0001
0100
1001
1100

一番目をコントロールビットにして四番目CX

0001
0100
1000
1101

一番目と二番目をコントロールビットにして三番目CCX

0001
0100
1000
1111

あとは三番目をコントロールビットにして順番に1、2、4をCXして

0001
0100
1000
0010

できました!

Circuit().h[0,1].x[3].cx[1,3].cx[0,3].ccx[0,1,2].cx[2,0].cx[2,1].cx[2,3].m[:].run(shots=100) #Counter({'0001': 27, '0010': 28, '0100': 27, '1000': 18})
Counter({'0010': 24, '0100': 32, '1000': 20, '0001': 24})

いい量子コンピュータライフを!

© 2024, blueqat Inc. All rights reserved