1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

量子ビットをイメージでつかむ(番外編)

Last updated at Posted at 2025-03-23

 一般社団法人日本量子コンピューティング協会様が新たに量子エンジニア(ゲート式)アドバンスコースとして第1回の教材を上げていただいているので、勝手ながら解説してみます。例によってJupyter notebookを https://github.com/sin-gee/ImageOfQuantumBit/ImageOfGrover2.ipynb に置いておきますのでよろしければ試してみてください。
 さて、今回対象にする量子回路は教材の30頁を確認いただきたいですが、最初のバリアの左側と、(面積的にはかなりを占める)中央と、拡散行列と記している右側に分かれています。実は基本構造はこちらで解説したものと同じです。
 左側、アダマール部分の解説は飛ばして、中央部分のゴチャゴチャしたところから解説します。この部分、エントリーコースの「バイトのシフト問題」の流用です。A,B,Cさんが以下のシフトを希望していて、どう組めばいいでしょう?という問題でした。

Aさん
Bさん
Cさん

 でいささか不条理とも思える設定ですが、シフトを分け合うことはできません。例えばBさんの希望を叶えるとBさんは昼と夜両方のシフトに入ります。昼はBさん、夜はCさん...ということはできないです。
 エントリーコースではZゲートより左までで測定する設定でした。Answerビットが1である場合の、A,B,Cのビットが1であるのものが答えでした。(AさんとBさんがシフトに入ります。)


 エントリーコース以降に追加された右側を見ていきます。
 Zゲートの意味についてはこちらを見ていただくとして、そこから右側が何をしているかを見ていきます。これは位相キックバックと呼ばれるものです。この動作を見るため、Zゲートの左側CCXと右側CCXの作用を取り出してみてみます。
最初にCCXを作用する前の状態です。一番左がAnswerビットに相当します。数値の横バーは振幅が無いことを示します(つまりAnswerビットは0)。
image.png
 CCXを作用させます。下位2ビットとも1の場合にAnswerが1になります(右端の状態)。
image.png
 ここでAnswerにZゲートを作用させます。|1xx>の位相(右の4つ)を反転させますが、振幅があるのは|111>のみですので、これが反転します(マイナスになります)。
image.png
 再びCCXを作用させます。Answerビットは0となりますが、下位2ビットが両方1の場合(|11>)に位相が反転しています(マイナスになっています)。
image.png
 これを順繰り行うことで、答えであるAさんとBさんのビットの位相のみを反転させる訳です。


 次に右側の拡散行列ですが、こちらとほぼ同じです。ただし、今回は量子ビットが3ビットになったのと、CZではなくCCXが使われていて前後のアダマールを挟まれている点が異なります。CZとH+CX+Hで同じ動きをするのでしょうか?結論から言えば同じです。
 まず、2ビットH+CX+H版はこうなります。


import numpy as np
import math
import matplotlib.patches as patches
def vector_to_vector_rotation_angle(v1, v2): #2ベクトルの角度をπ単位で算出
   return  np.arccos(np.inner(v1,v2)/(np.dot(np.linalg.norm(v1),np.linalg.norm(v2))))

dims = 2**2 # 2量子ビットのため次元数は2^2となる
x = (1/dims**0.5)
one = np.ones((dims,1))
sKet = x*one             # |s>を求める
sBra = np.transpose(sKet)# <s|を求める

HxH = np.array([[ 1, 1, 1, 1],
               [ 1,-1, 1,-1],
               [ 1, 1,-1,-1],
               [ 1,-1,-1, 1]])/2
XxX = np.array([[ 0, 0, 0, 1],
               [ 0, 0, 1, 0],
               [ 0, 1, 0, 0],
               [ 1, 0, 0, 0]])
CZ  = np.array([[ 1, 0, 0, 0],
               [ 0, 1, 0, 0],
               [ 0, 0, 1, 0],
               [ 0, 0, 0,-1]])
CX  = np.array([[ 1, 0, 0, 0],
               [ 0, 1, 0, 0],
               [ 0, 0, 0, 1],
               [ 0, 0, 1, 0]])
IH  = np.array([[ 1, 1, 0, 0],
               [ 1,-1, 0, 0],
               [ 0, 0, 1, 1],
               [ 0, 0, 1,-1]])/2**0.5

q00 = np.array([[1],[0],[0],[0]]) # Try any Vector

print('1回目のアダマール後')
G_1 = np.dot(HxH,q00)
print(G_1)

print('1回目のXゲート後')
G_2 = np.dot(XxX,G_1)
print(G_2)

print('CX前のHゲート後')
G_20 = np.dot(IH,G_2)
print(G_20)

