第1章: ベクトルと行列の基礎

Vectors and Matrices Fundamentals

1.1 ベクトルの基礎

📐 定義: ベクトル
n次元ベクトルは n 個の数の組: \[\mathbf{v} = \begin{pmatrix} v_1 \\ v_2 \\ \vdots \\ v_n \end{pmatrix}\] 大きさと向きを持つ量を表します(位置、速度、力など)。

💻 コード例1: NumPyによるベクトル演算

Python実装: NumPyによるベクトル演算
import numpy as np import matplotlib.pyplot as plt # ベクトルの定義 v1 = np.array([3, 2]) v2 = np.array([1, 4]) # ベクトルの演算 v_sum = v1 + v2 # 和 v_diff = v1 - v2 # 差 v_scalar = 2 * v1 # スカラー倍 print("ベクトル演算:") print(f"v1 = {v1}") print(f"v2 = {v2}") print(f"v1 + v2 = {v_sum}") print(f"v1 - v2 = {v_diff}") print(f"2 * v1 = {v_scalar}") # 可視化 fig, ax = plt.subplots(figsize=(8, 8)) origin = [0, 0] # ベクトルを矢印で描画 ax.quiver(*origin, *v1, angles='xy', scale_units='xy', scale=1, color='blue', width=0.01, label='v1') ax.quiver(*origin, *v2, angles='xy', scale_units='xy', scale=1, color='red', width=0.01, label='v2') ax.quiver(*origin, *v_sum, angles='xy', scale_units='xy', scale=1, color='green', width=0.01, label='v1+v2') # 平行四辺形の法則を表示 ax.plot([v1[0], v_sum[0]], [v1[1], v_sum[1]], 'k--', alpha=0.3) ax.plot([v2[0], v_sum[0]], [v2[1], v_sum[1]], 'k--', alpha=0.3) ax.set_xlim(-1, 6) ax.set_ylim(-1, 7) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('ベクトルの加法') ax.legend() ax.grid(True, alpha=0.3) ax.axhline(y=0, color='k', linewidth=0.5) ax.axvline(x=0, color='k', linewidth=0.5) plt.axis('equal') plt.show()

1.2 内積とノルム

📐 定義: 内積とノルム
ベクトル v, w の内積: \[\mathbf{v} \cdot \mathbf{w} = \sum_{i=1}^n v_i w_i = v_1 w_1 + v_2 w_2 + \cdots + v_n w_n\] ノルム(長さ): \[\|\mathbf{v}\| = \sqrt{\mathbf{v} \cdot \mathbf{v}} = \sqrt{v_1^2 + v_2^2 + \cdots + v_n^2}\]

💻 コード例2: 内積とノルムの計算

# 内積の計算 dot_product = np.dot(v1, v2) # または v1 @ v2 でも可 # ノルムの計算 norm_v1 = np.linalg.norm(v1) norm_v2 = np.linalg.norm(v2) # 角度の計算: cos θ = (v·w) / (||v|| ||w||) cos_theta = dot_product / (norm_v1 * norm_v2) theta_rad = np.arccos(cos_theta) theta_deg = np.degrees(theta_rad) print(f"\n内積と角度:") print(f"v1 · v2 = {dot_product}") print(f"||v1|| = {norm_v1:.4f}") print(f"||v2|| = {norm_v2:.4f}") print(f"v1とv2の成す角度: {theta_deg:.2f}°") # 単位ベクトル(正規化) v1_unit = v1 / norm_v1 v2_unit = v2 / norm_v2 print(f"\nv1の単位ベクトル: {v1_unit}") print(f"単位ベクトルのノルム: {np.linalg.norm(v1_unit):.10f}")

1.3 外積(3次元)

📐 定義: 外積
3次元ベクトル v, w の外積: \[\mathbf{v} \times \mathbf{w} = \begin{pmatrix} v_2 w_3 - v_3 w_2 \\ v_3 w_1 - v_1 w_3 \\ v_1 w_2 - v_2 w_1 \end{pmatrix}\] 結果は v と w の両方に垂直なベクトルです。

