3×3行列の固有値分解¶

In [14]:
# !pip install japanize-matplotlib
In [15]:
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
In [16]:
from mpl_toolkits.mplot3d import Axes3D

固有値

In [3]:
# 行列
A = np.array([[ 0.,  0.,  1.],
              [ 0.,  0., -1.],
              [ 1., -1.,  1.]])
In [4]:
# 固有値・固有ベクトル(対称行列なので np.linalg.eigh を使用)
w, V = np.linalg.eigh(A)
In [5]:
print("固有値 w =", w)
固有値 w = [-1.00000000e+00  1.08691268e-16  2.00000000e+00]

固有ベクトル

In [7]:
# 正規化済みの固有ベクトル
order = [1, 2, 0]  # w[1]=0, w[2]=2, w[0]=-1
lam = w[order]
P_raw = V[:, order]
In [8]:
print("固有値(並べ替え後) lam =", lam)
固有値(並べ替え後) lam = [ 1.08691268e-16  2.00000000e+00 -1.00000000e+00]

直交行列・対角行列¶

In [9]:
# 列ごとに正規化(eigh の列は既に単位長のはずだが、念のため)
P = P_raw / np.linalg.norm(P_raw, axis=0, keepdims=True)
D = np.diag(lam)
In [10]:
print("\n直交行列 P =\n", np.round(P, 6))
print("\n対角行列 D =\n", D)
直交行列 P =
 [[-0.707107  0.408248 -0.57735 ]
 [-0.707107 -0.408248  0.57735 ]
 [-0.        0.816497  0.57735 ]]

対角行列 D =
 [[ 1.08691268e-16  0.00000000e+00  0.00000000e+00]
 [ 0.00000000e+00  2.00000000e+00  0.00000000e+00]
 [ 0.00000000e+00  0.00000000e+00 -1.00000000e+00]]
In [12]:
# 検算:P^T P = I,  A = P D P^T
I_check = P.T @ P
recon   = P @ D @ P.T
In [13]:
print("\nP^T P =\n", np.round(I_check, 6))
print("\nP D P^T =\n", np.round(recon, 6))
print("\nA =\n", A)
P^T P =
 [[ 1.  0. -0.]
 [ 0.  1. -0.]
 [-0. -0.  1.]]

P D P^T =
 [[ 0. -0.  1.]
 [-0.  0. -1.]
 [ 1. -1.  1.]]

A =
 [[ 0.  0.  1.]
 [ 0.  0. -1.]
 [ 1. -1.  1.]]

グラフ化¶

In [23]:
# 単位球メッシュ
u = np.linspace(0, 2*np.pi, 40)
v = np.linspace(0, np.pi, 20)
xs = np.outer(np.cos(u), np.sin(v))
ys = np.outer(np.sin(u), np.sin(v))
zs = np.outer(np.ones_like(u), np.cos(v))
S = np.stack([xs, ys, zs], axis=0).reshape(3, -1)  # (3, N)

# A を作用
E = (A @ S).reshape(3, xs.shape[0], xs.shape[1])
xe, ye, ze = E[0], E[1], E[2]

# 固有ベクトル(列)
u0, u2, um1 = P[:, 0], P[:, 1], P[:, 2]  # λ=0,2,-1 の順
lam0, lam2, lamm1 = lam[0], lam[1], lam[2]

fig = plt.figure(figsize=(12, 6))

# 左:単位球と楕円体
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
ax1.plot_wireframe(xs, ys, zs, color='0.6', linewidth=0.5, rstride=2, cstride=2, label='単位球')
ax1.plot_wireframe(xe, ye, ze, color='C3', linewidth=0.8, rstride=2, cstride=2)
# 固有ベクトル(主軸)
ax1.quiver(0, 0, 0, u0[0], u0[1], u0[2], color='C0', linewidth=2)
ax1.quiver(0, 0, 0, u2[0], u2[1], u2[2], color='C1', linewidth=2)
ax1.quiver(0, 0, 0, um1[0], um1[1], um1[2], color='C2', linewidth=2)
ax1.set_title("単位球 → Aで楕円体に(主軸=固有ベクトル)")
ax1.set_box_aspect([1,1,1])

# 右:固有ベクトルと λv の伸び
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
def draw3(ax, v, label, color='C0', scale=1.0, ls='-'):
    ax.quiver(0, 0, 0, *(scale*v), color=color, linewidth=2)
    ax.text(*(1.05*scale*v), label, color=color)

draw3(ax2, u0,  f"u0 (λ={lam0:.0f})", color='C0')
draw3(ax2, lam0*u0, "λ u0", color='C0')
draw3(ax2, u2,  f"u2 (λ={lam2:.0f})", color='C1')
draw3(ax2, lam2*u2, "λ u2", color='C1')
draw3(ax2, um1, f"u-1 (λ={lamm1:.0f})", color='C2')
draw3(ax2, lamm1*um1, "λ u-1", color='C2')

# パネルに P, D の数値
panel = "P =\n" + np.array2string(np.round(P, 3)) + "\n\nD =\n" + np.array2string(D)
ax2.text2D(0.98, 0.98, panel, transform=ax2.transAxes,
           ha='right', va='top', bbox=dict(facecolor='white', alpha=0.85, edgecolor='0.6'))
ax2.set_title("固有ベクトルと 伸び(λv)")
ax2.set_box_aspect([1,1,1])

# 表示範囲を少し広めに
all_pts = np.column_stack([u0, u2, um1, lam0*u0, lam2*u2, lamm1*um1, E.reshape(3,-1)])
m = 1.15*np.max(np.abs(all_pts))
for ax in (ax1, ax2):
    ax.set_xlim(-m, m); ax.set_ylim(-m, m); ax.set_zlim(-m, m)
    ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')

plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]: