周期グラフ上の離散時間量子ウォーク(Qiskit)

# 量子ウォーク

量子ウォークは、色々と応用が広い（らしい）量子問題です。
今回は簡単な例をqiskitで実装したサンプルコードを使って勉強します。
https://github.com/qiskit-community/qiskit-community-tutorials/blob/master/terra/qis_adv/quantum_walk.ipynb

なお上記サンプルコードにはtypoらしきものがあるので、修正していきます。

# What is 量子ウォーク

8ノードの周期グラフ上の量子ウォークを考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/acb8e74b-b172-e0d2-83b6-65455599d3da.png)

量子力学っぽい言い方をします。
1量子の量子状態$|\psi \rangle$を考える。量子は8通りの位置のどこかに（一般には重ね合わせも許して）住んでいる。
つまり、{$|x=1\rangle, |x=2\rangle,...., |x=8\rangle$} を基底に持つ（位置基底）。[^1]
これを2進数表記すると、上記グラフのようになる。
また、量子はカイラリティと呼ばれる自由度{$|R\rangle, |L \rangle$}も持っている。
つまりこの1量子の量子状態の（カイラリティも含む）基底は　
{$|x=1\rangle \otimes |R \rangle, |x=1\rangle \otimes |L \rangle, |x=2\rangle \otimes |R \rangle...., |x=8\rangle \otimes |L \rangle$}
となる。

状態が定義できたので、次にこのグラフ上を”ウォーク”するシフト作用$S$を定義します。

