common.title

Docs
Quantum Circuit
TYTAN CLOUD

QUANTUM GAMING


Overview
Contact
Event
Project
Research

Terms of service (Web service)

Terms of service (Quantum and ML Cloud service)

Privacy policy


Sign in
Sign up
common.title

[基礎]テンソルネットワークで量子もつれ回路をCNOT回路の分析

Yuichiro Minato

2023/04/03 13:28

1

こんにちは、テンソルネットがわかりづらいという質問を結構インターンでもらいましたので、ちょっとやってみます。

1、まずは普通の量子もつれ回路を作ってみます。

量子もつれ回路はH-CXで作れます。Cは制御ビットを表しています。

q- --H-- --C--
|
q- ----- --X--

今回はGoogleのtensornetworkライブラリを使いました。もちろんcuTensorNetでもいいです。

!pip install tensornetwork

まずはツールを読み込み、初期状態の状態ベクトルを準備します。HゲートとCXゲートを設定します。CXゲートは4*4ではなく、2*2*2*2のように腕の数を行列からrank4のテンソルに変更しておきます。

import numpy as np
import tensornetwork as tn

#量子ビットを準備
psi0 = tn.Node(np.array([1,0])) 
psi1 = tn.Node(np.array([1,0]))

#Hゲートを準備
H = tn.Node(np.array([[1,1],[1,-1]])/np.sqrt(2))
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))

次にエッジを作ります。psi0の量子状態はまずHと繋いでからCXに。psi1の方はCXに直接繋ぎます。

繋いだら縮約を実行し、最終的に得られたノードをテンソルとして取り出します。

最終的なテンソルは状態ベクトルの形になってるはずなので、ベクトルの形に変更をします。

edge1 = psi0[0] ^ H[0]
edge2 = H[1] ^ CX[0]
edge3 = psi1[0] ^ CX[1]

con1 = tn.contract(edge1)
con2 = tn.contract(edge2)
con3 = tn.contract(edge3)

print(con3.tensor.reshape(4))

そうすると、

[0.70710678 0. 0. 0.70710678]

きちんと|00>と|11>状態の確率振幅が得られました。

2、次にCNOTゲートの仕組みをテンソルで確認

次にCNOTゲートの仕組みをテンソルで確認します。制御ビットとターゲットビットの仕組みをテンソル縮約で確認します。

--C--
|
--X--

上記のようにCを制御ビット、Xをターゲットビットとします。CXゲートは条件付きゲートですから、制御ビット側が0の時にはターゲットビットは何もせず、制御ビット側が1の時にはターゲットビットはXの操作をします。

今回は制御側の動きがどうターゲットビット側のテンソルに影響するのかみてみます。下記のように状態を置きます。制御側のビットは|0>を採用します。測定はもちろん|0>が得られるはずです。

#量子ビットと測定を準備
psi0 = tn.Node(np.array([1,0])) 
m0 = tn.Node(np.array([1,0]))

#CXゲートを準備
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))

このように表現しました。

|0>--C-- M=|0>
|
--X--

エッジを作成し縮約します。

edge1 = psi0[0] ^ CX[0] 
edge2 = m0[0] ^ CX[2]

con1 = tn.contract(edge1)
con2 = tn.contract(edge2)

制御ビット側の入力(初期量子状態)と出力側(測定結果の量子状態)を縮約した結果、このテンソルは行列になります。

--U--

縮約結果のノードは行列になっているはずです。確認します。

print(con2.tensor)

[[1 0]
[0 1]]

単位行列になりました。制御側のビットの値が|0>の場合には、ターゲットビット側は単位行列が適用されています。次に制御側を|1>にしてみます。

#量子ビットを準備
psi0 = tn.Node(np.array([0,1])) 
m0 = tn.Node(np.array([0,1]))

#CXゲートを準備
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))

初期状態と測定結果を変更した以外は同じです。

edge1 = psi0[0] ^ CX[0] 
edge2 = m0[0] ^ CX[2]

con1 = tn.contract(edge1)
con2 = tn.contract(edge2)

print(con2.tensor)

計算結果は、

[[0 1]
[1 0]]

Xゲートとなりました。制御ビットの値によって行列が変化するのがわかりました。最後に制御側の入力量子状態を任意の量子状態とします。

import sympy as sym
a, b = sym.symbols('a b')

#量子ビットを準備
psi1 = tn.Node(np.array([a,b]))
m1 = tn.Node(np.array([a,b]))

#CXゲートを準備
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))

量子回路自体は先ほどと同じです。初期の量子状態を確率振幅[a,b]と設定しました。

edge1 = psi1[0] ^ CX[0] 
edge2 = m1[0] ^ CX[2]

con1 = tn.contract(edge1)
con2 = tn.contract(edge2)

print(con2.tensor)

計算結果は、

[[a**2 b**2]
[b**2 a**2]]

こうなりました。確かに制御側の量子ビットの量子状態によってターゲット側の行列が変化していますね。複数のマルチコントロールドゲートでも同様の計算結果が得られると思いますので、ぜひ試してみてください。

© 2025, blueqat Inc. All rights reserved