print('CXゲート後')
G_3 = np.dot(CX,G_20)
print(G_3)

print('CX後のHゲート後')
G_30 = np.dot(IH,G_3)
print(G_30)

print('2回目のXゲート後')
G_4 = np.dot(XxX,G_30)
print(G_4)

print('2回目のHゲート後')
t00 = np.dot(HxH,G_4)
print('変換後のベクトル')
print(t00)

print('変換前と変換後(に原点で反転させた)のベクトルの間の角度は',round(vector_to_vector_rotation_angle( q00.reshape(-1),-t00.reshape(-1))/np.pi,3),'pi')
print('変換前のベクトルと|s>との間の角度は',                     round(vector_to_vector_rotation_angle( q00.reshape(-1),sKet.reshape(-1))/np.pi,3),'pi')
print('変換後(に原点で反転させた)ベクトルと|s>との間の角度は',   round(vector_to_vector_rotation_angle(sKet.reshape(-1),-t00.reshape(-1))/np.pi,3),'pi')

次に3ビットH+CCX+H版

import numpy as np
import math
import matplotlib.patches as patches
def vector_to_vector_rotation_angle(v1, v2): #2ベクトル間の角度をπ単位で算出
    return  np.arccos(np.inner(v1,v2)/(np.dot(np.linalg.norm(v1),np.linalg.norm(v2))))

dims = 2**3 # 3量子ビットのため次元数は2^3となる
x = (1/dims**0.5)
one = np.ones((dims,1))
sKet = x*one             # |s>を求める
sBra = np.transpose(sKet)# <s|を求める

HxHxH =np.array([[ 1, 1, 1, 1, 1, 1, 1, 1],
                 [ 1,-1, 1,-1, 1,-1, 1,-1],
                 [ 1, 1,-1,-1, 1, 1,-1,-1],
                 [ 1,-1,-1, 1, 1,-1,-1, 1],
                 [ 1, 1, 1, 1,-1,-1,-1,-1], 
                 [ 1,-1, 1,-1,-1, 1,-1, 1], 
                 [ 1, 1,-1,-1,-1,-1, 1, 1],
                 [ 1,-1,-1, 1,-1, 1, 1,-1]
                ])/2**1.5
XxXxX =np.array([[ 0, 0, 0, 0, 0, 0, 0, 1],
                 [ 0, 0, 0, 0, 0, 0, 1, 0],
                 [ 0, 0, 0, 0, 0, 1, 0, 0],
                 [ 0, 0, 0, 0, 1, 0, 0, 0],
                 [ 0, 0, 0, 1, 0, 0, 0, 0],
                 [ 0, 0, 1, 0, 0, 0, 0, 0],
                 [ 0, 1, 0, 0, 0, 0, 0, 0],
                 [ 1, 0, 0, 0, 0, 0, 0, 0]
                ])
CCX  = np.array([[ 1, 0, 0, 0, 0, 0, 0, 0],
                 [ 0, 1, 0, 0, 0, 0, 0, 0],
                 [ 0, 0, 1, 0, 0, 0, 0, 0],
                 [ 0, 0, 0, 1, 0, 0, 0, 0],
                 [ 0, 0, 0, 0, 1, 0, 0, 0],
                 [ 0, 0, 0, 0, 0, 1, 0, 0],
                 [ 0, 0, 0, 0, 0, 0, 0, 1],
                 [ 0, 0, 0, 0, 0, 0, 1, 0]
                ])
IIH  = np.array([[ 1, 1, 0, 0, 0, 0, 0, 0],
                 [ 1,-1, 0, 0, 0, 0, 0, 0],
                 [ 0, 0, 1, 1, 0, 0, 0, 0],
                 [ 0, 0, 1,-1, 0, 0, 0, 0],
                 [ 0, 0, 0, 0, 1, 1, 0, 0],
                 [ 0, 0, 0, 0, 1,-1, 0, 0],
                 [ 0, 0, 0, 0, 0, 0, 1, 1],
                 [ 0, 0, 0, 0, 0, 0, 1,-1]
                ])/2**0.5

q000 = np.array([[1],[0],[0],[0],[0],[0],[0],[0]]) # Try any Vector

print('1回目のアダマール後')
G_1 = np.dot(HxHxH,q000)
print(G_1)

print('1回目のXゲート後')
G_2 = np.dot(XxXxX,G_1)
print(G_2)

print('CCX前のHゲート後')
G_20 = np.dot(IIH,G_2)
print(G_20)

print('CCXゲート後')
G_3 = np.dot(CCX,G_20)
print(G_3)

