Qiskitで反復量子位相推定(回路整理version)


# IQPE復習
前回の記事で反復量子位相推定(IQPE)をqiskitで実装しました。

https://qiita.com/notori48/items/6674b668ba02b635dbe0

IQPEは、ユニタリ行列の固有値の規格化位相を1桁ずつ読み出すアルゴリズムです。
qiskit実装はしたものの、回路を何度も新しく生成する形のスクリプトになっていて、いまいちダサかったです。

# 回路を一つにする

今回、回路を整理して1つにしました。
結果として、以下の関数が必要でした。

- **c_if**
- **reset**

# c_if
c_if関数は、量子ビットを測定して古典ビットに落ちした後に、その古典ビットが0なのか1なのかによって
後段の量子ゲートを入れたり入れなかったりする操作に使います。
量子テレポーテーションなどで使います。

# reset
reset関数は、量子状態を回路の途中で初期化したい場合に使います。
測定を入れると、当然量子状態は破壊されるわけですが、resetを入れることで2つの回路を見かけ上1つに出来ます。

# やってみた結果
スクリプトです。まずはインストール

```python
pip install qiskit pylatexenc
#initialization
import matplotlib.pyplot as plt
import numpy as np
import math

# importing Qiskit
from qiskit import IBMQ, Aer
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute

# import basic plot tools
from qiskit.visualization import plot_histogram

```

1st iterationは、

```python
# U = [1 0 ; 0 exp(pi/4)]
# eigen value is 2pi(0) for |0> , 2pi(0.001) for |1>
t = 3 # num of iteration
k = 3 # iteration
qr = QuantumRegister(2)
cr_1 = ClassicalRegister(1)
cr_2 = ClassicalRegister(1)
cr_3 = ClassicalRegister(1)
qpe = QuantumCircuit(qr, cr_1, cr_2, cr_3) # 1 bit for eigen state and 1 ancilla bit for phase kick back
qpe.x(1) # 2nd bit becomes eigen state, |1>
qpe.h(0) # Hadamard for 1st ancilla bit

for i in range(2**(t-1)):
    qpe.cu1(math.pi/4, 0, 1); # This is Controlled-U , controll-qubit is 0 (ancilla) , target-qubit is 1 (eigen)

qpe.h(0) # Hadamard for 1st ancilla bit
qpe.measure(qr[0],cr_1)

qpe.barrier()
qpe.reset(qr[0])
qpe.reset(qr[1])

qpe.draw('mpl')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/04401691-55ef-2eda-2857-cd0321850b49.png)

このようになります。
回路の最後に初期化を入れることで、1st iteration と2nd iteration　の回路を繋げられるできるようにしています。
2nd iterationもつなげてみると、

```python
k = 2 # iteration
qpe.x(1) # 2nd bit becomes eigen state, |1>
qpe.h(0) # Hadamard for 1st ancilla bit
qpe.rz(-1*math.pi/2,0).c_if(cr_1,1)

for i in range(2**(k-1)):
    qpe.cu1(math.pi/4, 0, 1); # This is Controlled-U , controll-qubit is 0 (ancilla) , target-qubit is 1 (eigen)

qpe.h(0) # Hadamard for 1st ancilla bit
qpe.measure(qr[0],cr_2)
qpe.barrier()
qpe.reset(qr[0])
qpe.reset(qr[1])

qpe.draw('mpl')

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/4927ffc6-e84a-0df7-4777-5108ef09015f.png)


こうなります。
1st iterationでで得られた古典ビットを用いて、2nd iterationの回路に条件付きゲート操作をかけています。
(IQPEアルゴリズムでいうところの桁シフト操作です）
ここがテクいです。（どや）

最後に、3rd iterationです。

```python

k = 1 # iteration
qpe.x(1) # 2nd bit becomes eigen state, |1>
qpe.h(0) # Hadamard for 1st ancilla bit
qpe.rz(-1*math.pi/4,0).c_if(cr_1,1)
qpe.rz(-1*math.pi/2,0).c_if(cr_2,1)

for i in range(2**(k-1)):
    qpe.cu1(math.pi/4, 0, 1); # This is Controlled-U , controll-qubit is 0 (ancilla) , target-qubit is 1 (eigen)

qpe.h(0) # Hadamard for 1st ancilla bit
qpe.measure(qr[0],cr_3)
qpe.draw('mpl')

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/c0213abb-c0eb-49fa-8729-9b7fa2d94171.png)

こうなりました。
実際にこの1つの回路を測定します。

```python

backend = Aer.get_backend('qasm_simulator')
shots = 1
results = execute(qpe, backend=backend, shots=shots).result()
answer = results.get_counts()
print(answer)

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/dede2223-226c-55f2-96ac-c8abc60a11f5.png)


となりました。
なお、回路図上で上に来ている古典bitが、print(answer)では右端のbitに相当します。
つまりこれは固有値の規格化位相が 001 であったことを意味します。
ちゃんと解けていそうですね。
まぁ、ちゃんとデバッグできていないですが、アイデアは合っていると思います。

___
**2020/12/26追記**
上記コードでシミュレーターとしては動きますが、実機では
job is incurred error が出て動きません。
理由を考えてみたのですが、measureの段階で量子ビットが破壊されてしまうので、その後のresetが
実行できなくなっているものと思われます。
実際、以下の回路は動きません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/e5bcdcaf-f4ff-7591-3f51-33117cf3fa51.png)
しかし以下の回路は動きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/9b3217fe-eafe-1949-4ac7-b81f5a644270.png)

期待動作としては、measureのあとにはただちにもう一度量子ビットを作り直してほしかったのですが、そうなってはいない。
量子ビットを作り直すのに（ゲート演算よりも十分長い）時間が必要なのかな。

回路を1つにすることで、1st→2nd→3rd iterationを連続実行したときの位相推定結果をみたかったのですが、
各iterationで得られた0,1の頻度の多数派を取って値を確定させ、次のiterationにわたすような動作しか出来なさそうですね。ただ、現状のqiskitだとこういった処理はうまく書けなさそうです。（回路をまたいで値を渡す方法がないので）

**更に追記**
Qiskit tutorialにIQPEの記事が有りました。
https://github.com/qiskit-community/qiskit-community-tutorials/blob/6de54e7033edc4233142caecda257ed72a6735f5/algorithms/iterative_phase_estimation_algorithm.ipynb
この記事で書いていることそのままでした。
(resetが実機では通らないこと、回路をまたいだ処理ができないことなど)
___
# 結論
やってみると、意外と難しかったです。

- 古典的なプログラミングでは、前の結果を次の処理に使う　ということは簡単だが、qiskitによる量子プログラミングでは、頭を使わないと実現できない。
例えば、量子回路を2個用意して、回路Aの測定結果を回路Bのゲート操作に使うことは（調べた限り）出来ない。
つまり、回路をまたげない。ひとつの回路で書かないといけない。

- **c_if**,**reset**等の存在に気づけばなんてことはないが、この関数の使い方自体も日本語の資料は(Qiskit tutorialの訳文以外は)なく、たどり着くのに苦労した。
    - 古典ビットで条件付けられたゲート　→　量子テレポーテーションか？　とあたりをつけて、量子テレポーテーションのチュートリアルをあさってc_ifを発見、resetについては完全に勘で探した。

- 多分他にも重要な関数がある。remove_final_measurement とかもたまたま見つけた。 

Tutorialは教科書的な操作は一通り学べるものの、全ての関数が出てくるわけではないので、
各関数の使い方のまとめページが欲しいところですね。MATLABはそのあたり、調べれば全部書いてあるので助かる。