行列式の幾何的な解釈:体積拡大率#
2つのベクトルが四角形を表すとみなす。この四角形を変形させる行列\(A\)があったとき、変換後の四角形の面積はもとの面積の\(\text{det}(A)\)倍である、と解釈できる
(行列式の値が正の値のとき。負の場合は軸が反転して裏返しになる。\(\text{det}(A)=0\)ならぺちゃんこに潰れている状態)
例えば\(I \in \mathbb{R}^{2\times 2}\)が構成する四角形に\(A\)を乗じて\(AI=A\)とするときの拡大率ともいえるし、\(A\)の面積とも言える
Show code cell source
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import japanize_matplotlib
e0 = [1, 0]
e1 = [0, 1]
I = np.array([e0, e1])
O = np.array([0, 0])
fig, ax = plt.subplots(figsize=[4, 4], dpi=72)
ax.grid(True, alpha=.5)
ax.arrow(*O, *e0, width=0.01, color="black", length_includes_head=True)
ax.arrow(*O, *e1, width=0.01, color="black", length_includes_head=True)
ax.fill_between(x=[0, 1], y1=0, y2=1, alpha=.5)
ax.set(xlim=[-0.5, 1.5], ylim=[-0.5, 1.5], xticks=[0, 1], yticks=[0, 1])
fig.show()
適当な行列\(A\)で変換するとこうなる
A = np.array([
[1, 1],
[0, 1]
])
e0_ = A @ e0
e1_ = A @ e1
y_ = e0_ + e1_
Show code cell source
fig, ax = plt.subplots(dpi=72)
ax.grid(True, alpha=.5)
ax.arrow(0, 0, *e0_, width=0.01, color="black", length_includes_head=True)
ax.arrow(0, 0, *e1_, width=0.01, color="black", length_includes_head=True)
d = np.array([e0_, y_])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
d = np.array([e1_, y_])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
x = np.linspace(0, y_[0], 11)
ax.fill_between(x=x, y1=[max(e - 1, 0) for e in x], y2=[min(e, 1) for e in x], alpha=.5)
ax.set(xlim=[-0.25, 2.25], ylim=[-0.25, 1.25], xticks=[0, 1, 2], yticks=[0, 1])
fig.show()
平行四辺形の面積は底辺×高さ。今回は底辺も高さも1なので、面積は変わっていない。
この行列\(A\)の行列式は1になる
np.linalg.det(A)
1.0
参考:Chapter 6 行列式 | 線形代数のエッセンス - YouTube
(例)次のような行列の場合は…?#
A = np.array([
[1, 2],
[1, 3]
])
B = np.array([
[1, 102],
[1, 103]
])
fig, axes = plt.subplots(ncols=2, figsize=[8, 4], dpi=72)
for X, ax in zip([A, B], axes):
x0_ = X[0]
x1_ = X[1]
y_ = x0_ + x1_
ax.grid(True, alpha=.5)
ax.arrow(0, 0, *x0_, width=0.01, color="black", length_includes_head=True)
ax.arrow(0, 0, *x1_, width=0.01, color="black", length_includes_head=True)
d = np.array([x0_, y_])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
d = np.array([x1_, y_])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
x = np.linspace(0, y_[0], 11)
ax.set(title=f"det = {np.linalg.det(X)}")
fig.show()
どうしてそうなるのか#
\(\boldsymbol{a}, \boldsymbol{b}\) を平面 \(\boldsymbol{R}^2\) の 2 つのベクトルとする。 \(O\) を座標の原点とし、 \(A, B\) を \(\overrightarrow{O A}\) \(=\boldsymbol{a}, \overrightarrow{O B}=\boldsymbol{b}\) であるような点とする。 \(O A, O B\) を 2 辺とする平行四辺形 \(O A P B\) を、\(\boldsymbol{a}, \boldsymbol{b}\)を2辺とする平行四辺形という。その面積Sを求めたい。
もし\(\boldsymbol{a}, \boldsymbol{b}\)が1次従属なら、OAPBは1つの線分になるので\(S=0\)
\(\boldsymbol{a}, \boldsymbol{b}\)が1次独立のとき、\(\boldsymbol{a}, \boldsymbol{b}\)のなす角を\(\theta\)とすれば、 \(B\)から辺\(OA\)に下した垂線の長さは\(\|\boldsymbol{b}\| \sin \theta\)であるから、面積は底辺×高さで
両辺を2乗にする
\(\sin ^2 \theta=1-\cos ^2 \theta\) であり \(\cos \theta = \frac{ \boldsymbol{a} \cdot \boldsymbol{b} }{ \|\boldsymbol{a}\| \|\boldsymbol{b}\| }\)なので
\(\boldsymbol{a} = (a_1, a_2)^T, \boldsymbol{b}=(b_1, b_2)^T\)とすれば、
ゆえに
Show code cell source
X = np.array([
[2, 1],
[0, 1]
])
a = X @ e0
b = X @ e1
P = a + b
fig, ax = plt.subplots(figsize=[4, 4], dpi=100)
ax.grid(True, alpha=.5)
ax.text(0, 0, "O", ha="right", va="top")
ax.text(*a, "A", ha="left", va="top")
ax.text(*b, "B", ha="left", va="bottom")
ax.text(*P, "P", ha="left", va="bottom")
ax.arrow(0, 0, *a, width=0.01, color="black", length_includes_head=True)
ax.arrow(0, 0, *b, width=0.01, color="black", length_includes_head=True)
d = np.array([a, P])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
d = np.array([b, P])
ax.plot(d[:, 0], d[:, 1], color="black", linestyle="--")
# 垂線 y = |b| sinθ をもとめる
cos_theta = (a @ b) / (np.linalg.norm(a) * np.linalg.norm(b))
theta = np.arccos(cos_theta)
y = np.linalg.norm(b) * np.sin(theta)
ax.vlines(x=b[0], ymin=0, ymax=y, color="black", linestyle="--")
ax.text(b[0], y/2, r"$\|b\| \sin \theta$", ha="left", va="center")
# x = np.linspace(0, y_[0], 11)
# ax.fill_between(x=x, y1=[max(e - 1, 0) for e in x], y2=[min(e, 1) for e in x], alpha=.5)
ax.set(xlim=[-0.25, 3.25], ylim=[-0.25, 1.25],
xticks=range(4), yticks=range(2))
# Drawing the angle θ near O with an arc
ax.text(0.4, 0.15, "θ", ha="center", va="center")
angle = np.linspace(0, np.arctan2(B[0], B[1]), 100) # Calculate the angle of OB relative to the x-axis
radius = 0.3 # Radius of the arc for angle representation
x_arc = radius * np.cos(angle)
y_arc = radius * np.sin(angle)
ax.plot(x_arc, y_arc, 'k-')
fig.show()
import numpy as np
np.sin(np.pi) - np.cos(np.pi)
1.0000000000000002
- np.cos(np.pi) + np.sin(np.pi)
1.0000000000000002