量子コンピュータの勉強を始めさせていただきました。色々書籍を読む中で、量子ゲートをやる上で理解できないと何もできないんじゃないかというレベルのアダマールゲート。
$$
H|0〉=|+〉,H|1〉=|-〉
$$
というような量子重ね合わせの状態になります。また、式は以下の通りです。
$$
H \left| 0 \right\rangle = \frac{1}{\sqrt{2}} \left( \left| 0 \right\rangle + \left| 1 \right\rangle \right)
$$
$$
H \left| 1 \right\rangle = \frac{1}{\sqrt{2}} \left( \left| 0 \right\rangle - \left| 1 \right\rangle \right)
$$
0とか1の量子ビットをアダマールゲートに入れたら重ね合わせの状態になることは、そういうものとして腑に落とせますが、よく解説にて使用されるブロッホ球の説明を見ると、「ブロッホ球上でアダマールゲートは、Z軸上の状態(|0⟩)を、X軸方向(|+⟩)に写す回転を行います。これは、Z軸とX軸のなす面の法線(つまり Y 軸に対して斜め)を中心とした180°回転とみなすことができます。」のような記載があります。下の図だと緑のブロッホ球は緑の軸を中心に180°回転させるようです。
ここで理解が完全に停止しました。
|0〉のY軸を90°回転させてもX軸の位置にくるような気もするし、それはそれとしてYゲートも存在するし、これは一体どういうことなんだと理解がなかなかできませんでした。
そこでChatGPTさんにお願いして、アニメーションを作成していただきました。
俯瞰視点
各軸方向からの視点
ぱっと見で何をしているのかがようやく理解できました。
また副産物としてX軸方向の|+〉からZ軸方向の|0〉に戻る様子も確認できました。
ChatGPTとの壁打ちは始めて学習する分野、そうでないものでもかなり有用だなと感じました。(ファクトチェックは重要ですが...)
ここで詰まっている方がいるのか不明ですが一瞬で挫折された方がおられましたらご参考にしていただけますと幸いです。
また、認識齟齬や訂正等ございましたらコメントいただけると嬉しいです!
今後学習過程で全く理解できなかったことなどあれば随時記事作成できればと考えております!
ブロッホ球のアニメーションのコード
numpyとmatplotlibだけで動作するかと思います。
アングルもマウスで動かせます。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.lines import Line2D
# -------------------------------
# ヘルパー関数
# -------------------------------
def bloch_coords(state):
sx = np.array([[0, 1], [1, 0]])
sy = np.array([[0, -1j], [1j, 0]])
sz = np.array([[1, 0], [0, -1]])
x = np.real(state.conj().T @ sx @ state).item()
y = np.real(state.conj().T @ sy @ state).item()
z = np.real(state.conj().T @ sz @ state).item()
return [x, y, z]
def expm_2x2(H, t):
eigvals, eigvecs = np.linalg.eigh(H)
exp_diag = np.diag(np.exp(-1j * eigvals * t))
return eigvecs @ exp_diag @ np.linalg.inv(eigvecs)
# -------------------------------
# Hadamardゲートと状態の生成
# -------------------------------
ket0 = np.array([[1], [0]])
H = (1 / np.sqrt(2)) * np.array([[1, 1], [1, -1]])
times = np.linspace(0, np.pi, 100)
states = [expm_2x2(H, t) @ ket0 for t in times]
bloch_points = np.array([bloch_coords(state) for state in states])
# -------------------------------
# 描画セットアップ
# -------------------------------
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim([-1.1, 1.1])
ax.set_ylim([-1.1, 1.1])
ax.set_zlim([-1.1, 1.1])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Bloch Sphere: Hadamard Gate Evolution')
ax.set_box_aspect([1, 1, 1]) # 球の歪みを補正
ax.view_init(elev=20, azim=-60)
# ブロッホ球のメッシュ
u, v = np.mgrid[0:2*np.pi:30j, 0:np.pi:15j]
x_sphere = np.cos(u) * np.sin(v)
y_sphere = np.sin(u) * np.sin(v)
z_sphere = np.cos(v)
ax.plot_wireframe(x_sphere, y_sphere, z_sphere, color="lightgray", linewidth=0.5)
# -------------------------------
# 静的ベクトル・軸ラベル
# -------------------------------
# XYZ軸
ax.quiver(0, 0, 0, 1, 0, 0, color='gray', linewidth=1)
ax.quiver(0, 0, 0, 0, 1, 0, color='gray', linewidth=1)
ax.quiver(0, 0, 0, 0, 0, 1, color='gray', linewidth=1)
offset = 0.15
ax.text(1 + offset, 0, 0, 'X', color='gray', fontsize=10)
ax.text(0, 1 + offset, 0, 'Y', color='gray', fontsize=10)
ax.text(0, 0, 1 + offset, 'Z', color='gray', fontsize=10)
# 初期状態 |0⟩(赤)
ax.quiver(0, 0, 0, 0, 0, 1, color='red', linewidth=2)
# 重ね合わせ状態(青)
ax.quiver(0, 0, 0, 1, 0, 0, color='blue', linewidth=2)
# 回転軸 (1, 0, 1)/√2(緑破線)
n = np.array([1, 0, 1]) / np.sqrt(2)
ax.plot([-n[0], n[0]], [-n[1], n[1]], [-n[2], n[2]],
color='green', linestyle='dashed', linewidth=2)
# -------------------------------
# 凡例(色付き)
# -------------------------------
legend_elements = [
Line2D([0], [0], color='red', lw=2, label='|0⟩'),
Line2D([0], [0], color='blue', lw=2, label='(|0⟩ + |1⟩)/√2'),
Line2D([0], [0], color='green', lw=2, linestyle='dashed', label='Rotation Axis'),
Line2D([0], [0], color='gray', lw=1, label='X/Y/Z Axis'),
Line2D([0], [0], color='black', lw=2, label='Current State'),
Line2D([0], [0], color='black', lw=1, linestyle='solid', label='Trajectory')
]
ax.legend(handles=legend_elements, loc='upper left', fontsize=8)
# -------------------------------
# アニメーション設定
# -------------------------------
point, = ax.plot([], [], [], 'ko', markersize=6)
path_line, = ax.plot([], [], [], color='black', linewidth=1)
dynamic_vector = None
trajectory = []
def init():
point.set_data([], [])
point.set_3d_properties([])
path_line.set_data([], [])
path_line.set_3d_properties([])
return point, path_line
def update(frame):
global dynamic_vector
x, y, z = bloch_points[frame]
point.set_data([x], [y])
point.set_3d_properties([z])
trajectory.append([x, y, z])
traj_array = np.array(trajectory)
path_line.set_data(traj_array[:, 0], traj_array[:, 1])
path_line.set_3d_properties(traj_array[:, 2])
if dynamic_vector is not None:
dynamic_vector.remove()
dynamic_vector = ax.quiver(0, 0, 0, x, y, z, color='black', linewidth=2)
return point, dynamic_vector, path_line
# -------------------------------
# アニメーション生成 & GIF保存
# -------------------------------
ani = animation.FuncAnimation(
fig, update, frames=len(bloch_points),
init_func=init, interval=50, blit=False, save_count=len(bloch_points)
)
# GIF保存
ani.save('bloch_hadamard.gif', writer='pillow', fps=20)
plt.show()
```
</details>