blueqat で VQE

## この記事に関して
ここではpythonライブラリのblueqatを用いて量子プログラミングを行っていこうと思います。
内容は[公式のチュートリアル](https://github.com/Blueqat/Blueqat-tutorials/tree/master/tutorial-ja)を元に作成しています。
今回は VQE を実装していきます。

## VQE
詳しい理論は[ここ](https://qiita.com/KeiichiroHiga/items/c900d430dc33d4342b24)に述べています。

このアルゴリズムはハミルトニアン(エルミート行列)の固有値を量子コンピュータと
古典コンピューターを用いて近似的に求めるものです。

ハミルトニアンを $H$ とし、これに対する固有値を $E_0$ とします。

このとき量子変分原理から、一般の状態 $\left|\psi\right>$ に対し、 $\left<\psi\right|H\left|\psi\right> ≧ E_0$ となります。

このことから $\left|\psi\right>$ を自由に動かして、$\left<\psi\right|H\left|\psi\right>$ の最小値を求めればいいことがわかります。

###アルゴリズムの流れ
流れは以下のようになります。

1 . 自由に動かす状態は $\theta$ でパラメータ表示された状態 $\left|\psi(\theta)\right>$ とし、これと $H\left|\psi(\theta)\right>$ を量子コンピューターで計算する。

2 . 古典コンピュータで $\left<\psi(\theta)\right|H\left|\psi(\theta)\right>$ を計算する。

3 . $\left<\psi(\theta)\right|H\left|\psi(\theta)\right>$ が最小値でなければ、$\theta$ を更新する。最小値であればそれは $E_0$ の近似解である。

### 実装 1
blueqat を用いて実装します。
今回はハミルトニアン $H = Z$ としておきます。
$Z$ の固有値は $1, -1$ です。

$\left|\psi(\theta)\right> = R_y(\theta)\left|0\right>$ とし、$\theta$ は $(0≦\theta<2\pi)$ とします。

``` python:vqe.ipynb
from blueqat import Circuit
import numpy as np
import matplotlib.pyplot as plt
import math

# θの初期値、重み、誤差
th, w, d = 1.0, 0.4, 0.005

while True:
    
    d_ry = Circuit().ry(th+math.pi)[0].run()
    _ry = Circuit().ry(th)[0].run()
    hd_ry = Circuit().ry(th+math.pi)[0].z[0].run()
    h_ry = Circuit().ry(th)[0].z[0].run()
    
    '''
        d_ry = (-sin(θ/2) cos(θ/2)) => (d/dθ)|ψ(0)>
        _ry = (cos(θ/2) sin(θ/2)) => |ψ(0)>
        hd_ry = (-sin(θ/2) -cos(θ/2)) => (d/dθ)H|ψ(0)>
        h_ry = (cos(θ/2) -sin(θ/2)) => H|ψ(0)>
    '''
    
    # 位相処理
    if math.sin(th/2.0) >= 0.0:
        d_ry = -d_ry
        hd_ry = -hd_ry
    
    if math.cos(th/2.0) < 0.0:
        _ry = -_ry
        h_ry = -h_ry
    
    # 勾配
    ds_th = (np.dot(d_ry, h_ry) + np.dot(_ry, hd_ry))*(1/2.0) # -sinθ
    
    # θの更新
    th = th - w*ds_th*th
    
    # 誤差範囲
    if ds_th <= d and ds_th >= -d:
        s_th = np.dot(_ry, h_ry) # 期待値
        print(i) # 回数
        break

print(th) # θ
print(s_th) # 固有値

結果
3
(3.140573290275759+0j)
(-0.9999922075939599+0j)
```
上手く固有値を取り出すことができました。

### 実装 2
blueqat を用いて実装します。
今度はハミルトニアンを以下の行列とします。

``` math
H =
\left(\begin{array}{cc}
1 & 1 \\
1 & 1
\end{array}\right)
= I + X
```
この固有値は $0, 2$ です。

$\left|\psi(\theta)\right> = R_y(\theta)\left|0\right>$ とし、$\theta$ は $(0≦\theta<2\pi)$ とします。

``` python:vqe.ipynb
from blueqat import Circuit
import numpy as np
import matplotlib.pyplot as plt
import math

# θの初期値、重み、誤差
th, w, d = 2.0, 0.05, 0.01

# 格納配列
th_a, s_a = [], []

while True:
    
    # |ψ(θ)> の作成
    d_ry = Circuit().ry(th+math.pi)[0].run()
    _ry = Circuit().ry(th)[0].run()
    
    '''
        d_ry = (-sin(θ/2) cos(θ/2)) => (d/dθ)|ψ(0)>
        _ry = (cos(θ/2) sin(θ/2)) => |ψ(0)>
    '''
    
    # X の処理
    hd_ry = Circuit().ry(th+math.pi)[0].x[0].run()
    h_ry = Circuit().ry(th)[0].x[0].run()
    
    '''
        hd_ry = (cos(θ/2) -sin(θ/2)) => (d/dθ)X|ψ(0)>
        h_ry = (sin(θ/2) cos(θ/2)) => X|ψ(0)>
    '''
    
    # 位相処理
    if math.sin(th/2.0) >= 0.0:
        d_ry = -d_ry
        
    if math.sin(th/2.0) < 0.0:
        h_ry = -h_ry
        
    if math.cos(th/2.0) < 0.0:
        _ry = -_ry
        hd_ry = -hd_ry
    
    # 勾配
    ds_th = (np.dot(d_ry, _ry) + np.dot(_ry, d_ry) + np.dot(d_ry, h_ry) + np.dot(_ry, hd_ry))*(1/2.0)
    
    # θの更新
    th = th - w*ds_th*th
    
    # 誤差範囲
    if ds_th <= d and ds_th >= -d:
        s_th = np.dot(_ry, _ry) + np.dot(_ry, h_ry) # 期待値
        print(i) # 回数
        break

print(th) # θ
print(s_th) # 固有値

結果
19
(4.7057364938256585+0j)
(3.7828454340083084e-05+0j) # 3.0 × 10^-5
```
上手く固有値を取り出すことができました。

## まとめ
今回はblueqatを用いて VQE を実装しました。
次回は QAOA をblueqatで実装してみます。