sympy でグローバーアルゴリズム(量子ゲート計算）

グローバーアルゴリズムとは、`|0>,|1>,|2>,....|N>` の線形重ね合わせから、任意の状態 `|a>` の確率振幅を増幅して、できるだけ 1に近づけるアルゴリズムである。

# sympy でお手軽グローバー
sympy ではライブラリ化されているので使うのはめっちゃ簡単。3-qubitの系で、`|7>`を取り出したいな。`|7> = |111>` の観測確率は、その他の状態の 121 倍に増幅されている。

```python
>>> from sympy.physics.quantum.qubit import IntQubit, measure_all
>>> from sympy.physics.quantum.qapply import qapply
>>> from sympy.physics.quantum.grover import apply_grover

>>> isKet7 = lambda state: state == IntQubit(7)
>>> measure_all(qapply(apply_grover(isKet7, 3)))
[(|000>, 1/128), (|001>, 1/128), (|010>, 1/128), (|011>, 1/128), (|100>, 1/128), (|101>, 1/128), (|110>, 1/128), (|111>, 121/128)]
```

# sympy でもう少し踏み込んでグローバー

以上で終わりなのだが、これだけだとあまりにもつまらないので、もう少し手作り感をだそう。`|7> = |111>` に対応するオラクルは、`OracleGate`が対応する。行列表示をすれば一目瞭然に `|7>` だけがフェーズシフトされる様子がわかる。

```python
>>> from sympy.physics.quantum.grover import OracleGate
>>> from sympy.physics.quantum.represent import represent

>>> ora = OracleGate(3, isKet7)
>>> represent(ora)
Matrix([
[1, 0, 0, 0, 0, 0, 0,  0],
[0, 1, 0, 0, 0, 0, 0,  0],
[0, 0, 1, 0, 0, 0, 0,  0],
[0, 0, 0, 1, 0, 0, 0,  0],
[0, 0, 0, 0, 1, 0, 0,  0],
[0, 0, 0, 0, 0, 1, 0,  0],
[0, 0, 0, 0, 0, 0, 1,  0],
[0, 0, 0, 0, 0, 0, 0, -1]])
```

オラクルの後は、Inversion about mean という操作をする。これは sympy では `WGate` と呼ばれている。よってグローバーオペレータGを定義できる。G を 1回、2回かけた際にどのように確率振幅がどのようになるかを見よう。

```mygrover.py
from sympy.physics.quantum.qapply import qapply
from sympy.physics.quantum.dagger import Dagger
from sympy.physics.quantum.grover import apply_grover, OracleGate, WGate, superposition_basis
from sympy.physics.quantum.qubit import Qubit, IntQubit, measure_all
from sympy.physics.quantum.gate import I, X, Z, H, CNOT, CGate

G = WGate(3) * OracleGate(3, lambda state: state == IntQubit(7))
print(measure_all(qapply(G*superposition_basis(3))))
print(measure_all(qapply(G*G*superposition_basis(3))))
```

結果は以下の通り、2回 Gをかけた結果が、前述の`apply_grover` の結果と一致している。

```
[(|000>, 1/32), (|001>, 1/32), (|010>, 1/32), (|011>, 1/32), (|100>, 1/32), (|101>, 1/32), (|110>, 1/32), (|111>, 25/32)]
[(|000>, 1/128), (|001>, 1/128), (|010>, 1/128), (|011>, 1/128), (|100>, 1/128), (|101>, 1/128), (|110>, 1/128), (|111>, 121/128)]
```


# sympy で完全手作りグローバー

さて、私たちは具体的にこのオラクルの具体的な実現方式を知っている（`CGate((0,1,2),X(3))` 末尾の参考文献参照）。それと比べてみよう。インプットとして 3-qubit, オラクルビットとして 1bit の計 4-qubit の系が必要。

```mygrover.py
from sympy.physics.quantum.qapply import qapply
from sympy.physics.quantum.dagger import Dagger
from sympy.physics.quantum.grover import apply_grover, OracleGate
from sympy.physics.quantum.qubit import Qubit, IntQubit
from sympy.physics.quantum.gate import I, X, Z, H, CNOT, CGate

myora = CGate((0,1,2),X(3))

for state in range(8):
    inputState = qapply(H(3) * IntQubit(8+state))
    applied = qapply(myora * inputState)
    print (qapply(Dagger(inputState) * applied))
```

出力。確かに、 `|7>` の時だけフェーズシフトされていることがわかる。よってこのように構成した量子ゲートは上述のオラクルと対応付けることができる。つまり、我々の構成した 4-qubit の量子ゲートは、以降の全ての処理では、オラクルキュービットを無視するので、3-qubit の前述のオラクルで代替可能である。以降 3-qubit系で議論を進める。

```
1
1
1
1
1
1
1
-1
```

Wゲートに関してもその具体的な構成方法がわかっているので、グローバーオペレータを定義できる。

```py
from sympy.physics.quantum.qapply import qapply
from sympy.physics.quantum.dagger import Dagger
from sympy.physics.quantum.grover import OracleGate, superposition_basis
from sympy.physics.quantum.qubit import Qubit, IntQubit, measure_all
from sympy.physics.quantum.gate import I, X, Z, H, CNOT, CGate

ora = OracleGate(3, lambda state: state == IntQubit(7))
W = X(0) * X(1) * X(2) * CGate((0,1),Z(2)) * X(0) * X(1) * X(2)
myG = H(0) * H(1) * H(2) * W * H(0) * H(1) * H(2) * ora

state1 = qapply(myG*superposition_basis(3))
print(measure_all(state1))
state2 = qapply(myG*state1)
print(measure_all(state2))
```

結果は以下のようになる。ばっちりOK。

```
[(|000>, 1/32), (|001>, 1/32), (|010>, 1/32), (|011>, 1/32), (|100>, 1/32), (|101>, 1/32), (|110>, 1/32), (|111>, 25/32)]
[(|000>, 1/128), (|001>, 1/128), (|010>, 1/128), (|011>, 1/128), (|100>, 1/128), (|101>, 1/128), (|110>, 1/128), (|111>, 121/128)]
```

だれか sympy で次元の圧縮のやり方を知っている人がいればおしえてほすい



参考: https://www.appi.keio.ac.jp/Itoh_group/abe/pdf/qc4.pdf