common.title

Overview
Service overview
Terms of service

Privacy policy

Contact

Sign in
Sign up
common.title

量子コンピュータデータサイエンティスト講座:クラスタリング

Yuichiro Minato

2021/02/19 11:10

#量子コンピュータ #クラスタリング

はじめに

既存の最適化や機械学習と量子コンピュータを比べたりなどしてツールの使い方などを覚えようと思います。

概要

クラスタリングは分類問題で、グラフのノードVとエッジEがあったときに、ノードVをkのクラスタもしくはグループに分類します。

量子ビットはノードVの数にクラスタの数kをかけた数必要となり、QUBOmatrixは量子ビット数Nとして、kN*kNのサイズになります。

IMG_0011.PNG

モデル

例えば、4量子ビットで3つのクラスタは、下記のように、クラスタ内の接続とクラスタ外の接続を作ります。

IMG_0012.PNG

青はクラスタ、赤は量子ビット、黒の太い線は赤い量子ビットの3つのうちどれかが選ばれるように選ばれます。黄色は距離などでノード間の重み付けに使います。

今回はランダムに設定した点をblueqatの量子アニーリングシミュレータでクラスタリングしてみたいと思います。

例題

今回はおもにnetworkxとblueqatを使います。

4ノードを2つのクラスタに分けます。必要な量子ビット数は4*2=8です。q0,q2,q4,q6とq1,q3,q5,q7の二つのクラスタを作り、q0とq1,q2とq3、q4とq5、q6とq7は同じノードを表し、所属する方のクラスタの値が1になり、それ以外は0になります。

クラスタ内では必要に応じて接続され、重み付けがされます。今回は適当に距離を設定してみます。距離の総数の小さい方が選ばれます。左右のクラスタの重みはクラスタ内では左右同じ値が対応します。

IMG_0014.PNG

クラスタとクラスタの間では、それぞれ同じノードを表す量子ビット同士が接続され、どちらかが1、もう片方が0になるように設定されます。

IMG_0013.PNG

上の方のクラスタ内部の設定は量子ビット間の適当な重み付け(距離など)で決められそうです。

dijxixj\sum d_{ij} x_i x_j

また、下の方のクラスタ間の設定はよくある制約条件で、ノードごとに、

(i=knxi1)2\sum(\sum_{i=k}^n x_i - 1)^2

この二つを使います。QUBOは作るのは両方とも簡単にできそうです。まずはクラスタ内のエッジの条件です。今回はなんでもよかったのですが、答えのでそうなものを準備します。

IMG_0015.PNG

q1,q3,q5,q7にも同じものが同じ順番で適用されます。

ツール読み込みます。

import numpy as np import networkx as nx from blueqat.wq import * import matplotlib.pyplot as plt %matplotlib inline

まずは、クラスタ内のエッジを実装

#initialize A = np.zeros((8,8)) #weight on distance A[0][2] = 5 A[0][4] = 2 A[0][6] = 3 A[2][4] = 1 A[2][6] = 5 A[4][6] = 2 A[1][3] = 5 A[1][5] = 2 A[1][7] = 3 A[3][5] = 1 A[3][7] = 5 A[5][7] = 2 A
array([[0., 0., 5., 0., 2., 0., 3., 0.],

       [0., 0., 0., 5., 0., 2., 0., 3.],

       [0., 0., 0., 0., 1., 0., 5., 0.],

       [0., 0., 0., 0., 0., 1., 0., 5.],

       [0., 0., 0., 0., 0., 0., 2., 0.],

       [0., 0., 0., 0., 0., 0., 0., 2.],

       [0., 0., 0., 0., 0., 0., 0., 0.],

       [0., 0., 0., 0., 0., 0., 0., 0.]])

次に、制約条件を

#initialize B = np.zeros((8,8)) for i in range(8): B[i][i] = -1 for i in range(4): B[i*2][i*2+1] = 2 B
array([[-1.,  2.,  0.,  0.,  0.,  0.,  0.,  0.],

       [ 0., -1.,  0.,  0.,  0.,  0.,  0.,  0.],

       [ 0.,  0., -1.,  2.,  0.,  0.,  0.,  0.],

       [ 0.,  0.,  0., -1.,  0.,  0.,  0.,  0.],

       [ 0.,  0.,  0.,  0., -1.,  2.,  0.,  0.],

       [ 0.,  0.,  0.,  0.,  0., -1.,  0.,  0.],

       [ 0.,  0.,  0.,  0.,  0.,  0., -1.,  2.],

       [ 0.,  0.,  0.,  0.,  0.,  0.,  0., -1.]])

これもOK。そして、結合してネットワークを可視化してみます。可視化するだけなので、結合パラメータはM=1とします。

#set a QUBO M = 1 qubo = A+B*M #show as network G = nx.from_numpy_matrix(qubo) nx.draw_networkx(G) plt.show()
<Figure size 432x288 with 1 Axes>output

次にシミュレーションしてみます。

#solved on blueqat M = 10 qubo = A+B*M a = Opt() a.qubo = qubo res = a.run() res
[1, 0, 0, 1, 0, 1, 1, 0]

制約を満たすために、M=10としました。Aについてのコストだけをみてみると、

res@A@res
4.0

結果

簡単にできました。制約に課題がありますが、この部分に関してはゲートマシンでは解決方法があるので、今後みてみたいと思います。

もう少し大きめの問題でやってみます。

まずツールを入れます。今回メインで使うのは、

import numpy as np import networkx as nx from blueqat.wq import * import matplotlib.pyplot as plt from sklearn.cluster import KMeans %matplotlib inline

この辺りです。今回は40ノード、クラスタは2つに分けてみます。

n_node = 40 n_cluster = 2 N = n_node*n_cluster N
80

必要な量子ビット数は80です。結合は今回は面倒なので全結合を考えます。まずデータを作りましょう。今回はわかりやすいように、ざっくり2つの分布ができるようにしました。

x = np.random.normal(0, 1.5, int(n_node/2)) y = np.random.normal(0, 1.5, int(n_node/2)) x = np.append(x, np.random.normal(5, 1.5, int(n_node/2))) y = np.append(y, np.random.normal(5, 1.5, int(n_node/2))) # 散布図を描画 plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x7fa2e1c04850>
<Figure size 432x288 with 1 Axes>output

これでデータができました。早速Leapでクラスタリングを実行します。 5BCDFC82-536F-4996-9F1C-CD37053F7CF6.png

クラスタ内部の結合を使って、距離を求めてQUBO行列を作ります。

