頭がおかしくなったわけではありません。新しい量子コンピュータのシミュレータでは、アインシュタインの縮約記法と呼ばれる方法を使って計算をします。その際にアルファベットだけでは添え字がたりませんので、unicode対応した漢字を使うということになりました。
まずは漢字を読み込んでみます。そして、文字をリスト化します。
import opt_einsum as oe
import numpy as np
kanji = ["一","七","万","三","上","下","中","九","二","五","人","今","休","何","先","入","八","六","円","出","分","前","北","十","千","午","半","南","友","右","名","四","国","土","外","大","天","女","子","学","小","山","川","左","年","後","日","時","書","月","木","本","来","東","校","母","毎","気","水","火","父","生","男","白","百","聞","行","西","見","話","語","読","車","金","長","間","雨","電","食","高","不","世","主","事","京","仕","代","以","会","住","体","作","使","借","元","兄","公","写","冬","切","別","力","勉","動","医","去","口","古","台","同","味","品","員","問","図","地","堂","場"]
len(kanji)
118
無事こちらで118文字になりました。
ここからが問題です。今回はQAOAと呼ばれる組合せ最適化問題の回路でmaxcutを解いてみようと思いますが、漢字をテンソルネットワークのエッジに対応させ、漢字を使ってテンソルの縮約を行い、最後に状態ベクトルを求めようと思います。
漢字数が118ですので、52を超えているため、numpy.einsumはつかえませんので、opt_einsumでやります。もともとその予定です。
テンソルネットワークの腕の数は、量子ビット数と問題設定によっても変わりますが、今回はせいぜい118なので、ある程度暗算であたりをつけてみて回路を実際に作ってみたいとおもいます。
たとえば16量子ビットでp=1のQAOAの場合、mixerをXとして、量子ビット数16あるので、最初に状態ベクトルの時点で漢字を16消費します。次に横磁場の固有状態である重ね合わせを作るのにHゲートをそれぞれにかけますので、行列は腕が二本ですが、状態ベクトル側の腕はすでに消費されているので、ここで消費できるのは追加で漢字16消費します。p=1での横磁場Xに対応する時間発展演算子のRXでも腕が2本ですが、入力側はmaxucutのcost hamiltonian側で消費される予定なので16消費します。この時点で何も考えずにも、16*3=48漢字が消費されます。ということで、残りは70文字です。
コストハミルトニアンでは基本的にはRZZゲートを使います(今回は面倒なのでCX-RZ-CXの時間発展演算子はつかわないでやります)ので、RZZゲート1つにつき腕が4本ですので、半分の2漢字消費します。つまり、35本エッジをmaxcut問題として設定すればよいことになります。
まず必ずつながっていたいので、16量子ビットをループ状に接続します。残り19本はランダムで設定したいと思います。
l2 = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 0], [5, 8], [7, 12], [0, 3], [2, 14], [7, 9], [7, 11], [0, 14], [6, 13], [13, 15], [8, 12], [7, 10], [10, 13], [6, 8], [2, 7], [7, 14], [1, 14], [11, 15], [1, 9], [9, 13]]
これでそろいましたね!いきなり回路作るとわけわからなくなりそうですので、まずはnetworkxで可視化してみたいと思います。結構面倒なのが、グラフ上のエッジではなく、量子回路の時間発展の中に漢字がはいってるところですかね。なので、時間発展回路をnetworkxを使ってテンソルネットワーク形式で書いてみます。。。
networkxを準備します。まずは量子ビットを準備します。
import networkx as nx
G = nx.Graph()
#量子ビットを準備
qubits = []
for i in range(16):
qubits.append("q" + str(i))
#量子ビットを準備しました
G.add_nodes_from(qubits)
# ネットワークの可視化
nx.draw(G, with_labels = True)
<Figure size 432x288 with 1 Axes>
次に、mixerXの固有状態を作るためのHゲートを適用します。
#量子ゲートを準備
hadamards = []
for i in range(16):
hadamards.append("H"+str(i))
#量子ビットを準備しました
G.add_nodes_from(hadamards)
# ネットワークの可視化
nx.draw(G, with_labels = True)
<Figure size 432x288 with 1 Axes>
さっそく漢字を使ってゲートをつないでいきます。
import matplotlib.pyplot as plt
import japanize_matplotlib
edges = []
for i in range(16):
edges.append(['q'+str(i),'H'+str(i)])
G.add_edges_from(edges)
pos = nx.spring_layout(G)
plt.figure()
nx.draw(
G, pos,
node_size=50,
labels={node: node for node in G.nodes()},
alpha = 0.2
)
edge_labels = {}
for i in range(16):
edge_labels.update([(('q'+str(i),'H'+str(i)), kanji[i])])
nx.draw_networkx_edge_labels(
G, pos,
edge_labels = edge_labels,
font_color = 'red',
font_size = 20,
font_family="IPAexGothic"
)
plt.axis('off')
plt.show()
<Figure size 432x288 with 1 Axes>
なんかよくわかりませんが漢字が出現しました。。。続けて次はイジングゲートを実装します。イジングゲートはRZZで実装します。先ほど作った配列はちょっと工夫して使う必要がありそうです。
[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 0], [5, 8], [7, 12], [0, 3], [2, 14], [7, 9], [7, 11], [0, 14], [6, 13], [13, 15], [8, 12], [7, 10], [10, 13], [6, 8], [2, 7], [7, 14], [1, 14], [11, 15], [1, 9], [9, 13]]
0量子ビットと1量子ビットをつなげる場合には、実際にはH[0]とH[1]からCX[0,1]につなげます。そのあとは、H[2]とCX[0,1]からCX[1,2]につなげることになります。これを、上のループの、[0,1]から[15,0]まで実装してみます。
edges.append(['H0','ZZ01'])
edges.append(['H1','ZZ01'])
edge_labels.update([(('H0','ZZ01'), kanji[16])])
edge_labels.update([(('H1','ZZ01'), kanji[17])])
for i in range(15):
edges.append(['ZZ'+str(i)+str(i+1),'ZZ'+str(i+1)+str(i+2)])
edges.append(['H'+str(i+2),'ZZ'+str(i+1)+str(i+2)])
edge_labels.update([(('ZZ'+str(i)+str(i+1),'ZZ'+str(i+1)+str(i+2)), kanji[i*2+18])])
edge_labels.update([(('H'+str(i+2),'ZZ'+str(i+1)+str(i+2)), kanji[i*2+19])])
edges.append(['ZZ1415','ZZ150'])
edges.append(['ZZ01','ZZ150'])
edge_labels.update([(('ZZ1415','ZZ150'), kanji[46])])
edge_labels.update([(('ZZ01','ZZ150'), kanji[47])])
G.add_edges_from(edges)
nx.draw(G, with_labels = True)
<Figure size 432x288 with 1 Axes>
何とかつながりましたので、漢字を表示してみたいと思います。
pos = nx.spring_layout(G)
plt.figure()
nx.draw(
G, pos,
node_size=100,
font_size = 5,
labels={node: node for node in G.nodes()},
alpha = 0.5
)
nx.draw_networkx_edge_labels(
G, pos,
edge_labels = edge_labels,
font_color = 'red',
font_size = 16,
font_family="IPAexGothic"
)
plt.axis('off')
plt.show()
<Figure size 432x288 with 1 Axes>
次に数合わせの19本を設定していきます。どこがつながってるのかわからなくなるので、丁寧に行きます。
[5, 8], [7, 12], [0, 3], [2, 14], [7, 9], [7, 11], [0, 14], [6, 13], [13, 15], [8, 12], [7, 10], [10, 13], [6, 8], [2, 7], [7, 14], [1, 14], [11, 15], [1, 9], [9, 13]
#5,8
a = 'ZZ56'
b = 'ZZ89'
c = 'ZZ58'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[48])])
edge_labels.update([((b, c), kanji[49])])
#7,12
a = 'ZZ78'
b = 'ZZ1213'
c = 'ZZ712'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[50])])
edge_labels.update([((b, c), kanji[51])])
#0,3
a = 'ZZ150'
b = 'ZZ34'
c = 'ZZ03'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[52])])
edge_labels.update([((b, c), kanji[53])])
#2,14
a = 'ZZ23'
b = 'ZZ1415'
c = 'ZZ214'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[54])])
edge_labels.update([((b, c), kanji[55])])
#7,9
a = 'ZZ712'
b = 'ZZ910'
c = 'ZZ79'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[56])])
edge_labels.update([((b, c), kanji[57])])
#7,11
a = 'ZZ79'
b = 'ZZ1112'
c = 'ZZ711'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[58])])
edge_labels.update([((b, c), kanji[59])])
#0,14
a = 'ZZ03'
b = 'ZZ214'
c = 'ZZ014'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[60])])
edge_labels.update([((b, c), kanji[61])])
#6,13
a = 'ZZ67'
b = 'ZZ1314'
c = 'ZZ613'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[62])])
edge_labels.update([((b, c), kanji[63])])
#13,15
a = 'ZZ613'
b = 'ZZ150'
c = 'ZZ1315'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[64])])
edge_labels.update([((b, c), kanji[65])])
#8,12
a = 'ZZ58'
b = 'ZZ712'
c = 'ZZ812'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[66])])
edge_labels.update([((b, c), kanji[67])])
#7,10
a = 'ZZ711'
b = 'ZZ1011'
c = 'ZZ710'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[68])])
edge_labels.update([((b, c), kanji[69])])
#10,13
a = 'ZZ710'
b = 'ZZ1315'
c = 'ZZ1013'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[70])])
edge_labels.update([((b, c), kanji[71])])
#6,8
a = 'ZZ613'
b = 'ZZ812'
c = 'ZZ68'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[72])])
edge_labels.update([((b, c), kanji[73])])
#2,7
a = 'ZZ214'
b = 'ZZ710'
c = 'ZZ27'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[74])])
edge_labels.update([((b, c), kanji[75])])
#7,14
a = 'ZZ27'
b = 'ZZ014'
c = 'ZZ714'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[76])])
edge_labels.update([((b, c), kanji[77])])
#1,14
a = 'ZZ12'
b = 'ZZ714'
c = 'ZZ114'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[78])])
edge_labels.update([((b, c), kanji[79])])
#11,15
a = 'ZZ711'
b = 'ZZ1315'
c = 'ZZ1115'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[80])])
edge_labels.update([((b, c), kanji[81])])
#1,9
a = 'ZZ114'
b = 'ZZ79'
c = 'ZZ19'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[82])])
edge_labels.update([((b, c), kanji[83])])
#9,13
a = 'ZZ19'
b = 'ZZ1013'
c = 'ZZ913'
edges.append([a, c])
edges.append([b, c])
edge_labels.update([((a, c), kanji[84])])
edge_labels.update([((b, c), kanji[85])])
G.add_edges_from(edges)
nx.draw(G, with_labels = True)
<Figure size 432x288 with 1 Axes>
次に横磁場時間発展を追加します。面倒なのがつながりを考えないといけないところですかね。ついでに測定までつなげてしまいます。
#0
a = 'ZZ014'
b = 'RX0'
c = 'M0'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[86])])
edge_labels.update([((b, c), kanji[87])])
#1
a = 'ZZ19'
b = 'RX1'
c = 'M1'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[88])])
edge_labels.update([((b, c), kanji[89])])
#2
a = 'ZZ27'
b = 'RX2'
c = 'M2'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[90])])
edge_labels.update([((b, c), kanji[91])])
#3
a = 'ZZ03'
b = 'RX3'
c = 'M3'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[92])])
edge_labels.update([((b, c), kanji[93])])
#4
a = 'ZZ45'
b = 'RX4'
c = 'M4'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[94])])
edge_labels.update([((b, c), kanji[95])])
#5
a = 'ZZ58'
b = 'RX5'
c = 'M5'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[96])])
edge_labels.update([((b, c), kanji[97])])
#6
a = 'ZZ68'
b = 'RX6'
c = 'M6'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[98])])
edge_labels.update([((b, c), kanji[99])])
#7
a = 'ZZ714'
b = 'RX7'
c = 'M7'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[100])])
edge_labels.update([((b, c), kanji[101])])
#8
a = 'ZZ68'
b = 'RX8'
c = 'M8'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[102])])
edge_labels.update([((b, c), kanji[103])])
#9
a = 'ZZ913'
b = 'RX9'
c = 'M9'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[104])])
edge_labels.update([((b, c), kanji[105])])
#10
a = 'ZZ1013'
b = 'RX10'
c = 'M10'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[106])])
edge_labels.update([((b, c), kanji[107])])
#11
a = 'ZZ1115'
b = 'RX11'
c = 'M11'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[108])])
edge_labels.update([((b, c), kanji[109])])
#12
a = 'ZZ812'
b = 'RX12'
c = 'M12'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[110])])
edge_labels.update([((b, c), kanji[111])])
#13
a = 'ZZ913'
b = 'RX13'
c = 'M13'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[112])])
edge_labels.update([((b, c), kanji[113])])
#14
a = 'ZZ114'
b = 'RX14'
c = 'M14'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[114])])
edge_labels.update([((b, c), kanji[115])])
#15
a = 'ZZ1115'
b = 'RX15'
c = 'M15'
edges.append([a, b])
edges.append([b, c])
edge_labels.update([((a, b), kanji[116])])
edge_labels.update([((b, c), kanji[117])])
G.add_edges_from(edges)
nx.draw(G, with_labels = True)
<Figure size 432x288 with 1 Axes>
できました!漢字を表示してみます!
pos = nx.spring_layout(G)
plt.figure(figsize=(15,15))
nx.draw(
G, pos,
node_size=100,
font_size = 5,
labels={node: node for node in G.nodes()},
alpha = 0.5
)
nx.draw_networkx_edge_labels(
G, pos,
edge_labels = edge_labels,
font_color = 'red',
font_size = 16,
font_family="IPAexGothic"
)
plt.axis('off')
plt.show()
<Figure size 1080x1080 with 1 Axes>
だいぶましになりましたが、何をしているのかわからなくなってきました。。。ちょっと疲れたのでこの辺りでいったん切り上げます。次回は後編でopt_einsumを使って漢字を使って行列計算します。