3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アダマールゲートのブロッホ球のアニメーションを見る

Last updated at Posted at 2025-07-08

量子コンピュータの勉強を始めさせていただきました。色々書籍を読む中で、量子ゲートをやる上で理解できないと何もできないんじゃないかというレベルのアダマールゲート。

$$
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°回転させるようです。

image.png

ここで理解が完全に停止しました。

|0〉のY軸を90°回転させてもX軸の位置にくるような気もするし、それはそれとしてYゲートも存在するし、これは一体どういうことなんだと理解がなかなかできませんでした。

そこでChatGPTさんにお願いして、アニメーションを作成していただきました。

俯瞰視点

bloch_hadamard.gif

各軸方向からの視点

bloch_hadamard_xyz.gif

ぱっと見で何をしているのかがようやく理解できました。
また副産物として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>
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?