💻 コード例3: 外積の計算と可視化

from mpl_toolkits.mplot3d import Axes3D # 3次元ベクトル v_3d = np.array([1, 0, 0]) w_3d = np.array([0, 1, 0]) # 外積の計算 cross_product = np.cross(v_3d, w_3d) print("外積の計算:") print(f"v = {v_3d}") print(f"w = {w_3d}") print(f"v × w = {cross_product}") print(f"||v × w|| = {np.linalg.norm(cross_product):.4f}") # v × w が v, w の両方に垂直であることを確認 print(f"\n垂直性の確認:") print(f"(v × w) · v = {np.dot(cross_product, v_3d):.10f}") print(f"(v × w) · w = {np.dot(cross_product, w_3d):.10f}") # 3D可視化 fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') origin = [0, 0, 0] ax.quiver(*origin, *v_3d, color='blue', arrow_length_ratio=0.1, linewidth=2, label='v') ax.quiver(*origin, *w_3d, color='red', arrow_length_ratio=0.1, linewidth=2, label='w') ax.quiver(*origin, *cross_product, color='green', arrow_length_ratio=0.1, linewidth=2, label='v×w') ax.set_xlim([-0.5, 1.5]) ax.set_ylim([-0.5, 1.5]) ax.set_zlim([-0.5, 1.5]) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') ax.set_title('外積: v × w') ax.legend() plt.show()

1.4 行列の基本演算