print('CCX後のHゲート後')
G_30 = np.dot(IIH,G_3)
print(G_30)

print('2回目のXゲート後')
G_4 = np.dot(XxXxX,G_30)

print(G_4)
print('2回目のHゲート後')
t000 = np.dot(HxHxH,G_4)
print('変換後のベクトル')
print(t00)

print('変換前と変換後(に原点で反転させた)ベクトルの間の角度は',round(vector_to_vector_rotation_angle(q000.reshape(-1),-t000.reshape(-1))/np.pi,3),'pi')
print('変換前のベクトルと|s>との間の角度は',                   round(vector_to_vector_rotation_angle(q000.reshape(-1), sKet.reshape(-1))/np.pi,3),'pi')
print('変換後(に原点で反転させた)ベクトルと|s>との間の角度は', round(vector_to_vector_rotation_angle(sKet.reshape(-1),-t000.reshape(-1))/np.pi,3),'pi')

最後に3ビットCCZ版

import numpy as np
import math
import matplotlib.patches as patches
def vector_to_vector_rotation_angle(v1, v2): #2ベクトル間の角度をπ単位で算出
    return  np.arccos(np.inner(v1,v2)/(np.dot(np.linalg.norm(v1),np.linalg.norm(v2))))

dims = 2**3 # 3量子ビットのため次元数は2^3となる
x = (1/dims**0.5)
one = np.ones((dims,1))
sKet = x*one             # |s>を求める
sBra = np.transpose(sKet)# <s|を求める

HxHxH =np.array([[ 1, 1, 1, 1, 1, 1, 1, 1],
                 [ 1,-1, 1,-1, 1,-1, 1,-1],
                 [ 1, 1,-1,-1, 1, 1,-1,-1],
                 [ 1,-1,-1, 1, 1,-1,-1, 1],
                 [ 1, 1, 1, 1,-1,-1,-1,-1], 
                 [ 1,-1, 1,-1,-1, 1,-1, 1], 
                 [ 1, 1,-1,-1,-1,-1, 1, 1],
                 [ 1,-1,-1, 1,-1, 1, 1,-1]
                ])/2**1.5
XxXxX =np.array([[ 0, 0, 0, 0, 0, 0, 0, 1],
                 [ 0, 0, 0, 0, 0, 0, 1, 0],
                 [ 0, 0, 0, 0, 0, 1, 0, 0],
                 [ 0, 0, 0, 0, 1, 0, 0, 0],
                 [ 0, 0, 0, 1, 0, 0, 0, 0],
                 [ 0, 0, 1, 0, 0, 0, 0, 0],
                 [ 0, 1, 0, 0, 0, 0, 0, 0],
                 [ 1, 0, 0, 0, 0, 0, 0, 0]
                ])
CCZ  = np.array([[ 1, 0, 0, 0, 0, 0, 0, 0],
                 [ 0, 1, 0, 0, 0, 0, 0, 0],
                 [ 0, 0, 1, 0, 0, 0, 0, 0],
                 [ 0, 0, 0, 1, 0, 0, 0, 0],
                 [ 0, 0, 0, 0, 1, 0, 0, 0],
                 [ 0, 0, 0, 0, 0, 1, 0, 0],
                 [ 0, 0, 0, 0, 0, 0, 1, 0],
                 [ 0, 0, 0, 0, 0, 0, 0,-1]
                ])

q000 = np.array([[1],[0],[0],[0],[0],[0],[0],[0]]) # Try any Vector

print('1回目のアダマール後')
G_1 = np.dot(HxHxH,q000)
print(G_1)

print('1回目のXゲート後')
G_2 = np.dot(XxXxX,G_1)
print(G_2)

print('CCXゲート後')
G_3 = np.dot(CCZ,G_2)
print(G_3)

print('2回目のXゲート後')
G_4 = np.dot(XxXxX,G_30)
print(G_4)

print('2回目のHゲート後')
t000 = np.dot(HxHxH,G_4)
print('変換後のベクトル')
print(t00)

print('変換前と変換後(に原点で反転させた)ベクトルの間の角度は',round(vector_to_vector_rotation_angle(q000.reshape(-1),-t000.reshape(-1))/np.pi,3),'pi')
print('変換前のベクトルと|s>との間の角度は',                   round(vector_to_vector_rotation_angle(q000.reshape(-1), sKet.reshape(-1))/np.pi,3),'pi')
print('変換後(に原点で反転させた)ベクトルと|s>との間の角度は', round(vector_to_vector_rotation_angle(sKet.reshape(-1),-t000.reshape(-1))/np.pi,3),'pi')

ぜひ皆さんの手元で確認してみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?