#initialize distance d = np.zeros((n_node,n_node)) for i in range(0, n_node-1): for j in range(i+1, n_node): a = np.array([x[i],y[i]]) b = np.array([x[j],y[j]]) d[i][j] = np.linalg.norm(a-b) #map distance to qubo A = np.zeros((N,N)) for i in range(0, n_node-1): for j in range(i+1, n_node): A[i*2][j*2] = A[i*2+1][j*2+1] = d[i][j]
#initialize constraint B = np.zeros((N,N)) for i in range(N): B[i][i] = -1 for i in range(n_node): B[i*2][i*2+1] = 2

できました。計算にかける前に参考程度にネットワークを見てみます。調整変数は小さくしてみます。

#set a QUBO M = 1 qubo = A+B*M #show as network G = nx.from_numpy_matrix(qubo) nx.draw_networkx(G) plt.show()
<Figure size 432x288 with 1 Axes>output

これにより、二つのクラスタが見えますが、実はこれは今回分類したクラスタではありません。後で解説します。二つの塊が見えて、その間がエッジでつながっています。各塊の内部は全結合になっています。調整変数を大きめにとり

#to Leap M=120 qubo = A+B*M a = Opt() a.qubo = qubo res = a.run() print(sum(res))
40

計算を投げたら少しして計算が戻ります。計算結果の合計は、40になれば大体OKだと思います。先ほどのnetworkXで書いたグラフがどのようになってるかみてみます。

#check the result as network color = ["red", "blue"] colors = [color[int(i)] for i in res] nx.draw_networkx_nodes(G, pos=nx.spring_layout(G), node_color = colors) plt.show()
<Figure size 432x288 with 1 Axes>output
plt.scatter(x, y, c=list(res)[::2])
<matplotlib.collections.PathCollection at 0x7fa2e0221e20>
<Figure size 432x288 with 1 Axes>output

続いてScikit-learnで

続いて古典でもやってみます。古典はツールが充実しているので使いやすいです。

kmeans = KMeans(n_clusters=n_cluster,random_state=0).fit(np.stack([x,y],1))

クラスタ数2とデータをまとめて入力します。これで計算が終わりました。

plt.scatter(x, y, c=kmeans.labels_)
<matplotlib.collections.PathCollection at 0x7fa2e0176820>
<Figure size 432x288 with 1 Axes>output

できました

ツールを使って簡単にクラスタリングができました。

データ処理と量子コンピュータ

前回は2つのクラスタに分けてみましたが、今回は4つにしてみたいと思います。 また、データ処理に馴染みのない人(自分を含めて)少しずつデータ処理のツールになれられるように、list, np.array ではなく、今回からPandasを使ってみます。

早速

早速やってみます。今回読み込むツールは、

import numpy as np import pandas as pd import networkx as nx from blueqat.wq import * import matplotlib.pyplot as plt from sklearn.cluster import KMeans %matplotlib inline

Numpyは通常の数値ライブラリ Pandasは、これまでデータ管理はlistやnp.arrayで行うことが多かったですが、データ処理が煩雑になると分かりづらくなるので、データを整理しながら行うことでコードが見やすく、短くなります。 Networkxは量子ビットの接続を確認するために使います。 Matplotlibは図の描画に使います。 Sklearnは量子に関係ありませんが、一応使い勝手が良いのでクラスタリングの例で見てみます。

ノードとクラスタの指定

今回はいくつでも良かったのですが、100ノードを4つのクラスタに分けてみます。

n_node = 100 n_cluster = 4 N = n_node*n_cluster print('nodes',n_node) print('clusters',n_cluster) print('qubits',N)
nodes 100

clusters 4

qubits 400

必要な量子ビットは400になります。

適当なデータを作ってみる

x,y = [],[] for i in range(n_cluster): x = np.append(x, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) y = np.append(y, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) color = [np.random.randint(0,4) for _ in range(n_node)] # 散布図を描画 plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x7fa2daa777f0>
<Figure size 432x288 with 1 Axes>output

データはなんでもいいですが、こんな感じでできました。今回は将来的に座標データを利用することを想定しています。

Colorは特に意味はありませんが、pandasを使って表を管理する際に、将来的な別のラベルを想定します。今回はcolorは使いません。

plt.scatter(x,y,c=color)
<matplotlib.collections.PathCollection at 0x7fa2da9c9520>
<Figure size 432x288 with 1 Axes>output

Pandas

Pandasを使ってデータを管理します。DataFrameを使って、x,y座標と例として用意したcolorを作るには、下記のようになります。

df = pd.DataFrame({'x':x,'y':y,'color':color}) df
            x          y  color

0   28.113550   3.767856      2

1   27.666256   4.344076      3

2   24.961899   1.848932      2

3   28.986555   4.807284      2

4   27.925991   7.386340      3

..        ...        ...    ...

95   9.914501  12.689689      3

96   5.913565  12.233850      1

97   7.467597  12.074053      1

98   7.885100  15.532731      0

99   5.097209  10.727201      0



[100 rows x 3 columns]

こんな感じで表ができました。これで、いつでもデータが簡単に指定して取り出すことができます。

もう一つ例題

データが二次元で例えば用意されていたとして、np.stackを使って表現してみます。 そのごdataを列に導入し、x,yと名前をつけてデータを作ってみます。新しい列を追加する際には、df[‘color’]と単に名前をつけてデータを導入するだけでできます。いろんな形でデータを準備できるので便利です。

data = np.stack([x,y],1) df = pd.DataFrame(data,columns=['x','y']) #add color list df['color'] = color df
            x          y  color

0   28.113550   3.767856      2

1   27.666256   4.344076      3

2   24.961899   1.848932      2

3   28.986555   4.807284      2

4   27.925991   7.386340      3

..        ...        ...    ...

95   9.914501  12.689689      3

96   5.913565  12.233850      1

97   7.467597  12.074053      1

98   7.885100  15.532731      0

99   5.097209  10.727201      0



[100 rows x 3 columns]

データの取り出し

データの取り出しは列を指定すればOKです。

#plot plt.scatter(df['x'], df['y'])
<matplotlib.collections.PathCollection at 0x7fa2da937640>
<Figure size 432x288 with 1 Axes>output
#plot plt.scatter(df['x'], df['y'], c=df['color'] )
<matplotlib.collections.PathCollection at 0x7fa2da88f280>
<Figure size 432x288 with 1 Axes>output

scikit-learnでクラスタリング

まずはscikit-learnでやってみます。クラスタリングするには、xとyの列だけを指定する必要があるので、df.locで列を指定します。今回はxとyを指定しました。

そして、クラスタ数を指定して、fitでクラスタリングを実行します。

