量子ビット： 確率振幅,位相,複素数の関係をStreamlitで可視化

# 実在する異世界

　　量子の世界は，実在する異世界です．日常生活で，体感しがたい不思議な現象がいくつかあるからです．例えば，「重ね合わせ（superposition）」[^1]，「もつれ（entanglement）」[^2]，「干渉（interfarence）」[^3]などです．重ね合わせ状態を「観測」することで，状態が決定すること（いわゆるシュレディンガー猫[^4]）も不思議に感じます．
 　しかしながら「波(wave)[^5]」について注意深く観察すれば，重ね合わせも干渉も，日常で体感可能で必ずしも不思議な現象ではないことがわかります．「波」や「波動」は身近な存在です．音波，電波，日光，水や地面の振動など．音もスマホの電波も普通に「壁」を抜けて伝達し，水面をよく見れば，重なり合って干渉する「波」を観察できます．
 　したがって「量子の世界」を必要以上に構えて難しく考える意味はなく，もっと気軽に入門できると考えます．ただ，量子もつれ（entanglement）だけは非日常の異世界感が残ります．テンソル積で表せず説明に難しさが確かに存在します．量子状態は複製が不可能だが，「もつれ」を使って状態を転送するができます．「もつれ」を活用した量子エラー訂正技術[^9]の実用化が待たれます．
 　ここでは，気軽な入門を助ける可視化の手法について，取り上げます．具体的には，「もつれ」以外の :smile:「重ね合わせ」「干渉」を対象として，状態を可視化するブロッフォスフィア（ブロッフォ球,Bloch sphere）[^6]を，Python,Qiskit[^7],Streamlit[^8]を用いて扱います．

