Nobisuke
Dekisugi
RAG
Privacy policy
2021/01/31 07:53
高速フーリエ変換(FFT)は、信号処理などで離散化されたデジタル信号の周波数解析などによく使われる離散フーリエ変換(DFT)を計算機上で高速に計算するアルゴリズムですが、同様のものが量子フーリエ変換(QFT)として量子コンピュータ回路で実現できますので確認したいと思います。
離散フーリエ変換の式は下記の通りです。
ちなみに逆離散フーリエ変換は下記の通りです。
まずは離散フーリエ変換をみてみます。入力に行列変換を行うことで、出力を得ます。
N=4の時、
こちらは、N=2のフーリエ変換を再帰的に利用しています。
量子フーリエ変換は上記のベクトルの代わりに量子状態を入力として量子状態を得ます。
基底状態にあるときは、
ここで、とすると、変換部分は、
はアダマールゲート、
は高速フーリエ変換と同様に変形したあと、への再帰部分はとのテンソル積がとれて、その他行列は、回転ゲートとHゲートへ数学的に分解できる。大きなゲートになっても再帰的にどんどん計算が進む。
量子フーリエ変換の入力は01のビットになります。これらのビット入力が位相の形で量子状態として出力されます。出力状態をテンソル積を用いて表現すると、
位相にビットが現れた状態での量子状態が得られます。ここで注意したいのは、各量子状態の出現確率は確率振幅の二乗で表せられますが、どの量子状態も出現確率は同一なので測定を通じて位相が得られない点です。
高速フーリエ変換はpythonのnumpyを使うことで実装ができます。早速例題でやってみたいと思います。{0,1,0}という離散値をfftにかけてみます。
Copy import numpy as np print(np.fft.fft([0,1,0])) #[ 1. +0.j -0.5-0.8660254j -0.5+0.8660254j]
[ 1. +0.j -0.5-0.8660254j -0.5+0.8660254j]
このようになりました。高速フーリエ変換では、複素数が答えに出てきました。 再度これに逆高速フーリエ変換をかけてみて元に戻ることを確認してみたいと思います。
Copy print(np.fft.ifft(np.fft.fft([0,1,0]))) #[0.00000000e+00+0.j 1.00000000e+00+0.j 7.40148683e-17+0.j]
[0.00000000e+00+0.j 1.00000000e+00+0.j 7.40148683e-17+0.j]
多少少数はずれますが、だいたい元に戻っています。
量子フーリエ変換は上記の高速フーリエ変換と同様ですが、量子状態を入力値として出力にも量子状態を得るのが特徴です。 回路は再帰的にQFTをかけて、実現できます。
ここで特徴的なのは量子状態を出力で得ますが、計算してみると、F4 = [[1,1,1,1],[1,1j,-1,-1j],[1,-1,1,-1],[1,-1j,-1,1j]]/2 なので、
Copy print(1/2*np.array([[1,1,1,1],[1,1j,-1,-1j],[1,-1,1,-1],[1,-1j,-1,1j]])@np.array([0,0,0,1])) #[ 0.5+0.j 0. -0.5j -0.5+0.j 0. +0.5j]
[ 0.5+0.j 0. -0.5j -0.5+0.j 0. +0.5j]
状態ベクトルで量子状態が取り出せそうですが、出現確率は1/4ずつなので、観測してもダメそうです。FFTで確認してみると、
Copy np.fft.fft(np.array([0,0,0,1])/2) #array([ 0.5+0.j , 0. +0.5j, -0.5+0.j , 0. -0.5j])
array([ 0.5+0.j , 0. +0.5j, -0.5+0.j , 0. -0.5j])
符号の問題はありますが、同じように出ました。
N=2の量子フーリエ変換回路は、
--H--Rz2-----
-----*----H--
Blueqatのコードで書くと、コントロール回転ゲートは、
--H----Rz(lambda/2)--X--Rz(-lambda/2)--X------
| |
---------------------*-----------------*---H--
lambdaにはmath.pi/2をいれます。
Copy from blueqat import Circuit import math Circuit().x[0].x[1].h[0].rz(math.pi/4)[0].cx[1,0].rz(-math.pi/4)[0].cx[1,0].h[1].run() #array([ 5.00000000e-01+0.j , -8.32667268e-17-0.5j, -5.00000000e-01+0.j , 8.32667268e-17+0.5j])
array([ 0.35355339-0.35355339j, -0.35355339-0.35355339j,
-0.35355339+0.35355339j, 0.35355339+0.35355339j])
前回の結果と比べてみますと、同じになってるのが確認できます。
Copy print(1/2*np.array([[1,1,1,1],[1,1j,-1,-1j],[1,-1,1,-1],[1,-1j,-1,1j]])@np.array([0,0,0,1])) #[ 0.5+0.j 0. -0.5j -0.5+0.j 0. +0.5j]
[ 0.5+0.j 0. -0.5j -0.5+0.j 0. +0.5j]
次に3量子ビットを行なってみます。
--H--Rz2--Rz3-------------
-----*----|----H--Rz2-----
----------*-------*----H--
blueqatでは、
Copy Circuit().x[:].h[0].rz(math.pi/4)[0].cx[1,0].rz(-math.pi/4)[0].cx[1,0].rz(math.pi/8)[0].cx[2,0].rz(-math.pi/8)[0].cx[2,0].h[1].rz(math.pi/4)[1].cx[2,1].rz(-math.pi/4)[1].cx[2,1].h[2].run()
array([-0.13529903-0.32664074j, -0.32664074-0.13529903j,
-0.32664074+0.13529903j, -0.13529903+0.32664074j,
0.13529903+0.32664074j, 0.32664074+0.13529903j,
0.32664074-0.13529903j, 0.13529903-0.32664074j])
array([-0.13529903-0.32664074j, -0.32664074-0.13529903j,
-0.32664074+0.13529903j, -0.13529903+0.32664074j,
0.13529903+0.32664074j, 0.32664074+0.13529903j,
0.32664074-0.13529903j, 0.13529903-0.32664074j])
最後に4量子ビットでやってみます。
--H--Rz2--Rz3--Rz4--------------------------
-----*----|----|----H--Rz2--Rz3-------------
----------*----|-------*----|----H--Rz2-----
---------------*------------*-------*----H--
blueqatでは、
Copy Circuit().x[:].h[0].rz(math.pi/4)[0].cx[1,0].rz(-math.pi/4)[0].cx[1,0].rz(math.pi/8)[0].cx[2,0].rz(-math.pi/8)[0].cx[2,0].rz(math.pi/16)[0].cx[3,0].rz(-math.pi/16)[0].cx[3,0].h[1].rz(math.pi/4)[1].cx[2,1].rz(-math.pi/4)[1].cx[2,1].rz(math.pi/8)[1].cx[3,1].rz(-math.pi/8)[1].cx[3,1].h[2].rz(math.pi/4)[2].cx[3,2].rz(-math.pi/4)[2].cx[3,2].h[3].run()
array([-0.24519632+0.04877258j, -0.2078674 +0.13889256j,
-0.13889256+0.2078674j , -0.04877258+0.24519632j,
0.04877258+0.24519632j, 0.13889256+0.2078674j ,
0.2078674 +0.13889256j, 0.24519632+0.04877258j,
0.24519632-0.04877258j, 0.2078674 -0.13889256j,
0.13889256-0.2078674j , 0.04877258-0.24519632j,
-0.04877258-0.24519632j, -0.13889256-0.2078674j ,
-0.2078674 -0.13889256j, -0.24519632-0.04877258j])
array([-0.24519632+0.04877258j, -0.2078674 +0.13889256j,
-0.13889256+0.2078674j , -0.04877258+0.24519632j,
0.04877258+0.24519632j, 0.13889256+0.2078674j ,
0.2078674 +0.13889256j, 0.24519632+0.04877258j,
0.24519632-0.04877258j, 0.2078674 -0.13889256j,
0.13889256-0.2078674j , 0.04877258-0.24519632j,
-0.04877258-0.24519632j, -0.13889256-0.2078674j ,
-0.2078674 -0.13889256j, -0.24519632-0.04877258j])
numpyのfftでも確認してみました。元の定義の符号がFFTとQFTが異なっているので、共役をとっています。
Copy print(np.fft.fft(np.array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1])/4).conj())
[ 0.25 -0.j 0.23096988-0.09567086j 0.1767767 -0.1767767j
0.09567086-0.23096988j 0. -0.25j -0.09567086-0.23096988j
-0.1767767 -0.1767767j -0.23096988-0.09567086j -0.25 -0.j
-0.23096988+0.09567086j -0.1767767 +0.1767767j -0.09567086+0.23096988j
0. +0.25j 0.09567086+0.23096988j 0.1767767 +0.1767767j
0.23096988+0.09567086j]
[ 0.25 -0.j 0.23096988-0.09567086j 0.1767767 -0.1767767j
0.09567086-0.23096988j 0. -0.25j -0.09567086-0.23096988j
-0.1767767 -0.1767767j -0.23096988-0.09567086j -0.25 -0.j
-0.23096988+0.09567086j -0.1767767 +0.1767767j -0.09567086+0.23096988j
0. +0.25j 0.09567086+0.23096988j 0.1767767 +0.1767767j
0.23096988+0.09567086j]
以上でblueqatで実装ができました。
© 2024, blueqat Inc. All rights reserved