Nobisuke
Dekisugi
RAG
Privacy policy
2021/02/19 11:10
既存の最適化や機械学習と量子コンピュータを比べたりなどしてツールの使い方などを覚えようと思います。
クラスタリングは分類問題で、グラフのノードVとエッジEがあったときに、ノードVをkのクラスタもしくはグループに分類します。
量子ビットはノードVの数にクラスタの数kをかけた数必要となり、QUBOmatrixは量子ビット数Nとして、kN*kNのサイズになります。
例えば、4量子ビットで3つのクラスタは、下記のように、クラスタ内の接続とクラスタ外の接続を作ります。
青はクラスタ、赤は量子ビット、黒の太い線は赤い量子ビットの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になります。
クラスタ内では必要に応じて接続され、重み付けがされます。今回は適当に距離を設定してみます。距離の総数の小さい方が選ばれます。左右のクラスタの重みはクラスタ内では左右同じ値が対応します。
クラスタとクラスタの間では、それぞれ同じノードを表す量子ビット同士が接続され、どちらかが1、もう片方が0になるように設定されます。
上の方のクラスタ内部の設定は量子ビット間の適当な重み付け(距離など)で決められそうです。
また、下の方のクラスタ間の設定はよくある制約条件で、ノードごとに、
この二つを使います。QUBOは作るのは両方とも簡単にできそうです。まずはクラスタ内のエッジの条件です。今回はなんでもよかったのですが、答えのでそうなものを準備します。
q1,q3,q5,q7にも同じものが同じ順番で適用されます。
ツール読み込みます。
Copy import numpy as np import networkx as nx from blueqat.wq import * import matplotlib.pyplot as plt %matplotlib inline
まずは、クラスタ内のエッジを実装
Copy #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.]])
次に、制約条件を
Copy #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とします。
Copy #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>
次にシミュレーションしてみます。
Copy #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についてのコストだけをみてみると、
Copy res@A@res
4.0
簡単にできました。制約に課題がありますが、この部分に関してはゲートマシンでは解決方法があるので、今後みてみたいと思います。
まずツールを入れます。今回メインで使うのは、
Copy 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つに分けてみます。
Copy n_node = 40 n_cluster = 2 N = n_node*n_cluster N
80
必要な量子ビット数は80です。結合は今回は面倒なので全結合を考えます。まずデータを作りましょう。今回はわかりやすいように、ざっくり2つの分布ができるようにしました。
Copy 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>
これでデータができました。早速Leapでクラスタリングを実行します。
クラスタ内部の結合を使って、距離を求めてQUBO行列を作ります。
Copy #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]
Copy #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
できました。計算にかける前に参考程度にネットワークを見てみます。調整変数は小さくしてみます。
Copy #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>
これにより、二つのクラスタが見えますが、実はこれは今回分類したクラスタではありません。後で解説します。二つの塊が見えて、その間がエッジでつながっています。各塊の内部は全結合になっています。調整変数を大きめにとり
Copy #to Leap M=120 qubo = A+B*M a = Opt() a.qubo = qubo res = a.run() print(sum(res))
40
計算を投げたら少しして計算が戻ります。計算結果の合計は、40になれば大体OKだと思います。先ほどのnetworkXで書いたグラフがどのようになってるかみてみます。
Copy #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>
Copy plt.scatter(x, y, c=list(res)[::2])
<matplotlib.collections.PathCollection at 0x7fa2e0221e20>
<Figure size 432x288 with 1 Axes>
続いて古典でもやってみます。古典はツールが充実しているので使いやすいです。
Copy kmeans = KMeans(n_clusters=n_cluster,random_state=0).fit(np.stack([x,y],1))
クラスタ数2とデータをまとめて入力します。これで計算が終わりました。
Copy plt.scatter(x, y, c=kmeans.labels_)
<matplotlib.collections.PathCollection at 0x7fa2e0176820>
<Figure size 432x288 with 1 Axes>
ツールを使って簡単にクラスタリングができました。
前回は2つのクラスタに分けてみましたが、今回は4つにしてみたいと思います。 また、データ処理に馴染みのない人(自分を含めて)少しずつデータ処理のツールになれられるように、list, np.array ではなく、今回からPandasを使ってみます。
早速やってみます。今回読み込むツールは、
Copy 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つのクラスタに分けてみます。
Copy 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になります。
Copy 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>
データはなんでもいいですが、こんな感じでできました。今回は将来的に座標データを利用することを想定しています。
Colorは特に意味はありませんが、pandasを使って表を管理する際に、将来的な別のラベルを想定します。今回はcolorは使いません。
Copy plt.scatter(x,y,c=color)
<matplotlib.collections.PathCollection at 0x7fa2da9c9520>
<Figure size 432x288 with 1 Axes>
Pandasを使ってデータを管理します。DataFrameを使って、x,y座標と例として用意したcolorを作るには、下記のようになります。
Copy 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’]と単に名前をつけてデータを導入するだけでできます。いろんな形でデータを準備できるので便利です。
Copy 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です。
Copy #plot plt.scatter(df['x'], df['y'])
<matplotlib.collections.PathCollection at 0x7fa2da937640>
<Figure size 432x288 with 1 Axes>
Copy #plot plt.scatter(df['x'], df['y'], c=df['color'] )
<matplotlib.collections.PathCollection at 0x7fa2da88f280>
<Figure size 432x288 with 1 Axes>
まずはscikit-learnでやってみます。クラスタリングするには、xとyの列だけを指定する必要があるので、df.locで列を指定します。今回はxとyを指定しました。
そして、クラスタ数を指定して、fitでクラスタリングを実行します。
Copy #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>
出来上がったクラスタリングのラベルはmeans.labels_に入ってますので、df[‘cl’]で新しく列を作成して、入れておきます。
再度の呼び出しはをして散布図を確認してみると、いい感じです。
今回はどんどん複雑になるので一般化するために関数を作ってみました。まずはすべてのノード間の距離を計算し、listのdに格納します。今回クラスタ数を4にしましたので、このdのlistを4つクローンを作る必要があります。今回のinitCostでは引数に、先ほど作ったpandasのxとy座標の入ったデータとクラスタ数を指定して実行します。
Copy 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になります。
を展開した形を実装します。
Copy 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
QUBOができるとネットワーク構造が明らかになりますのでみてみます。
Copy #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>
真っ黒になってしまいましたが、ノードの全結合のクラスタが4つあり、それぞれの間でさらに全結合になっています。
QUBOの調整変数を決めて、投げてみます。計算結果の要素の合計が100にならないとダメなはず(本当は4つごとに25入ってないとダメなので細かく調べる必要ありますが、今回はざっくり、、、)なので、100になるまで調整変数を調整します。
Copy #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のように判断します。
Copy 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としました。
最後に散布図で確認します。
Copy plt.scatter(df['x'], df['y'], c=df['cl2'])
<matplotlib.collections.PathCollection at 0x7fa2d9498490>
<Figure size 432x288 with 1 Axes>
できました。こんな感じで頑張りましょう。
scikit-learn / pandasなどを活用して、データ利用と量子コンピューティングを同時に学び統合してきました。今回はさらに量子ゲート方式のクラスタリング手法を確認してみたいと思います。量子ゲートは量子コンピュータの本命で開発が進んでいますが、まだハードウェアのエラーが多かったり、量子ビット数が少なかったりします。 今回の量子ゲート方式でのクラスタリングは、かなり特殊な方法を使います。また、量子ビット数や量子ゲートの実効の深さがあればNISQと呼ばれる現在のマシンでも実行が可能です。
早速みてみましょう。
今回もpythonでツールを準備します。
Copy 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を使います。
まずは簡単な例題をやってみます。サイズは大きな問題はできません。シミュレーションも回路が長いので量子ビットも15程度に抑えたいところです。
Copy 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量子ビット利用します。まずはデータをざっくり作ります。
Copy 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>
これを分類します。作ったデータをDataFrameに入れます。x,yは今作ったデータです。zは特に使いませんが、参考にDataFrameの使い方を確認するついでに入れました。
Copy 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
Copy #plot plt.scatter(df['x'], df['y'], c=df['z'] )
<matplotlib.collections.PathCollection at 0x7fa2d94301c0>
<Figure size 432x288 with 1 Axes>
まずは古典計算機でクラスタリングをします。
Copy #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>
データからxとyの列を抜き出して、クラスタリングします。それでkmeans.labels_の値をDataFrameに入れます。今回はクラスタは2つなので綺麗に別れました。2色に塗り分けられているのがわかります。
前回の量子アニーリングと同じコスト関数を利用します。
Copy 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で書いてみると、
Copy #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>
直接quboを入れて、ネットワークをnetworkXで書き出してみると、6ノードの全結合が2つあります。これでネットワークができました。
今回の量子ゲートは、
1、初期状態でもつれを作る
2、もつれの状態を維持したまま2量子ビットを入れ替える操作を実行
上記の2種類の操作を行うために、初期状態initと入れ替え操作のmixerを準備します。
Copy 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を確認してみると、
Copy 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に格納します。最後に散布図で確認をすると、
Copy 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>
きちんとできていることがわかりました。ネットワークで繋がっていなくてももつれを活用することでクラスタリングできました。ちょっと量子っぽくて不思議ですね。ちなみに利用した回路を見てみると、
Copy 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つのクラスタ対応です。ただ、量子ビットを増やすと大変なので、4つのノードを3つのクラスタに分けます。
Copy 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ノードです。
Copy 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>
データを格納します。
Copy 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
まずは古典で計算してみます。
Copy #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>
いい感じでできました。
NetworkXで見てみます。今回ももつれをつかったハード制約になります。
Copy #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>
4ノードの全結合が3つあります。
今回は初期状態のもつれはちょっと工夫が必要です。が001,010,100という3つの状態のもつれを作ります。
Copy 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を確認すると、
Copy 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に格納しました。最終的に散布図を確認すると、
Copy 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>
上手くできました。また、回路を確認してみると、、、
Copy 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