NVIDIAのcuQuantumを利用することで、マルチGPUを活用した高度な量子計算が大規模に行えます。今回は規模は小さいですが実装をしてみましたのでご紹介します。数百のみならず、今後は数千・数万量子ビットの量子ゲート計算が可能になりました。
import opt_einsum as oe
from cuquantum import contract
import numpy as np
kanji = [oe.get_symbol(i) for i in range(118)]
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]]
#量子ビット数
N = 16
#初期量子状態
psi = np.array([1,0], dtype="complex128")
arr_tensor = []
arr_arm = []
#kanji
n_kanji = 0
for i in range(N):
    arr_arm.append(kanji[i])
    arr_tensor.append(psi)
    
arr_state = []
for i in range(N):
    arr_state.append(arr_arm[i])
    n_kanji += 1
    
H = np.array([[1,1],[1,-1]], dtype="complex128")/np.sqrt(2)
for i in range(N):
    arr_tensor.append(H)
    arr_arm.append(arr_state[i] + kanji[n_kanji])
    arr_state[i] = kanji[n_kanji]
    n_kanji += 1
    
theta = np.random.rand()*np.pi*2
ZZ = np.array([[np.exp(-1*1j*theta/2),0,0,0],[0,np.exp(-1*1j*theta/2),0,0],[0,0,np.exp(1j*theta/2),0],[0,0,0,np.exp(-1*1j*theta/2)]], dtype="complex128").reshape(2,2,2,2)
for item in l2:
    in1 = item[0]
    in2 = item[1]
    arr_tensor.append(ZZ)
    arr_arm.append(arr_state[in1] + arr_state[in2] + kanji[n_kanji] + kanji[n_kanji+1])
    arr_state[in1] = kanji[n_kanji]
    arr_state[in2] = kanji[n_kanji+1]
    n_kanji += 2
    
theta2 = np.random.rand()*np.pi*2
RX = np.array([[np.cos(theta2/2),-1j*np.sin(theta2/2)],[-1j*np.sin(theta2/2),np.cos(theta2/2)]], dtype="complex128")
for i in range(N):
    arr_tensor.append(RX)
    arr_arm.append(arr_state[i] + kanji[n_kanji])
    arr_state[i] = kanji[n_kanji]
    n_kanji += 1
r = contract(','.join(arr_arm), *arr_tensor)
r.reshape(2**N)
import numpy as np
kanji = [oe.get_symbol(i) for i in range(118)]
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]]
#量子ビット数
N = 16
#初期量子状態
psi = np.array([1,0], dtype="complex128")
arr_tensor = []
arr_arm = []
#kanji
n_kanji = 0
for i in range(N):
    arr_arm.append(kanji[i])
    arr_tensor.append(psi)
    
arr_state = []
for i in range(N):
    arr_state.append(arr_arm[i])
    n_kanji += 1
    
H = np.array([[1,1],[1,-1]], dtype="complex128")/np.sqrt(2)
for i in range(N):
    arr_tensor.append(H)
    arr_arm.append(arr_state[i] + kanji[n_kanji])
    arr_state[i] = kanji[n_kanji]
    n_kanji += 1
    
theta = np.random.rand()*np.pi*2
ZZ = np.array([[np.exp(-1*1j*theta/2),0,0,0],[0,np.exp(-1*1j*theta/2),0,0],[0,0,np.exp(1j*theta/2),0],[0,0,0,np.exp(-1*1j*theta/2)]], dtype="complex128").reshape(2,2,2,2)
for item in l2:
    in1 = item[0]
    in2 = item[1]
    arr_tensor.append(ZZ)
    arr_arm.append(arr_state[in1] + arr_state[in2] + kanji[n_kanji] + kanji[n_kanji+1])
    arr_state[in1] = kanji[n_kanji]
    arr_state[in2] = kanji[n_kanji+1]
    n_kanji += 2
    
theta2 = np.random.rand()*np.pi*2
RX = np.array([[np.cos(theta2/2),-1j*np.sin(theta2/2)],[-1j*np.sin(theta2/2),np.cos(theta2/2)]], dtype="complex128")
for i in range(N):
    arr_tensor.append(RX)
    arr_arm.append(arr_state[i] + kanji[n_kanji])
    arr_state[i] = kanji[n_kanji]
    n_kanji += 1
r = contract(','.join(arr_arm), *arr_tensor)
r.reshape(2**N)
これを実行し、状態ベクトルを取得できました。16量子ビットです。
array([0.00824732+0.01775042j, 0.00892071+0.01081702j,
0.0086728 +0.01309864j, ..., 0.00096275-0.01151744j,
0.0117274 -0.00364553j, 0.00917731+0.01767776j])
中身はそのうち解説します。
