Qiskitで反復量子位相推定(IQPE)の実機実行

# IQPEの実機実行

これまでQPE,IQPEを色々勉強してきました。
[Qiskitで量子位相推定を勉強する](https://qiita.com/notori48/items/6522389a7582a40d3f15)
[Qiskitで反復量子位相推定を勉強する](https://qiita.com/notori48/items/6674b668ba02b635dbe0)
[Qiskitで反復量子位相推定(回路整理version)](https://qiita.com/notori48/items/6b617fc1c4ae8be5834f)


[Qiskitで反復量子位相推定(回路整理version)](https://qiita.com/notori48/items/6b617fc1c4ae8be5834f)では、IQPEを実装したものの、reset,c_ifなどIBMQ実機ではサポートされていない処理があり実機実行できませんでした。

今回、この点を修正して**実機実行まで持っていきました。**
ただ、どうしても回路単体では出来ず、古典的なif文も使って回路を作っていくことにしました。
また、[Qiskit 機能色々(TIPS)](https://qiita.com/notori48/items/2d836bc5ada901414d89)の内容も使っています。

# スクリプト

```python
#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
from qiskit.tools.monitor import job_monitor

# import basic plot tools
from qiskit.visualization import plot_histogram

counts_list = []
psi = [0,1]
#psi = np.multiply([1,1],1/np.sqrt(2))
flag_sim = 0

# 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
qpe = QuantumCircuit(2,1) # 1 bit for eigen state and 1 ancilla bit for phase kick back
qpe.initialize(psi,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(0,0)

if flag_sim==1:
  backend = Aer.get_backend('qasm_simulator')
  shots = 1024
  results = execute(qpe, backend=backend, shots=shots).result()
else:
  backend = provider.get_backend('ibmqx2')
  job = execute(qpe, backend, shots=1024)
  job_monitor(job, interval = 2)
  results = job.result()


counts = results.get_counts()
counts_list.append(counts)
print(counts)
j3 = int(counts.most_frequent(),2)
print('j3='+str(j3)+'\n')



k = 2 # iteration
qpe = QuantumCircuit(2,1) # 1 bit for eigen state and 1 ancilla bit for phase kick back
qpe.initialize(psi,1)
qpe.h(0) # Hadamard for 1st ancilla bit

if j3==1:
  qpe.rz(-1*math.pi/2,0)

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(0,0)

if flag_sim==1:
  backend = Aer.get_backend('qasm_simulator')
  shots = 1024
  results = execute(qpe, backend=backend, shots=shots).result()
else:
  backend = provider.get_backend('ibmqx2')
  job = execute(qpe, backend, shots=1024)
  job_monitor(job, interval = 2)
  results = job.result()

counts = results.get_counts()
counts_list.append(counts)
print(counts)
j2 = int(counts.most_frequent(),2)
print('j2='+str(j2)+'\n')

k = 1 # iteration

qpe = QuantumCircuit(2,1) # 1 bit for eigen state and 1 ancilla bit for phase kick back
qpe.initialize(psi,1)
qpe.h(0) # Hadamard for 1st ancilla bit

if j3==1:
  qpe.rz(-1*math.pi/4,0)

if j2==1:
  qpe.rz(-1*math.pi/2,0)

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(0,0)

if flag_sim==1:
  backend = Aer.get_backend('qasm_simulator')
  shots = 1024
  results = execute(qpe, backend=backend, shots=shots).result()
else:
  backend = provider.get_backend('ibmqx2')
  job = execute(qpe, backend, shots=1024)
  job_monitor(job, interval = 2)
  results = job.result()

counts = results.get_counts()
counts_list.append(counts)
print(counts)
j1 = int(counts.most_frequent(),2)
print('j1='+str(j1)+'\n')

print('Phase = 2π*('+'0.'+str(j1)+str(j2)+str(j3)+')')

#新規ウインドウ作成
fig = plt.figure(figsize=(20,4))
plt.subplots_adjust(wspace=0.4, hspace=0.6)
#flg全体をX*Yに分割し、plot位置に画像を配置する。
X = 1
Y = 3

ax1 = fig.add_subplot(X, Y, 3)
plot_histogram(counts_list[0], legend=['j 3'],ax=ax1)
ax2 = fig.add_subplot(X, Y, 2)
plot_histogram(counts_list[1], legend=['j 2'],ax=ax2)
ax3 = fig.add_subplot(X, Y, 1)
plot_histogram(counts_list[2], legend=['j 1'],ax=ax3)
```

# 解説
counts.most_frequent()　で、最大頻度のビットを取り出しています。
ビットの値に応じて　if でrzゲートを与えるかどうかを決めています。

# 出力結果（シミュレーター)

正しい解は $j_{1}j_{2}j_{3} = 001$ です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/79296b4d-f78c-166a-47c7-39a1d0b9c263.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/7be2048e-7924-89b8-5190-7cc7c44ac8bf.png)

出来ています。

# 出力（実機, ibmqx2)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/3cb544c2-9a71-2775-cf1a-1b24e16a1809.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/6873ee8f-53d5-2ebc-0b53-c7e38c13b32b.png)

雑音によるエラーはありますが、出来ています。
更に、QPEでの結果[Qiskitで量子位相推定を勉強する](https://qiita.com/notori48/items/6522389a7582a40d3f15) と比べてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/26c90a90-bc06-0d57-02d1-b39f4e5798ee.png)

明らかにIQPEのほうが良いですね。

QPEでは3桁を1つの回路で一気に読み出しますので、
- 回路が長い
- 補助量子ビットが3個必要 (IQPEは1個)
という点が劣位であったと考えられます。

# 結論
フルスクラッチでIQPEを実機実行できるものが書けた。
qiskit.aquaにはライブラリとしてIQPEがあるが、おそらく同じような手順ではないだろうか。