特異値分解
今回は量子ゲートの分解でも利用される特異値分解を見てみます。
まずはツールを読み込みます。
!pip install tensornetwork
Collecting tensornetwork
Using cached tensornetwork-0.4.6-py3-none-any.whl (364 kB)
Requirement already satisfied: scipy>=1.1 in /opt/conda/lib/python3.10/site-packages (from tensornetwork) (1.8.1)
Requirement already satisfied: h5py>=2.9.0 in /opt/conda/lib/python3.10/site-packages (from tensornetwork) (3.7.0)
Requirement already satisfied: opt-einsum>=2.3.0 in /opt/conda/lib/python3.10/site-packages (from tensornetwork) (3.3.0)
Collecting graphviz>=0.11.1
Using cached graphviz-0.20-py3-none-any.whl (46 kB)
Requirement already satisfied: numpy>=1.17 in /opt/conda/lib/python3.10/site-packages (from tensornetwork) (1.21.0)
Installing collected packages: graphviz, tensornetwork
Successfully installed graphviz-0.20 tensornetwork-0.4.6
量子コンピュータのゲートでのCNOTをみてみましょう。CXともいわれます。
import tensornetwork as tn
import numpy as np
#行列
cx = tn.Node(np.array([[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]]).reshape(2,2,2,2))
print(cx.tensor)
[[[[1 0]
[0 0]]
[[0 1]
[0 0]]]
[[[0 0]
[0 1]]
[[0 0]
[1 0]]]]
次にこれを分解します。特異値分解では3つのパートに分解されます。左右の腕を残したまま分解します。
U, s, V, trun_error = tn.split_node_full_svd(cx, [cx[0],cx[1]], [cx[2],cx[3]])
無事分解できたので三つのテンソルを確認します。まずはU。
U.tensor
array([[[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.]],
[[ 0., 0., 0., -1.],
[ 0., 0., -1., 0.]]])
そしてV
V.tensor
array([[[ 1., 0.],
[ 0., 0.]],
[[ 0., 1.],
[ 0., 0.]],
[[-0., -0.],
[-1., -0.]],
[[-0., -0.],
[-0., -1.]]])
最後にs
s.tensor
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
sは対角行列となっています。前回のトライアルとでは真ん中のsは自動的に平方根をつけて左右に割り振られていました。分解されたテンソルが元に戻るか確認してみます。
final = U@s@V
print(final.tensor.reshape(4,4))
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 0. 1.]
[0. 0. 1. 0.]]
元に戻りましたね。真ん中のsを4x4から3x3にしてみます。
s_dash = s.tensor[:3,:3]
print(s_dash)
[[1 0 0]
[0 1 0]
[0 0 1]]
いつも通り行列に戻してみると、
U.tensor.reshape(4,4)@s.tensor@V.tensor.reshape(4,4)
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 0., 1.],
[0., 0., 1., 0.]])
sの次元を削ったものでやってみると、
U.tensor.reshape(4,4)[:,:3]@s.tensor[:3,:3]@V.tensor.reshape(4,4)[:3,:]
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 1., 0.]])
もとの行列とちょっと変わってしまいました。さらに削ってみると、
U.tensor.reshape(4,4)[:,:2]@s.tensor[:2,:2]@V.tensor.reshape(4,4)[:2,:]
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
だいぶ削れました。CXで近似は無理がありました。きちんとsを保存する必要があります。より大きな行列ではどうなるかを見てみます。
もはや量子ゲートではないですが、適当な行列を作ってみます。
a = np.array([np.random.randint(100) for _ in range(100)])
from matplotlib import pyplot as plt
plt.imshow(a.reshape(10,10), interpolation='nearest')
plt.show()
<Figure size 432x288 with 1 Axes>
なんか画像となりました。これを分解してみます。
b = tn.Node(a.reshape(10,10))
print(b.tensor)
U, s, V, trun_error = tn.split_node_full_svd(b, [b[0]], [b[1]])
[[72 32 73 77 63 43 86 51 54 77]
[81 92 67 16 39 21 75 71 32 46]
[32 41 62 37 68 47 2 69 41 55]
[32 59 80 86 65 55 61 22 49 53]
[59 36 94 34 1 62 76 4 37 10]
[75 1 59 21 98 51 8 65 11 76]
[33 68 45 55 78 1 61 65 58 57]
[15 74 60 78 17 5 11 2 14 52]
[11 96 53 56 39 25 53 44 90 41]
[35 80 51 10 66 63 54 3 23 60]]
できたsを見てみます。
s.tensor
array([[498, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 136, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 111, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 92, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 77, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 63, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 56, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 21, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 12, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6]])
戻してみます。
c = U@s@V
plt.imshow(c.tensor.reshape(10,10), interpolation='nearest')
plt.show()
<Figure size 432x288 with 1 Axes>
画像を見る限りはきちんと戻ってますね。では、sを削って近似してみます。
N = 9
d = U.tensor.reshape(10,10)[:,:N]@s.tensor[:N,:N]@V.tensor.reshape(10,10)[:N,:]
plt.imshow(d, interpolation='nearest')
plt.show()
<Figure size 432x288 with 1 Axes>
あまり違いは見えません。
N = 3
d = U.tensor.reshape(10,10)[:,:N]@s.tensor[:N,:N]@V.tensor.reshape(10,10)[:N,:]
plt.imshow(d, interpolation='nearest')
plt.show()
<Figure size 432x288 with 1 Axes>
かなり変わってしまいましたが、真ん中あたりは面影が見えます。
N = 5
d = U.tensor.reshape(10,10)[:,:N]@s.tensor[:N,:N]@V.tensor.reshape(10,10)[:N,:]
plt.imshow(d, interpolation='nearest')
plt.show()
<Figure size 432x288 with 1 Axes>
多少の面影はありますね。このように、画像を圧縮することができます。今後はより大きな量子ゲート計算にこのSVDを適用しますが、コツがありますので今後はそれも見ていきます。