量子計算のスワップテスト（swap test）を試してみる

休日の読書で、「[量子コンピューティング 基本アルゴリズムから量子機械学習まで](https://amzn.to/3MsKt7G)」を読んでいて、「3.3 内積の計算（スワップテスト）」がわかりにくかったので、調べて試してみたメモです。（間違っていたら教えてください）

# スワップテスト（swap test）とは
スワップテストはベクトルaとbの状態の内積を評価するサブルーティンとのこと。わかりやすく説明すると、一番の特徴は、aとbの量子状態を計測する（"aとbの状態を壊す"）ことなく、この2つの量子状態が"どれだけ近いか正確に推定する"ことです。これにより量子機械学習での利用を考えることができるようです。

回路としては以下のようになります。(Azure Quantumの利用も意識してpytketで書いてみます)

```python
st_circuit = Circuit(3, 1).H(0) .CSWAP(0, 1, 2).H(0).Measure(0, 0)
render_circuit_jupyter(st_circuit)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/0dd5138b-8598-91f1-917d-965c81c0403a.png)

ここのq[0]、q[1]、q[2]が量子ビットです。q[0]は計測した結果を出力するビットです。入力のaはq[1]、bはq[2]になります。出力のq[0]は補助量子ビットと呼ばれていますが、スワップテストの結果がq[0]になりますので、最後に計測しています。

# 試してみる
わかりにくかったので実際に動かしてみました。

まずはパッケージを読み込みます。

```python
from pytket.extensions.qiskit import AerBackend
from pytket import Circuit
from pytket.circuit import OpType
from pytket.circuit.display import render_circuit_jupyter
import matplotlib.pyplot as plt
from math import pi, sqrt
```

結果を表示するサブルーチンを用意しておきます。

```python
def plot_tket_result_histogram(counts):
    labels = []
    y = []
    for label in counts.keys():
        str_label = ''
        for value in label:
            str_label = str_label + str(value)
        labels.append(str_label)
        y.append(counts[label])
    x = range(0, len(labels))
    plt.bar(x, y, tick_label = labels)
    plt.show()
    print(counts)
```

スワップテストの回路を組み立てるサブルーチンも用意しておきます。入力として、aとbのθ（シータ）を用意しておきます。（以下のq[1]とq[2]の量子状態は、例なので、重ね合わせ状態にしたり、好きな方向に回すように修正して試してもいいです）

```python
def build_swap_test_circuit(theta1, theta2):
    st_circuit = Circuit(3, 1).H(0)
    st_circuit = st_circuit.add_gate(OpType.U3, [theta1,0,0], [1])
    st_circuit = st_circuit.add_gate(OpType.U3, [theta2,0,0], [2])
    st_circuit = st_circuit.CSWAP(0, 1, 2)
    st_circuit = st_circuit.H(0).Measure(0, 0)
    return st_circuit
```

こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/4301ec01-c491-0693-f6eb-54cf2a35ee15.png)

では、度数法で、aのθは0°、bのθは180°にして動かしてみます。
ちなみに、pytket（tket）のU3は、piが含んでいるので、qiskitとは異なる入力になるので注意です。
[pytketのu3](https://cqcl.github.io/tket/pytket/api/optype.html?highlight=u3)
[qiskitのu3](https://qiskit.org/documentation/stubs/qiskit.circuit.library.U3Gate.html)

```python
backend = AerBackend()
swap_test_circuit = build_swap_test_circuit(0, 180/180)
handle = backend.process_circuit(swap_test_circuit, n_shots=10000)
result = backend.get_result(handle)
plot_tket_result_histogram(result.get_counts())
```

結果は、Counter({(0,): 5014, (1,): 4986})でした。aとbの2つの量子状態が一番近くない場合は、|0>の（0になる）確率は50%になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/1e74cf5e-6a57-db61-5841-b8b8e997a585.png)

では、aのθは0、bのθは0にして状態を近くして動かしてみます。

```python
backend = AerBackend()
swap_test_circuit = build_swap_test_circuit(0, 0)
handle = backend.process_circuit(swap_test_circuit, n_shots=10000)
result = backend.get_result(handle)
plot_tket_result_histogram(result.get_counts())
```

結果は、Counter({(0,): 10000})でした。aとbの2つの量子状態が一番近い場合は、|0>の（0になる）確率は100%になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/a50a5371-ead9-a9fd-fe26-387b1356b46b.png)

# 入力状態とスワップテストの出力の関係を確認してみる
単体だとわかりにくいので、aとbの入力とスワップテストの出力の関係を確認を表示してみます。aのθは常に0°にして、bのθを0°から360°まで動かしてみます。

```python
x = []
y = []
shots = 1024*10
for i in range(0,360,10):
    swap_test_circuit = build_swap_test(0, i/180)
    handle = backend.process_circuit(swap_test_circuit, n_shots=shots)
    result = backend.get_result(handle)
    x.append(i)
    y.append(result.get_counts()[(0,)]/shots)
plt.plot(x, y)
plt.show()
```

結果は、こんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/efd4bab3-8788-defc-1bb4-e1015c4175b2.png)

# さいごに
休日の読書で量子コンピューティングの本を読んでいましたが、理解を深めるためには複数の資料を読まないとわからないですね。結果的に回路を組んで量子計算に触れることになりましたが、本に書かれている式だけではなく動かしてみると理解が深まりますね。

今回参考にさせて頂いた資料は以下になります。

[動かして学ぶ量子コンピュータプログラミング](https://amzn.to/36Jxu2a)
[量子k-means法のはなし](https://note.com/utaka233/n/n06e345cf776e)
[量子コンピューティング 基本アルゴリズムから量子機械学習まで](https://amzn.to/36FuKme)