[^1]: 重ね合わせ (https://ja.wikipedia.org/wiki/重ね合わせ)
[^2]: 量子もつれ (https://ja.wikipedia.org/wiki/量子もつれ)
[^3]: 干渉（https://ja.wikipedia.org/wiki/干渉_(物理学))
[^4]: シュレディンガーの猫 (https://ja.wikipedia.org/wiki/シュレーディンガーの猫)
[^5]: 波動 (https://ja.wikipedia.org/wiki/波動)
[^6]: ブロッフォ球 (https://ja.wikipedia.org/wiki/ブロッホ球)
[^7]: Qiskit (https://www.ibm.com/quantum/qiskit)
[^8]: Streamlit (https://streamlit.io)
[^9]: 量子誤り訂正 (https://dojo.qulacs.org/ja/latest/notebooks/9_quantum_error_correction.html)

# 目的
　　可視化と対話により，以下の「もやっと」を「すっきり」とした理解に変えることを目的とします[^11][^12][^13]：
  - 状態$|0>$と$|1>$が確率$\alpha^2$,$\beta^2$で重なり合うこと
  - $|\alpha^2+\beta^2|=1$,確率振幅，ボルンの規則[^10]
  - それが球体上の緯度$\theta$,経度$\phi$の複素ベクトルで表現されること
  - 複素数の実数部と虚数部と位相の関係性　
     $\alpha=a+ai,\beta=b+bi (iは\sqrt(-1))虚数単位$ 
  - $|\psi> = \cos\frac{\theta}{2} |0> + \sin \frac{\theta}{2}\exp^{i\phi} |1>$
  - ブロッフォスフィアの可視化と対話操作によって理解を深めること

[^10]: ボルンの規則 (https://ja.wikipedia.org/wiki/ボルンの規則)
[^11]: 量子コンピューティング　基本アルゴリズムから量子機械学習ま (https://www.ohmsha.co.jp/book/9784274226212/)
[^12]: ラズパイ電子工作&光の実験で理解する量子コンピュータ (https://shop.cqpub.co.jp/hanbai/books/50/50501.html)
[^13]: Interface2022年６月号Pythonで体験量子コンピュータ (https://cc.cqpub.co.jp/lib/system/doclib_item/1582/)


# 動作画面
- 緯度（θ）経度（φ）を操作して，球体上の位置関係を把握する

![位相モード（θ,φ）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635215/219dad4f-3689-498b-4ca5-d04dbef5f131.png "位相モード（θ,φ）のブロッフォ球")

   ブラウザ左サイドバー画面で，緯度（θ）経度（φ）の値をスライダー操作する
   トグルボタンにチェックすると，下記の確率振幅モードに切り替わる

- 確率振幅の複素数（α，β）実数部と虚数部を操作して，球体上の位置関係を把握する

![確率振幅モード（α,β）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635215/a9397097-5b1e-e6e2-19bf-78935a2c452c.png "複素数モード（α，β）のブロッフォ球")

   ブラウザ左サイドバー画面で，確率振幅の複素数（α，β）実数と虚数の値をスライダー操作する
   トグルボタンにチェックすると，上記の緯度／経度モードに切り替わる

# 動作環境
- MacOS sonoma 14.1.2, Python3.11.6, pip 23.3.1, VSCode 1.85.1
- streamlit                       1.27.2
- qiskit                          0.43.2
- qiskit-aer                      0.12.1
- qiskit-ibmq-provider            0.20.2
- qiskit-terra                    0.24.1

# Pythonコード例 と動作手順

```
$ pip3 install qiskit streamlit qiskit-aer
$ streamlit run st-bloch.py
  Local URL: http://localhost:8501
  Network URL: http://192.168.3.18:8501

|Alpha|^2 + |Beta|^2 == Zero. (0j,0j)
```

- st-bloch.py

```python

import numpy as np
import math,cmath
from qiskit.visualization import plot_bloch_vector
import streamlit as st
from PIL import Image

def alpha_beta_to_theta_phi(A: complex, B: complex) -> tuple:
    def normalize(a, b):
        norm = cmath.sqrt(abs(a)**2 + abs(b)**2)
        if norm == 0:
            raise ZeroDivisionError(f'|Alpha|^2 + |Beta|^2 == Zero. ({A},{B})')
        return a/norm,b/norm
    try:
        alpha,beta = normalize(A,B)
    except ZeroDivisionError as e:
        print(e)
        alpha,beta = 1+0j,0+0j

    # thetaとphiを計算する
    theta = 2 * cmath.acos(alpha)
    phi = cmath.phase(beta) - cmath.phase(alpha)

    st.sidebar.write(f'(θ,φ)=({theta},{phi})')
    return theta.real, phi.real

def alpha_beta_real_imag():
    st.markdown("-----")
    st.markdown("## 確率振幅α、β（Real/Imag）　⇒　ブロッフォスフィア")
    ra = st.sidebar.slider("Real(α) >", -10, 10, 1, 1)
    ia = st.sidebar.slider("Imag(α) >", -10, 10, 1, 1)
    alpha = ra + ia * 1j
    st.sidebar.write(f'α={alpha}')

    rb = st.sidebar.slider("Real(β) >", -10, 10, 0, 1)
    ib = st.sidebar.slider("Imag(β) >", -10, 10, 0, 1)
    beta = rb + ib * 1j
    st.sidebar.write(f'β={beta}')

    theta,phi = alpha_beta_to_theta_phi(alpha,beta)
    return theta,phi

def theta_phi():
    st.markdown("-----")
    st.markdown("## 位相theta,phi ⇒　ブロッフォスフィア")
    theta = st.sidebar.slider("theta(θ) >", -math.pi/2.0, math.pi/2.0, 0.0, 0.1)
    phi = st.sidebar.slider("phi(φ) >", -math.pi, math.pi, 0.0, 0.1)

    st.sidebar.write(f'θ={theta}')
    st.sidebar.write(f'φ={phi}')
    return 2*theta,phi

Fig_Path = './bloch_sphere.png'

def bloch(theta,phi):
    sphere = plot_bloch_vector([1, theta, phi], coord_type='spherical',title='Bloch Sphere')
    sphere.savefig(Fig_Path)
    image = Image.open(Fig_Path)
    st.image(image, channels="BGR")

def main():
        toggle = st.sidebar.checkbox('α，β / Theta_Phi')
        if toggle:
            theta,phi = alpha_beta_real_imag()
            bloch(theta,phi) 
        else:
            theta,phi = theta_phi()
            bloch(theta,phi)

if __name__ == "__main__":
    main()
 
```

# 注意事項，今後の課題
　やってみて気づいたこと，今後の課題を箇条書きします．
 
- 任意の複素数を自由に操作できるが，確率振幅として成立するために加算して1.0にする必要がある，つまり正規化が必要
- その際，ZeroDivideのExceptionが発生しうる想定と対応が必要
- 2つの複素数の意味をさらに詳しく可視化するには，２次元複素ベクトル空間で有名なオイラーの公式( $ e^{i\phi} = \cos\phi + i\sin\phi )$ の世界を可視化するとなおよい 
- 各種パラメタを自動更新することで，アニメーションの動きを実装することが可能だろう
- streamlitは，対話的にわかりやすく作れて便利，短時間でWeb対話環境が構築できる
- ブロッフォ球は一旦png画像ファイルに出力して，読み込んで描画している

# 分析，考察
　量子ビットの状態理解の先にある様々な概念とそれらの存在意義，ご利益について分析考察します．
 
- 量子ビットは，観測により０か１の普通の古典ビットにもどってしまい，そのありがたさが消失する（と感じる）
- 結果的0か１だが，観測前はどの辺の緯度・経度にいたのか？　試行回数を増やして確率を推定して，確率振幅を推測する操作も実際ある
- 試行錯誤を繰り返さずとも，逆量子フーリエ変換とともに位相推定する（巨大なユニタリ行列の固有値を得る）手法がある
- 所望の解を得るために，確率振幅を反転したり偏らせたりして，意図的に狙った正解を引き出す手法もある
- 確率振幅と位相の操作が，基本的な量子アルゴリズムの鍵を握っているらしい
- 今回はその入門編に向き合うところで，可視化の道具を用立てした
- 著名な量子アルゴリズムがどんな発想でうまれてきたのか？　先人の天才達の発想に遠く及ばない．まずは世界観と背景にある着想に近づくことが最初の一歩だろう
- 量子ゲートの組み立ては，古典コンピューティングのゲート回路ーアセンブラ世界を彷彿として，プリミティブな作業もまた楽しいはず

# おわりに
   ブロッフォスフィアの可視化と対話操作によって, 量子の世界にかかる「もやっと」を「すっきり」した理解に変える目的でQiskitとStreamlitを用いたプログラミング例を示しました．

  - 球体上の緯度$\theta$,経度$\phi$の複素ベクトルで表現される  
  - 状態$|0>$と$|1>$が確率$\alpha^2$,$\beta^2$で重なり合うイメージ
  - $|\alpha^2+\beta^2|=1$,確率振幅，ボルンの規則[^10]
  - 複素数の実数部と虚数部と位相の関係性　
     $\alpha=a+ai,\beta=b+bi (iは\sqrt(-1))虚数単位$ 
  - $|\psi> = \cos\frac{\theta}{2} |0> + \sin \frac{\theta}{2}\exp^{i\phi} |1>$

  これらの世界観を体感しながら，すっきり理解につなげていただけると幸いです．