📐 定義: 行列
m × n 行列は m 行 n 列の数の配列: \[A = \begin{pmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{pmatrix}\]

💻 コード例4: 行列の基本演算

# 行列の定義 A = np.array([[1, 2, 3], [4, 5, 6]]) B = np.array([[7, 8], [9, 10], [11, 12]]) print("行列の演算:") print(f"A (2×3) =\n{A}\n") print(f"B (3×2) =\n{B}\n") # 転置行列 A_T = A.T print(f"A^T (転置) =\n{A_T}\n") # 行列の積 (2×3) × (3×2) = (2×2) C = A @ B # または np.dot(A, B) print(f"A × B (2×2) =\n{C}\n") # 要素ごとの演算 D = A + A # 同じ形状なら加算可能 E = 2 * A # スカラー倍 print(f"A + A =\n{D}\n") print(f"2 * A =\n{E}")

1.5 特殊な行列

💻 コード例5: 単位行列、零行列、対角行列

# 単位行列(対角成分が1) I = np.eye(3) print("単位行列 I (3×3):") print(I) # 零行列 Z = np.zeros((2, 3)) print(f"\n零行列 O (2×3):\n{Z}") # 対角行列 diag_values = [1, 2, 3] D_diag = np.diag(diag_values) print(f"\n対角行列 D:\n{D_diag}") # 行列の対角成分を取り出す A_square = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) diag_A = np.diag(A_square) print(f"\nA の対角成分: {diag_A}") # トレース(対角成分の和) trace_A = np.trace(A_square) print(f"tr(A) = {trace_A}")

1.6 逆行列

📐 定義: 逆行列
正方行列 A に対して AA⁻¹ = A⁻¹A = I となる A⁻¹ を逆行列と呼びます。 逆行列が存在する ⇔ det(A) ≠ 0(正則行列)

💻 コード例6: 逆行列の計算

# 正則行列 A_inv = np.array([[1, 2], [3, 4]]) # 逆行列の計算 A_inverse = np.linalg.inv(A_inv) print("逆行列の計算:") print(f"A =\n{A_inv}\n") print(f"A^(-1) =\n{A_inverse}\n") # 検証: A × A^(-1) = I product = A_inv @ A_inverse print(f"A × A^(-1) =\n{product}\n") print(f"単位行列に近いか: {np.allclose(product, np.eye(2))}") # 行列式 det_A = np.linalg.det(A_inv) print(f"\ndet(A) = {det_A:.4f}") print(f"det(A) ≠ 0 なので逆行列が存在 ✓")

1.7 線形変換の幾何学的意味

💻 コード例7: 回転行列

# 回転行列: 反時計回りに θ 回転 def rotation_matrix(theta): """2D回転行列""" cos_t = np.cos(theta) sin_t = np.sin(theta) return np.array([[cos_t, -sin_t], [sin_t, cos_t]]) # 45度回転 theta = np.pi / 4 # 45度 R = rotation_matrix(theta) print(f"45度回転行列:") print(R) # 元のベクトル points = np.array([[1, 0], [0, 1], [1, 1], [0, 0]]) # 回転後のベクトル rotated_points = points @ R.T # 可視化 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) # 元の図形 ax1.plot([0, 1], [0, 0], 'b-', linewidth=2, marker='o') ax1.plot([0, 0], [0, 1], 'r-', linewidth=2, marker='o') ax1.set_xlim(-1.5, 1.5) ax1.set_ylim(-1.5, 1.5) ax1.set_xlabel('x') ax1.set_ylabel('y') ax1.set_title('元の図形') ax1.grid(True, alpha=0.3) ax1.axhline(y=0, color='k', linewidth=0.5) ax1.axvline(x=0, color='k', linewidth=0.5) ax1.axis('equal') # 回転後の図形 ax2.plot([0, rotated_points[0,0]], [0, rotated_points[0,1]], 'b-', linewidth=2, marker='o') ax2.plot([0, rotated_points[1,0]], [0, rotated_points[1,1]], 'r-', linewidth=2, marker='o') ax2.set_xlim(-1.5, 1.5) ax2.set_ylim(-1.5, 1.5) ax2.set_xlabel('x') ax2.set_ylabel('y') ax2.set_title('45度回転後') ax2.grid(True, alpha=0.3) ax2.axhline(y=0, color='k', linewidth=0.5) ax2.axvline(x=0, color='k', linewidth=0.5) ax2.axis('equal') plt.tight_layout() plt.show()

💻 コード例8: スケーリングとせん断

# スケーリング行列(拡大・縮小) S = np.array([[2, 0], [0, 0.5]]) # せん断(shear)行列 Sh = np.array([[1, 0.5], [0, 1]]) # 元の正方形の頂点 square = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]) # 変換後 scaled = square @ S.T sheared = square @ Sh.T fig, axes = plt.subplots(1, 3, figsize=(15, 5)) # 元の図形 axes[0].plot(square[:,0], square[:,1], 'b-', linewidth=2) axes[0].fill(square[:,0], square[:,1], alpha=0.3) axes[0].set_title('元の正方形') axes[0].set_xlim(-0.5, 2.5) axes[0].set_ylim(-0.5, 2.5) axes[0].grid(True, alpha=0.3) axes[0].axis('equal') # スケーリング axes[1].plot(scaled[:,0], scaled[:,1], 'r-', linewidth=2) axes[1].fill(scaled[:,0], scaled[:,1], alpha=0.3, color='red') axes[1].set_title('スケーリング (2倍, 0.5倍)') axes[1].set_xlim(-0.5, 2.5) axes[1].set_ylim(-0.5, 2.5) axes[1].grid(True, alpha=0.3) axes[1].axis('equal') # せん断 axes[2].plot(sheared[:,0], sheared[:,1], 'g-', linewidth=2) axes[2].fill(sheared[:,0], sheared[:,1], alpha=0.3, color='green') axes[2].set_title('せん断(shear)') axes[2].set_xlim(-0.5, 2.5) axes[2].set_ylim(-0.5, 2.5) axes[2].grid(True, alpha=0.3) axes[2].axis('equal') plt.tight_layout() plt.show() print("線形変換:") print(f"スケーリング行列:\n{S}") print(f"\nせん断行列:\n{Sh}")

まとめ