#x,yの列だけ抜き出す。 fitxy = df.loc[:,['x','y']] kmeans = KMeans(n_clusters=n_cluster, random_state=0).fit(fitxy) print(kmeans.labels_) df['cl'] = kmeans.labels_ #result plt.scatter(df['x'], df['y'], c=df['cl'])
[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 2 2 2 2 2 2 2 2 2 2 2

 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
<matplotlib.collections.PathCollection at 0x7fa2da7cf1c0>
<Figure size 432x288 with 1 Axes>output

出来上がったクラスタリングのラベルはmeans.labels_に入ってますので、df[‘cl’]で新しく列を作成して、入れておきます。

再度の呼び出しはをして散布図を確認してみると、いい感じです。

続いてblueqat

今回はどんどん複雑になるので一般化するために関数を作ってみました。まずはすべてのノード間の距離を計算し、listのdに格納します。今回クラスタ数を4にしましたので、このdのlistを4つクローンを作る必要があります。今回のinitCostでは引数に、先ほど作ったpandasのxとy座標の入ったデータとクラスタ数を指定して実行します。

def initCost(data, n_cluster): #initialize distance n_node = len(data) d = np.zeros((n_node, n_node)) for i in range(0, n_node-1): for j in range(i+1, n_node): a = np.array([data['x'][i], data['y'][i]]) b = np.array([data['x'][j], data['y'][j]]) d[i][j] = np.linalg.norm(a-b) #map distance to qubo N = n_node*n_cluster A = np.zeros((N, N)) for i in range(0, n_node-1): for j in range(i+1, n_node): for k in range(n_cluster): A[i*n_cluster+k][j*n_cluster+k] = d[i][j] return A, d

出来上がったQUBOとdが戻ってきます。dは使わないのですが、念のため入れてあります。次にBを作ります。こちらは制約条件です。クラスタ数4ですが、そのうちの1つのクラスタに含まれる量子ビットだけが1になります。

(q0+q1+q2+q31)2(q_0+q_1+q_2+q_3-1)^2

を展開した形を実装します。

def initConst(n_node, n_cluster): #initialize constraint N = n_node * n_cluster B = np.zeros((N,N)) for i in range(N): B[i][i] = -1 for i in range(n_cluster-1): for j in range(i+1, n_cluster): for k in range(n_node): B[i+k*n_cluster][j+k*n_cluster] = 2 return B

networkXで確認

QUBOができるとネットワーク構造が明らかになりますのでみてみます。

#set a QUBO M = 1 A,d = initCost(df, n_cluster) B = initConst(n_node, n_cluster) qubo = A+B*M #show as network G = nx.from_numpy_matrix(qubo) nx.draw_networkx(G) plt.show()
<Figure size 432x288 with 1 Axes>output

真っ黒になってしまいましたが、ノードの全結合のクラスタが4つあり、それぞれの間でさらに全結合になっています。

blueqatに投げる

QUBOの調整変数を決めて、投げてみます。計算結果の要素の合計が100にならないとダメなはず(本当は4つごとに25入ってないとダメなので細かく調べる必要ありますが、今回はざっくり、、、)なので、100になるまで調整変数を調整します。

#to blueqat M=150 qubo = A+B*M a = Opt() a.qubo = qubo res = a.run() print(sum(res))
100

今回はM=100ではダメだったので、M=200から少しずつ小さくして調整してみました。

出た答えのラベルを見ますが、今回は0001のように4量子ビットごとのどこに1があるかによってラベルを判断します。0001だと3、0100だと1のように判断します。

resc = [] j = 0 for i in res: if i == 1.0: resc.append(j%n_cluster) j+=1 df['cl2'] = resc

準備したrescのlistをDataFrameに追加します、cl2としました。

確認

最後に散布図で確認します。

plt.scatter(df['x'], df['y'], c=df['cl2'])
<matplotlib.collections.PathCollection at 0x7fa2d9498490>
<Figure size 432x288 with 1 Axes>output

できました。こんな感じで頑張りましょう。

量子もつれを利用したクラスタリング

scikit-learn / pandasなどを活用して、データ利用と量子コンピューティングを同時に学び統合してきました。今回はさらに量子ゲート方式のクラスタリング手法を確認してみたいと思います。量子ゲートは量子コンピュータの本命で開発が進んでいますが、まだハードウェアのエラーが多かったり、量子ビット数が少なかったりします。 今回の量子ゲート方式でのクラスタリングは、かなり特殊な方法を使います。また、量子ビット数や量子ゲートの実効の深さがあればNISQと呼ばれる現在のマシンでも実行が可能です。

早速みてみましょう。

ツールの読み込み

今回もpythonでツールを準備します。

import numpy as np import pandas as pd import networkx as nx import matplotlib.pyplot as plt from sklearn.cluster import KMeans import blueqat from blueqat.wq import * from blueqat import vqe,Circuit from blueqat.pauli import X, Y, Z, I %matplotlib inline

前回は量子アニーリングだったのでblueqat.wqのツールを使いましたが、今回はblueqatのCircuitを使います。

まずは6ノードを2つのクラスタに

まずは簡単な例題をやってみます。サイズは大きな問題はできません。シミュレーションも回路が長いので量子ビットも15程度に抑えたいところです。

n_node = 6 n_cluster = 2 N = n_node*n_cluster print('nodes',n_node) print('clusters',n_cluster) print('qubits',N)
nodes 6

clusters 2

qubits 12

今回は12量子ビット利用します。まずはデータをざっくり作ります。

x,y = [],[] for i in range(n_cluster): x = np.append(x, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) y = np.append(y, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) # 散布図を描画 plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x7fa2d945e880>
<Figure size 432x288 with 1 Axes>output

これを分類します。作ったデータをDataFrameに入れます。x,yは今作ったデータです。zは特に使いませんが、参考にDataFrameの使い方を確認するついでに入れました。

df = pd.DataFrame({'x':x, 'y':y, 'z':[np.random.rand() for _ in range(n_node)]}) df
           x          y         z

0   6.478605  10.130512  0.927451

1   3.691610   8.122024  0.044480

2   3.172296  10.405221  0.395221

3  13.326200   4.506591  0.276267

4  10.797100   5.297671  0.352052

5  12.767047   6.548201  0.211641
#plot plt.scatter(df['x'], df['y'], c=df['z'] )
<matplotlib.collections.PathCollection at 0x7fa2d94301c0>
<Figure size 432x288 with 1 Axes>output

scikit-learnを使ってみる

まずは古典計算機でクラスタリングをします。

#x,yの列だけ抜き出す。 fitxy = df.loc[:,['x','y']] kmeans = KMeans(n_clusters=n_cluster, random_state=0).fit(fitxy) print(kmeans.labels_) df['cl'] = kmeans.labels_ #result plt.scatter(df['x'], df['y'], c=df['cl'])
[1 1 1 0 0 0]
<matplotlib.collections.PathCollection at 0x7fa2d948cb50>
<Figure size 432x288 with 1 Axes>output

データからxとyの列を抜き出して、クラスタリングします。それでkmeans.labels_の値をDataFrameに入れます。今回はクラスタは2つなので綺麗に別れました。2色に塗り分けられているのがわかります。

コスト関数

前回の量子アニーリングと同じコスト関数を利用します。

def initCost(data, n_cluster): #initialize distance n_node = len(data) d = np.zeros((n_node, n_node)) for i in range(0, n_node-1): for j in range(i+1, n_node): a = np.array([data['x'][i], data['y'][i]]) b = np.array([data['x'][j], data['y'][j]]) d[i][j] = np.linalg.norm(a-b) #map distance to qubo N = n_node*n_cluster A = np.zeros((N, N)) for i in range(0, n_node-1): for j in range(i+1, n_node): for k in range(n_cluster): A[i*n_cluster+k][j*n_cluster+k] = d[i][j] return A, d

全く同じです。しかし違うのはこれからです。

制約条件

今回制約条件は量子もつれを使ってかけます。2量子ビットのもつれはもつれの回路を作ることで実現できます。例えば01と10をもつれさせると11と00は出てきません。

今回は2つのクラスタのどちらかには必ず1があり、もう片方は0になるという条件があるので、量子もつれはH->CX->Xでかけることによりもつれを実現できます。

制約をもつれで作るので、ネットワーク構造上、QUBOには制約条件が出てきません。これが新しいところです。

ですので、QUBOはコスト関数だけで、量子アニーリングのときのように制約条件のBのQUBOは出現しません。

networkX

今回制約条件はネットワーク上には出ませんので、networkXで書いてみると、

#set a QUBO qubo,d = initCost(df, n_cluster) #show as network G = nx.from_numpy_matrix(qubo) nx.draw_networkx(G) plt.show()
<Figure size 432x288 with 1 Axes>output

直接quboを入れて、ネットワークをnetworkXで書き出してみると、6ノードの全結合が2つあります。これでネットワークができました。

量子ゲートを作る

今回の量子ゲートは、

1、初期状態でもつれを作る
2、もつれの状態を維持したまま2量子ビットを入れ替える操作を実行

上記の2種類の操作を行うために、初期状態initと入れ替え操作のmixerを準備します。

q = pauli(qubo) step = 2 #mixer and init state for i in range(n_node): if i==0: mixer = 0.5*X[0]*X[1] + 0.5*Y[0]*Y[1] init = Circuit().h[0].cx[0,1].x[0] else: mixer += 0.5*X[i*n_cluster]*X[i*n_cluster+1] + 0.5*Y[i*n_cluster]*Y[i*n_cluster+1] init.h[i*n_cluster].cx[i*n_cluster,i*n_cluster+1].x[i*n_cluster] result = vqe.Vqe(vqe.QaoaAnsatz(q, step, init, mixer)).run() resv = result.most_common(1)[0][0] print(sum(resv))
6

Initはもつれ回路と呼ばれるもので、指定の2量子ビットにH->CX->Xをかけます。また、mixerは0.5*(XX+YY)というゲートを利用します。XXとYYにはそれぞれ交換したい量子ビット同士を対応させます。

それらを準備したものが上になります。それぞれinitとmixerを確認してみると、

print(mixer) print(init)
0.5*X[0]*X[1] + 0.5*Y[0]*Y[1] + 0.5*X[2]*X[3] + 0.5*Y[2]*Y[3] + 0.5*X[4]*X[5] + 0.5*Y[4]*Y[5] + 0.5*X[6]*X[7] + 0.5*Y[6]*Y[7] + 0.5*X[8]*X[9] + 0.5*Y[8]*Y[9] + 0.5*X[10]*X[11] + 0.5*Y[10]*Y[11]

Circuit(12).h[0].cx[0, 1].x[0].h[2].cx[2, 3].x[2].h[4].cx[4, 5].x[4].h[6].cx[6, 7].x[6].h[8].cx[8, 9].x[8].h[10].cx[10, 11].x[10]

多少長いですが、Mixerと初期量子もつれ状態が求まりました。出てきた答えは下記のようにDataFrameに格納します。最後に散布図で確認をすると、

resc = [] j = 0 for i in resv: if i == 1.0: resc.append(j%n_cluster) j+=1 df['cl2'] = resc plt.scatter(df['x'], df['y'], c=df['cl2'])
<matplotlib.collections.PathCollection at 0x7fa2da16d370>
<Figure size 432x288 with 1 Axes>output

きちんとできていることがわかりました。ネットワークで繋がっていなくてももつれを活用することでクラスタリングできました。ちょっと量子っぽくて不思議ですね。ちなみに利用した回路を見てみると、

result.circuit
Circuit(12).ry(1.9106332362490184)[0].cry(1.5707963267948968)[0, 1].x[2].cx[0, 2].cx[1, 0].ry(1.9106332362490184)[3].cry(1.5707963267948968)[3, 4].x[5].cx[3, 5].cx[4, 3].ry(1.9106332362490184)[6].cry(1.5707963267948968)[6, 7].x[8].cx[6, 8].cx[7, 6].ry(1.9106332362490184)[9].cry(1.5707963267948968)[9, 10].x[11].cx[9, 11].cx[10, 9].cx[0, 3].rz(-2.5916769983258354)[3].cx[0, 3].cx[0, 6].rz(-2.859332157514607)[6].cx[0, 6].cx[0, 9].rz(-9.209377326585162)[9].cx[0, 9].rz(14.660386482425604)[0].rz(23.595425469642944)[10].rz(23.595425469642944)[11].cx[1, 10].rz(-9.209377326585162)[10].cx[1, 10].cx[1, 4].rz(-2.5916769983258354)[4].cx[1, 4].cx[1, 7].rz(-2.859332157514607)[7].cx[1, 7].rz(14.660386482425604)[1].cx[2, 11].rz(-9.209377326585162)[11].cx[2, 11].cx[2, 5].rz(-2.5916769983258354)[5].cx[2, 5].cx[2, 8].rz(-2.859332157514607)[8].cx[2, 8].rz(14.660386482425604)[2].cx[3, 6].rz(-3.15214677088277)[6].cx[3, 6].cx[3, 9].rz(-7.025008271476153)[9].cx[3, 9].rz(12.768832040684758)[3].cx[4, 10].rz(-7.025008271476153)[10].cx[4, 10].cx[4, 7].rz(-3.15214677088277)[7].cx[4, 7].rz(12.768832040684758)[4].cx[5, 11].rz(-7.025008271476153)[11].cx[5, 11].cx[5, 8].rz(-3.15214677088277)[8].cx[5, 8].rz(12.768832040684758)[5].cx[6, 9].rz(-7.361039871581624)[9].cx[6, 9].rz(13.372518799979)[6].cx[7, 10].rz(-7.361039871581624)[10].cx[7, 10].rz(13.372518799979)[7].cx[8, 11].rz(-7.361039871581624)[11].cx[8, 11].rz(13.372518799979)[8].rz(23.595425469642944)[9].h[0].h[1].cx[0, 1].rz(-1.097093824685061)[1].cx[0, 1].h[0].h[1].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[1].cx[0, 1].rz(-1.097093824685061)[1].cx[0, 1].rx(1.5707963267948966)[0].rx(1.5707963267948966)[1].h[1].h[2].cx[1, 2].rz(-1.097093824685061)[2].cx[1, 2].h[1].h[2].rx(-1.5707963267948966)[1].rx(-1.5707963267948966)[2].cx[1, 2].rz(-1.097093824685061)[2].cx[1, 2].rx(1.5707963267948966)[1].rx(1.5707963267948966)[2].h[0].h[2].cx[0, 2].rz(-1.097093824685061)[2].cx[0, 2].h[0].h[2].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[2].cx[0, 2].rz(-1.097093824685061)[2].cx[0, 2].rx(1.5707963267948966)[0].rx(1.5707963267948966)[2].h[3].h[4].cx[3, 4].rz(-1.097093824685061)[4].cx[3, 4].h[3].h[4].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[4].cx[3, 4].rz(-1.097093824685061)[4].cx[3, 4].rx(1.5707963267948966)[3].rx(1.5707963267948966)[4].h[4].h[5].cx[4, 5].rz(-1.097093824685061)[5].cx[4, 5].h[4].h[5].rx(-1.5707963267948966)[4].rx(-1.5707963267948966)[5].cx[4, 5].rz(-1.097093824685061)[5].cx[4, 5].rx(1.5707963267948966)[4].rx(1.5707963267948966)[5].h[3].h[5].cx[3, 5].rz(-1.097093824685061)[5].cx[3, 5].h[3].h[5].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[5].cx[3, 5].rz(-1.097093824685061)[5].cx[3, 5].rx(1.5707963267948966)[3].rx(1.5707963267948966)[5].h[6].h[7].cx[6, 7].rz(-1.097093824685061)[7].cx[6, 7].h[6].h[7].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[7].cx[6, 7].rz(-1.097093824685061)[7].cx[6, 7].rx(1.5707963267948966)[6].rx(1.5707963267948966)[7].h[7].h[8].cx[7, 8].rz(-1.097093824685061)[8].cx[7, 8].h[7].h[8].rx(-1.5707963267948966)[7].rx(-1.5707963267948966)[8].cx[7, 8].rz(-1.097093824685061)[8].cx[7, 8].rx(1.5707963267948966)[7].rx(1.5707963267948966)[8].h[6].h[8].cx[6, 8].rz(-1.097093824685061)[8].cx[6, 8].h[6].h[8].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[8].cx[6, 8].rz(-1.097093824685061)[8].cx[6, 8].rx(1.5707963267948966)[6].rx(1.5707963267948966)[8].h[9].h[10].cx[9, 10].rz(-1.097093824685061)[10].cx[9, 10].h[9].h[10].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[10].cx[9, 10].rz(-1.097093824685061)[10].cx[9, 10].rx(1.5707963267948966)[9].rx(1.5707963267948966)[10].h[10].h[11].cx[10, 11].rz(-1.097093824685061)[11].cx[10, 11].h[10].h[11].rx(-1.5707963267948966)[10].rx(-1.5707963267948966)[11].cx[10, 11].rz(-1.097093824685061)[11].cx[10, 11].rx(1.5707963267948966)[10].rx(1.5707963267948966)[11].h[9].h[11].cx[9, 11].rz(-1.097093824685061)[11].cx[9, 11].h[9].h[11].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[11].cx[9, 11].rz(-1.097093824685061)[11].cx[9, 11].rx(1.5707963267948966)[9].rx(1.5707963267948966)[11].cx[0, 3].rz(-37.078341986841195)[3].cx[0, 3].cx[0, 6].rz(-40.90760370940713)[6].cx[0, 6].cx[0, 9].rz(-131.75578678267655)[9].cx[0, 9].rz(209.74173247892486)[0].rz(337.57264329374226)[10].rz(337.57264329374226)[11].cx[1, 10].rz(-131.75578678267655)[10].cx[1, 10].cx[1, 4].rz(-37.078341986841195)[4].cx[1, 4].cx[1, 7].rz(-40.90760370940713)[7].cx[1, 7].rz(209.74173247892486)[1].cx[2, 11].rz(-131.75578678267655)[11].cx[2, 11].cx[2, 5].rz(-37.078341986841195)[5].cx[2, 5].cx[2, 8].rz(-40.90760370940713)[8].cx[2, 8].rz(209.74173247892486)[2].cx[3, 6].rz(-45.09681416280192)[6].cx[3, 6].cx[3, 9].rz(-100.5046768244817)[9].cx[3, 9].rz(182.6798329741248)[3].cx[4, 10].rz(-100.5046768244817)[10].cx[4, 10].cx[4, 7].rz(-45.09681416280192)[7].cx[4, 7].rz(182.6798329741248)[4].cx[5, 11].rz(-100.5046768244817)[11].cx[5, 11].cx[5, 8].rz(-45.09681416280192)[8].cx[5, 8].rz(182.6798329741248)[5].cx[6, 9].rz(-105.31217968658399)[9].cx[6, 9].rz(191.31659755879303)[6].cx[7, 10].rz(-105.31217968658399)[10].cx[7, 10].rz(191.31659755879303)[7].cx[8, 11].rz(-105.31217968658399)[11].cx[8, 11].rz(191.31659755879303)[8].rz(337.57264329374226)[9].h[0].h[1].cx[0, 1].rz(-5.214280438586125)[1].cx[0, 1].h[0].h[1].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[1].cx[0, 1].rz(-5.214280438586125)[1].cx[0, 1].rx(1.5707963267948966)[0].rx(1.5707963267948966)[1].h[1].h[2].cx[1, 2].rz(-5.214280438586125)[2].cx[1, 2].h[1].h[2].rx(-1.5707963267948966)[1].rx(-1.5707963267948966)[2].cx[1, 2].rz(-5.214280438586125)[2].cx[1, 2].rx(1.5707963267948966)[1].rx(1.5707963267948966)[2].h[0].h[2].cx[0, 2].rz(-5.214280438586125)[2].cx[0, 2].h[0].h[2].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[2].cx[0, 2].rz(-5.214280438586125)[2].cx[0, 2].rx(1.5707963267948966)[0].rx(1.5707963267948966)[2].h[3].h[4].cx[3, 4].rz(-5.214280438586125)[4].cx[3, 4].h[3].h[4].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[4].cx[3, 4].rz(-5.214280438586125)[4].cx[3, 4].rx(1.5707963267948966)[3].rx(1.5707963267948966)[4].h[4].h[5].cx[4, 5].rz(-5.214280438586125)[5].cx[4, 5].h[4].h[5].rx(-1.5707963267948966)[4].rx(-1.5707963267948966)[5].cx[4, 5].rz(-5.214280438586125)[5].cx[4, 5].rx(1.5707963267948966)[4].rx(1.5707963267948966)[5].h[3].h[5].cx[3, 5].rz(-5.214280438586125)[5].cx[3, 5].h[3].h[5].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[5].cx[3, 5].rz(-5.214280438586125)[5].cx[3, 5].rx(1.5707963267948966)[3].rx(1.5707963267948966)[5].h[6].h[7].cx[6, 7].rz(-5.214280438586125)[7].cx[6, 7].h[6].h[7].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[7].cx[6, 7].rz(-5.214280438586125)[7].cx[6, 7].rx(1.5707963267948966)[6].rx(1.5707963267948966)[7].h[7].h[8].cx[7, 8].rz(-5.214280438586125)[8].cx[7, 8].h[7].h[8].rx(-1.5707963267948966)[7].rx(-1.5707963267948966)[8].cx[7, 8].rz(-5.214280438586125)[8].cx[7, 8].rx(1.5707963267948966)[7].rx(1.5707963267948966)[8].h[6].h[8].cx[6, 8].rz(-5.214280438586125)[8].cx[6, 8].h[6].h[8].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[8].cx[6, 8].rz(-5.214280438586125)[8].cx[6, 8].rx(1.5707963267948966)[6].rx(1.5707963267948966)[8].h[9].h[10].cx[9, 10].rz(-5.214280438586125)[10].cx[9, 10].h[9].h[10].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[10].cx[9, 10].rz(-5.214280438586125)[10].cx[9, 10].rx(1.5707963267948966)[9].rx(1.5707963267948966)[10].h[10].h[11].cx[10, 11].rz(-5.214280438586125)[11].cx[10, 11].h[10].h[11].rx(-1.5707963267948966)[10].rx(-1.5707963267948966)[11].cx[10, 11].rz(-5.214280438586125)[11].cx[10, 11].rx(1.5707963267948966)[10].rx(1.5707963267948966)[11].h[9].h[11].cx[9, 11].rz(-5.214280438586125)[11].cx[9, 11].h[9].h[11].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[11].cx[9, 11].rz(-5.214280438586125)[11].cx[9, 11].rx(1.5707963267948966)[9].rx(1.5707963267948966)[11]

3つのクラスタ

今回はさらに進めます。3つのクラスタ対応です。ただ、量子ビットを増やすと大変なので、4つのノードを3つのクラスタに分けます。

n_node = 4 n_cluster = 3 N = n_node*n_cluster print('nodes',n_node) print('clusters',n_cluster) print('qubits',N)
nodes 4

clusters 3

qubits 12

12量子ビット程度ですが、現在の量子ゲートマシンならシミュレータでも十分な数です。

データ

データを作ります。4ノードです。

x,y = [],[] for _ in range(2): x = np.append(x, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) y = np.append(y, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) x = np.append(x, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) y = np.append(y, np.random.normal(np.random.randint(0,n_cluster*10), 1.5, int(n_node/n_cluster))) # 散布図を描画 plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x7fa2d9f5a880>
<Figure size 432x288 with 1 Axes>output

データを格納します。

df = pd.DataFrame({'x':x, 'y':y}) df
           x          y

0  22.352586  15.352647

1  16.351266  12.397482

2  17.065669  20.502160

3  -1.407501  16.059789

まずはscikit-learnで

まずは古典で計算してみます。

#x,yの列だけ抜き出す。 kmeans = KMeans(n_clusters=n_cluster, random_state=0).fit(df) df['cl'] = kmeans.labels_ #result plt.scatter(df['x'], df['y'], c=df['cl'])
<matplotlib.collections.PathCollection at 0x7fa2da0b2d00>
<Figure size 432x288 with 1 Axes>output

いい感じでできました。

quboでネットワーク表記

NetworkXで見てみます。今回ももつれをつかったハード制約になります。

#set a QUBO qubo,d = initCost(df, n_cluster) #show as network G = nx.from_numpy_matrix(qubo) nx.draw_networkx(G) plt.show()
<Figure size 432x288 with 1 Axes>output

4ノードの全結合が3つあります。

回路

今回は初期状態のもつれはちょっと工夫が必要です。が001,010,100という3つの状態のもつれを作ります。

q = pauli(qubo) step = 2 #mixer and init state for i in range(n_node): if i==0: mixer = 0.5*X[0]*X[1] + 0.5*Y[0]*Y[1] mixer += 0.5*X[1]*X[2] + 0.5*Y[1]*Y[2] mixer += 0.5*X[2]*X[0] + 0.5*Y[2]*Y[0] init = Circuit(N).ry(0.9553166181245092*2)[0].cry(0.7853981633974484*2)[0,1].x[2].cx[0,2].cx[1,0] else: mixer += 0.5*X[i*n_cluster]*X[i*n_cluster+1] + 0.5*Y[i*n_cluster]*Y[i*n_cluster+1] mixer += 0.5*X[i*n_cluster+1]*X[i*n_cluster+2] + 0.5*Y[i*n_cluster+1]*Y[i*n_cluster+2] mixer += 0.5*X[i*n_cluster+2]*X[i*n_cluster] + 0.5*Y[i*n_cluster+2]*Y[i*n_cluster] init.ry(0.9553166181245092*2)[i*n_cluster].cry(0.7853981633974484*2)[i*n_cluster,i*n_cluster+1].x[i*n_cluster+2].cx[i*n_cluster,i*n_cluster+2].cx[i*n_cluster+1,i*n_cluster] result = vqe.Vqe(vqe.QaoaAnsatz(q, step, init, mixer)).run() resv = result.most_common(1)[0][0] print(sum(resv))
4

Mixerは4ノードあって、0と1番目、1と2番目、2と0番目の量子ビットを順に交換しながら進めます。初期状態とmixerを確認すると、

print(mixer) print(init)
0.5*X[0]*X[1] + 0.5*Y[0]*Y[1] + 0.5*X[1]*X[2] + 0.5*Y[1]*Y[2] + 0.5*X[2]*X[0] + 0.5*Y[2]*Y[0] + 0.5*X[3]*X[4] + 0.5*Y[3]*Y[4] + 0.5*X[4]*X[5] + 0.5*Y[4]*Y[5] + 0.5*X[5]*X[3] + 0.5*Y[5]*Y[3] + 0.5*X[6]*X[7] + 0.5*Y[6]*Y[7] + 0.5*X[7]*X[8] + 0.5*Y[7]*Y[8] + 0.5*X[8]*X[6] + 0.5*Y[8]*Y[6] + 0.5*X[9]*X[10] + 0.5*Y[9]*Y[10] + 0.5*X[10]*X[11] + 0.5*Y[10]*Y[11] + 0.5*X[11]*X[9] + 0.5*Y[11]*Y[9]

Circuit(12).ry(1.9106332362490184)[0].cry(1.5707963267948968)[0, 1].x[2].cx[0, 2].cx[1, 0].ry(1.9106332362490184)[3].cry(1.5707963267948968)[3, 4].x[5].cx[3, 5].cx[4, 3].ry(1.9106332362490184)[6].cry(1.5707963267948968)[6, 7].x[8].cx[6, 8].cx[7, 6].ry(1.9106332362490184)[9].cry(1.5707963267948968)[9, 10].x[11].cx[9, 11].cx[10, 9]

こんな感じです。そして、結果をcl2に格納しました。最終的に散布図を確認すると、

resc = [] j = 0 for i in resv: if i == 1: resc.append(j%n_cluster) j+=1 df['cl2'] = resc plt.scatter(df['x'], df['y'], c=df['cl2'])
<matplotlib.collections.PathCollection at 0x7fa2d95d8400>
<Figure size 432x288 with 1 Axes>output

上手くできました。また、回路を確認してみると、、、

result.circuit
Circuit(12).ry(1.9106332362490184)[0].cry(1.5707963267948968)[0, 1].x[2].cx[0, 2].cx[1, 0].ry(1.9106332362490184)[3].cry(1.5707963267948968)[3, 4].x[5].cx[3, 5].cx[4, 3].ry(1.9106332362490184)[6].cry(1.5707963267948968)[6, 7].x[8].cx[6, 8].cx[7, 6].ry(1.9106332362490184)[9].cry(1.5707963267948968)[9, 10].x[11].cx[9, 11].cx[10, 9].cx[0, 3].rz(10.025429252823972)[3].cx[0, 3].cx[0, 6].rz(11.060804364897644)[6].cx[0, 6].cx[0, 9].rz(35.62479464450334)[9].cx[0, 9].rz(-56.71102826222495)[0].rz(-91.27459513241614)[10].rz(-91.27459513241614)[11].cx[1, 10].rz(35.62479464450334)[10].cx[1, 10].cx[1, 4].rz(10.025429252823972)[4].cx[1, 4].cx[1, 7].rz(11.060804364897644)[7].cx[1, 7].rz(-56.71102826222495)[1].cx[2, 11].rz(35.62479464450334)[11].cx[2, 11].cx[2, 5].rz(10.025429252823972)[5].cx[2, 5].cx[2, 8].rz(11.060804364897644)[8].cx[2, 8].rz(-56.71102826222495)[2].cx[3, 6].rz(12.19350423159085)[6].cx[3, 6].cx[3, 9].rz(27.17496179951543)[9].cx[3, 9].rz(-49.39389528393025)[3].cx[4, 10].rz(27.17496179951543)[10].cx[4, 10].cx[4, 7].rz(12.19350423159085)[7].cx[4, 7].rz(-49.39389528393025)[4].cx[5, 11].rz(27.17496179951543)[11].cx[5, 11].cx[5, 8].rz(12.19350423159085)[8].cx[5, 8].rz(-49.39389528393025)[5].cx[6, 9].rz(28.47483868839735)[9].cx[6, 9].rz(-51.72914728488584)[6].cx[7, 10].rz(28.47483868839735)[10].cx[7, 10].rz(-51.72914728488584)[7].cx[8, 11].rz(28.47483868839735)[11].cx[8, 11].rz(-51.72914728488584)[8].rz(-91.27459513241614)[9].h[0].h[1].cx[0, 1].rz(-8.58582998672358)[1].cx[0, 1].h[0].h[1].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[1].cx[0, 1].rz(-8.58582998672358)[1].cx[0, 1].rx(1.5707963267948966)[0].rx(1.5707963267948966)[1].h[1].h[2].cx[1, 2].rz(-8.58582998672358)[2].cx[1, 2].h[1].h[2].rx(-1.5707963267948966)[1].rx(-1.5707963267948966)[2].cx[1, 2].rz(-8.58582998672358)[2].cx[1, 2].rx(1.5707963267948966)[1].rx(1.5707963267948966)[2].h[0].h[2].cx[0, 2].rz(-8.58582998672358)[2].cx[0, 2].h[0].h[2].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[2].cx[0, 2].rz(-8.58582998672358)[2].cx[0, 2].rx(1.5707963267948966)[0].rx(1.5707963267948966)[2].h[3].h[4].cx[3, 4].rz(-8.58582998672358)[4].cx[3, 4].h[3].h[4].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[4].cx[3, 4].rz(-8.58582998672358)[4].cx[3, 4].rx(1.5707963267948966)[3].rx(1.5707963267948966)[4].h[4].h[5].cx[4, 5].rz(-8.58582998672358)[5].cx[4, 5].h[4].h[5].rx(-1.5707963267948966)[4].rx(-1.5707963267948966)[5].cx[4, 5].rz(-8.58582998672358)[5].cx[4, 5].rx(1.5707963267948966)[4].rx(1.5707963267948966)[5].h[3].h[5].cx[3, 5].rz(-8.58582998672358)[5].cx[3, 5].h[3].h[5].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[5].cx[3, 5].rz(-8.58582998672358)[5].cx[3, 5].rx(1.5707963267948966)[3].rx(1.5707963267948966)[5].h[6].h[7].cx[6, 7].rz(-8.58582998672358)[7].cx[6, 7].h[6].h[7].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[7].cx[6, 7].rz(-8.58582998672358)[7].cx[6, 7].rx(1.5707963267948966)[6].rx(1.5707963267948966)[7].h[7].h[8].cx[7, 8].rz(-8.58582998672358)[8].cx[7, 8].h[7].h[8].rx(-1.5707963267948966)[7].rx(-1.5707963267948966)[8].cx[7, 8].rz(-8.58582998672358)[8].cx[7, 8].rx(1.5707963267948966)[7].rx(1.5707963267948966)[8].h[6].h[8].cx[6, 8].rz(-8.58582998672358)[8].cx[6, 8].h[6].h[8].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[8].cx[6, 8].rz(-8.58582998672358)[8].cx[6, 8].rx(1.5707963267948966)[6].rx(1.5707963267948966)[8].h[9].h[10].cx[9, 10].rz(-8.58582998672358)[10].cx[9, 10].h[9].h[10].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[10].cx[9, 10].rz(-8.58582998672358)[10].cx[9, 10].rx(1.5707963267948966)[9].rx(1.5707963267948966)[10].h[10].h[11].cx[10, 11].rz(-8.58582998672358)[11].cx[10, 11].h[10].h[11].rx(-1.5707963267948966)[10].rx(-1.5707963267948966)[11].cx[10, 11].rz(-8.58582998672358)[11].cx[10, 11].rx(1.5707963267948966)[10].rx(1.5707963267948966)[11].h[9].h[11].cx[9, 11].rz(-8.58582998672358)[11].cx[9, 11].h[9].h[11].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[11].cx[9, 11].rz(-8.58582998672358)[11].cx[9, 11].rx(1.5707963267948966)[9].rx(1.5707963267948966)[11].cx[0, 3].rz(-13.159573628785532)[3].cx[0, 3].cx[0, 6].rz(-14.518627159277267)[6].cx[0, 6].cx[0, 9].rz(-46.76179905240987)[9].cx[0, 9].rz(74.43999984047267)[0].rz(119.80881065459445)[10].rz(119.80881065459445)[11].cx[1, 10].rz(-46.76179905240987)[10].cx[1, 10].cx[1, 4].rz(-13.159573628785532)[4].cx[1, 4].cx[1, 7].rz(-14.518627159277267)[7].cx[1, 7].rz(74.43999984047267)[1].cx[2, 11].rz(-46.76179905240987)[11].cx[2, 11].cx[2, 5].rz(-13.159573628785532)[5].cx[2, 5].cx[2, 8].rz(-14.518627159277267)[8].cx[2, 8].rz(74.43999984047267)[2].cx[3, 6].rz(-16.005431057560838)[6].cx[3, 6].cx[3, 9].rz(-35.670383944849576)[9].cx[3, 9].rz(64.83538863119593)[3].cx[4, 10].rz(-35.670383944849576)[10].cx[4, 10].cx[4, 7].rz(-16.005431057560838)[7].cx[4, 7].rz(64.83538863119593)[4].cx[5, 11].rz(-35.670383944849576)[11].cx[5, 11].cx[5, 8].rz(-16.005431057560838)[8].cx[5, 8].rz(64.83538863119593)[5].cx[6, 9].rz(-37.37662765733499)[9].cx[6, 9].rz(67.90068587417309)[6].cx[7, 10].rz(-37.37662765733499)[10].cx[7, 10].rz(67.90068587417309)[7].cx[8, 11].rz(-37.37662765733499)[11].cx[8, 11].rz(67.90068587417309)[8].rz(119.80881065459445)[9].h[0].h[1].cx[0, 1].rz(-2.2644034858651763)[1].cx[0, 1].h[0].h[1].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[1].cx[0, 1].rz(-2.2644034858651763)[1].cx[0, 1].rx(1.5707963267948966)[0].rx(1.5707963267948966)[1].h[1].h[2].cx[1, 2].rz(-2.2644034858651763)[2].cx[1, 2].h[1].h[2].rx(-1.5707963267948966)[1].rx(-1.5707963267948966)[2].cx[1, 2].rz(-2.2644034858651763)[2].cx[1, 2].rx(1.5707963267948966)[1].rx(1.5707963267948966)[2].h[0].h[2].cx[0, 2].rz(-2.2644034858651763)[2].cx[0, 2].h[0].h[2].rx(-1.5707963267948966)[0].rx(-1.5707963267948966)[2].cx[0, 2].rz(-2.2644034858651763)[2].cx[0, 2].rx(1.5707963267948966)[0].rx(1.5707963267948966)[2].h[3].h[4].cx[3, 4].rz(-2.2644034858651763)[4].cx[3, 4].h[3].h[4].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[4].cx[3, 4].rz(-2.2644034858651763)[4].cx[3, 4].rx(1.5707963267948966)[3].rx(1.5707963267948966)[4].h[4].h[5].cx[4, 5].rz(-2.2644034858651763)[5].cx[4, 5].h[4].h[5].rx(-1.5707963267948966)[4].rx(-1.5707963267948966)[5].cx[4, 5].rz(-2.2644034858651763)[5].cx[4, 5].rx(1.5707963267948966)[4].rx(1.5707963267948966)[5].h[3].h[5].cx[3, 5].rz(-2.2644034858651763)[5].cx[3, 5].h[3].h[5].rx(-1.5707963267948966)[3].rx(-1.5707963267948966)[5].cx[3, 5].rz(-2.2644034858651763)[5].cx[3, 5].rx(1.5707963267948966)[3].rx(1.5707963267948966)[5].h[6].h[7].cx[6, 7].rz(-2.2644034858651763)[7].cx[6, 7].h[6].h[7].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[7].cx[6, 7].rz(-2.2644034858651763)[7].cx[6, 7].rx(1.5707963267948966)[6].rx(1.5707963267948966)[7].h[7].h[8].cx[7, 8].rz(-2.2644034858651763)[8].cx[7, 8].h[7].h[8].rx(-1.5707963267948966)[7].rx(-1.5707963267948966)[8].cx[7, 8].rz(-2.2644034858651763)[8].cx[7, 8].rx(1.5707963267948966)[7].rx(1.5707963267948966)[8].h[6].h[8].cx[6, 8].rz(-2.2644034858651763)[8].cx[6, 8].h[6].h[8].rx(-1.5707963267948966)[6].rx(-1.5707963267948966)[8].cx[6, 8].rz(-2.2644034858651763)[8].cx[6, 8].rx(1.5707963267948966)[6].rx(1.5707963267948966)[8].h[9].h[10].cx[9, 10].rz(-2.2644034858651763)[10].cx[9, 10].h[9].h[10].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[10].cx[9, 10].rz(-2.2644034858651763)[10].cx[9, 10].rx(1.5707963267948966)[9].rx(1.5707963267948966)[10].h[10].h[11].cx[10, 11].rz(-2.2644034858651763)[11].cx[10, 11].h[10].h[11].rx(-1.5707963267948966)[10].rx(-1.5707963267948966)[11].cx[10, 11].rz(-2.2644034858651763)[11].cx[10, 11].rx(1.5707963267948966)[10].rx(1.5707963267948966)[11].h[9].h[11].cx[9, 11].rz(-2.2644034858651763)[11].cx[9, 11].h[9].h[11].rx(-1.5707963267948966)[9].rx(-1.5707963267948966)[11].cx[9, 11].rz(-2.2644034858651763)[11].cx[9, 11].rx(1.5707963267948966)[9].rx(1.5707963267948966)[11]

かなり複雑になりました。人の手で直接作るのは難しいでしょう。。。

まとめ

今回は量子もつれを使ってクラスタリングを行いました。順番に内容を押さえていくとわかりやすいと思います。将来的な応用になりますので、これからの期待が持てます。

© 2024, blueqat Inc. All rights reserved