はじめに
量子アニーリングなどをやっているとよく使う式が出てきますが、よく使うので忘れがちなものはちょっとまとめておきます。
量子ビットを+1と-1でランダムに初期化
量子ビットは-1と+1で初期化されますので、
import numpy as np
N=10
q = np.random.choice([-1,1],N)
print(q)
#=>
[-1 1 -1 -1 -1 -1 -1 1 -1 -1]
#リストにしたいときは、
list(q)
#=>
[-1, 1, -1, -1, -1, -1, -1, 1, -1, -1]
QUBOmatrixをよしなに操作
量子アニーリングでは問題設定をQUBOという形で表現しますが、matrixを使って表現もします。QUBOmatrixはN量子ビットに対してN*Nの行列の形で、上三角行列を使って局所磁場と相互作用の計算を表現します。計算によっては、対称行列を使いたいこともありますので、
#量子ビット数を決める
N=10
#QUBOmatrixを適当に初期化
qubo = np.ones((N,N))
#=>
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., 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.]])
#上三角だけを抜き出す
np.triu(qubo)
#=>
array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
#上三角行列にしてから対称行列に戻してみる。まず上三角行列
qubo = np.triu(qubo)
#=>
array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
#戻す。上三角行列とオフセットした行列の転置をとって足し合わせる
print(np.triu(qubo)+np.triu(qubo,k=1).T)
#=>
[[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. 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.]]
QUBOとイジング変換
QUBOは{0,1}のバイナリで考える一方、イジングは{-1,+1}で考えます。相互変換が可能で量子ビットの値は、
QUBO=>イジングは、値を二倍して-1します。
0*2-1 = -1
1*2-1 = +1
のように0が-1に、1が+1に変換されます。
同様に、
イジング=>QUBOは、+1して/2します。
(-1+1)/2 = 0
(+1+1)/2 = 1
のように、-1が0に、+1が1のままとなります。コードでは、
N=10
q = np.random.choice([-1,1],N)
print(q)
#=>
[-1 1 1 -1 -1 -1 -1 -1 1 -1]
#イジングからQUBOへ
print((np.asarray(q,int)+1)/2)
#=>
[0. 1. 0. 0. 0. 0. 0. 0. 1. 1.]
#QUBOからイジングヘ
print(q*2-1)
#=>
array([ -1., 1., -1., -1., -1., -1., -1., -1., 1., 1.])
Blueqatも開発中
OSSノ量子コンピュータSDKのBlueqatにもこんなのどんどん搭載してます。ご贔屓に。。。