- 量子状態が $|x=k\rangle \otimes |R \rangle$ であるとき(kは何でも良い）、このグラフ上を”右に”動く; $|x=k+1\rangle \otimes |R \rangle$
- 量子状態が $|x=k\rangle \otimes |L \rangle$ であるとき(kは何でも良い）、このグラフ上を”左に”動く; $|x=k-1\rangle \otimes |L \rangle$

もちろん、一般の量子状態は位置に関して重ね合わせされていますので、それらが同時に動くことになります。
”衝突”するのでは？と思いますが、そのとおりです。
線形性から、”衝突”した場合は、振幅が足し合わされることになります。干渉が起きるわけですね。

次に、コイン作用素$C$を定義します。
こちらは簡単で、

- 量子状態が $|x=k\rangle \otimes |W \rangle$ であるとき(k,Wは何でも良い）、カイラリティ次元に$H$を作用させる; $|x=k\rangle \otimes H|W \rangle$


となります。
位置はそのままで、カイラリティを変える、例えば$L$と$R$を入れ替えたり、$L$だけの状態を$R$と$L$の重ね合わせにしたりします。
$H$としては好きなユニタリ行列を考えましょう。何にしたかによって量子ウォークの挙動が変わります。
サンプルではアダマールゲートとしています。

量子ウォークでは、上記のコイン作用素$C$とシフト作用素$S$を1セットとして、繰り返します。
はじめに原点$|x=0 \rangle$に局在していたカイラリティ$|L \rangle$の状態が、ウォークと共に拡散していくこととなります。[^2]

# 量子ビットと量子ゲートによる実装

上記問題を量子ビットで表現します。位置の量子ビットとしては3 bit、カイラリティとしては1 bitあればよいでしょう。[^3]
コイン作用素は簡単で、カイラリティ次元の量子ビットにゲート$H$をかけてやればよいです。
シフト作用素は、カイラリティ次元の量子ビットを制御ビットとする”制御位置シフトゲート”をかけてやればよいです。
位置のシフトとは、カイラリティがRのときは位置(2進数表示)に1を足すことになりますので、加算器の応用で作れるでしょう。
例えば000が001へ行き、111が000へ行くようなゲートです。
カイラリティがLのときは減算器になるでしょう。
step = 2 のイメージ図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/3e2cf80d-7ea4-5711-f8d3-2b0a8c9649ff.png)


やってみますと、以下のようになります。
加算器・減算器を作るためにはマルチ制御ノットゲートCNXが必要なので、最初にそれを定義して、あとは組み合わせです。

```python
import numpy as np
from qiskit import IBMQ, QuantumCircuit, ClassicalRegister, QuantumRegister, execute
from qiskit.tools.visualization import plot_histogram
from qiskit import Aer

n=3

def cnx(qc, *qubits):
    if len(qubits) >= 3:
        last = qubits[-1]
        # A matrix: (made up of a  and Y rotation, lemma4.3)
        qc.crz(np.pi/2, qubits[-2], qubits[-1])
        qc.cu3(np.pi/2, 0, 0, qubits[-2],qubits[-1])
        
        # Control not gate
        cnx(qc,*qubits[:-2],qubits[-1])
        
        # B matrix (pposite angle)
        qc.cu3(-np.pi/2, 0, 0, qubits[-2], qubits[-1])
        
        # Control
        cnx(qc,*qubits[:-2],qubits[-1])
        
        # C matrix (final rotation)
        qc.crz(-np.pi/2,qubits[-2],qubits[-1])
    elif len(qubits)==3:
        qc.ccx(*qubits)
    elif len(qubits)==2:
        qc.cx(*qubits)

def increment_gate(qwc, q, subnode):
  
  cnx(qwc, subnode, q[2], q[1], q[0])
  cnx(qwc, subnode, q[2], q[1])
  cnx(qwc, subnode, q[2])
  qwc.barrier()
  return qwc

def decrement_gate(qwc, q, subnode):
  
  qwc.x(subnode)
  qwc.x(q[2])
  qwc.x(q[1])
  cnx(qwc, subnode, q[2], q[1], q[0])
  qwc.x(q[1])
  cnx(qwc, subnode, q[2], q[1])
  qwc.x(q[2])
  cnx(qwc, subnode, q[2])
  qwc.x(subnode)
  return qwc
  
def ibmsim(circ):
  ibmqBE = Aer.get_backend('qasm_simulator')
  return execute(circ,ibmqBE, shots=1000).result().get_counts(circ)  

qnodes = QuantumRegister(n,'qc')
qsubnodes = QuantumRegister(1,'qanc')
#csubnodes = ClassicalRegister(1,'canc')
cnodes = ClassicalRegister(n,'cr')

qwc = QuantumCircuit(qnodes, qsubnodes, cnodes)


def runQWC(qwc, times):
    for i in range(times):
        qwc.h(qsubnodes)
        increment_gate(qwc, qnodes, qsubnodes)
        decrement_gate(qwc,qnodes,qsubnodes)
        qwc.barrier()
        qwc.measure(qnodes, cnodes)

    return qwc

```

できました。初期状態 step = 0 をみてみます。

```python
import matplotlib as mpl

# zero-padding
def zero_padding_counts(counts):
    nqubits = n
    for i in range (2**nqubits):
        counts.setdefault(format(i, '0'+str(nqubits)+'b'),0)

step = 0
qwc = QuantumCircuit(qnodes, qsubnodes, cnodes, csubnodes) # initialize
qwc = runQWC(qwc, step)
result = ibmsim(qwc)
zero_padding_counts(result)
plot_histogram(result)

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/6a3ef76a-61c8-49e7-5f18-06d95be00065.png)

位置(3量子ビット)を測定した結果、初期状態では原点$|x = 0 \rangle = |000 \rangle$ にいます。

次にstep = 1 です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/f1b86fb5-6786-d73a-23a7-df5e256e0f1a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/425f91d0-eec5-1e67-ae2d-9caab732ddb3.png)

注意点として、bitの桁は上から下に向かって読んでください。qiskitの仕様です。
001と111に居る、となっていますね。
原点にいた量子に対して、$H$ゲートでカイラリティがRとLの重ね合わせになった後、シフト作用素をかけますので、50%/50%の重みで000と111へいくわけですね。

次にstep = 2です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/bd9028be-166e-e4e9-77f3-7099418740ed.png)

もうよくわからないのですが、おそらく000のところで同位相で”衝突”しています。
010と011は、もともと空席だったので、そのまま着地していますね。

step = 3です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/ed2d1fda-4b0b-3f79-4c0f-930ce3b1855b.png)

step = 4です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/b8fb066d-7232-f707-9a98-3c2ab5fe66a3.png)

step = 5です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/3fad5630-2f0a-937a-0d6a-ef4697f6c6b3.png)

実はstep=3の状態に戻ってきています。
これ以上繰り返しても、周期的に繰り返されます。
循環グラフ上で「定在波ができた」と考えてよいかと思います。

# まとめ

循環グラフ上の量子ウォークを実装した。
これで何ができるのかはわからないので、もっと勉強します。

[^1]: 位置基底で表示した時の振幅値を、波動関数といいます。大学で少し量子力学を触った方は、波動関数が量子状態と教わったかもしれません。正確には、量子状態を”位置”という基底で展開した時の姿が波動関数なのであって、波動関数を基礎に置きすぎることはよくありません。

[^2]: もしコイン作用素がない場合はどうなるでしょう？　量子は左方向へ動き続けるため、位置が局在したままぐるぐる回ることになりますね。もしシフト作用素がない場合はどうなるでしょう？量子の位置は原点から動かないまま、カイラリティだけが変わることになります。

[^3]: (念の為)位置は8量子ビットではありません。あくまで、1量子の位置状態が8通りあるだけで、8量子ビットが相互作用する問題を考えているわけでは有りません。また、Rが$|1 \rangle$でLが$|0 \rangle$となるように定義します。