からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

【Python】5.1-2ベクトルの線形独立の可視化【『スタンフォード線形代数入門』のノート】

はじめに

 『スタンフォード ベクトル・行列からはじめる最適化数学』の学習ノートです。
 「数式の行間埋め」や「Pythonを使っての再現」によって理解を目指します。本と一緒に読んでください。

 この記事は5.1節「線形従属」と5.2節「基底」の内容です。
 線形独立なベクトル集合のグラフを作成します。

【前の内容】

www.anarchive-beta.com

【他の内容】

www.anarchive-beta.com

【今回の内容】

ベクトルの線形独立の可視化

 ベクトルの線形独立(inear independent・linearly independent vectors)をグラフで確認します。
 線形結合については「【Python】1.3:ベクトルの線形結合の可視化【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」、線形従属については「【Python】ベクトルの線形従属の可視化【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」を参照してください。

 利用するライブラリを読み込みます。

# 利用ライブラリ
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


2次元の場合

 まずは、2次元空間(平面)上でベクトルの線形独立を可視化します。

 2次元ベクトルを指定します。

# ベクトルを指定
a1 = np.array([3.0, 2.0])
a2 = np.array([-2.0, 2.0])

 2つのベクトル \mathbf{a}_1 = (a_{1,1}, a_{1,2})^{\top}, \mathbf{a}_2 = (a_{2,1}, a_{2,2})^{\top}a1, a2として値を指定します。Pythonでは0からインデックスが割り当てられるので、 a_{1,1}の値はa1[0]に対応します。

 ベクトル \mathbf{a}_1, \mathbf{a}_2と平行な平面(原点と点 \mathbf{a}_1, \mathbf{a}_2を通る平面)の座標を計算します。

# 平面用の係数を作成
beta_vals = np.arange(start=-1.5, stop=1.6, step=0.5)
print(beta_vals)
print(beta_vals.shape)

# 格子点を作成
beta1_grid, beta2_grid = np.meshgrid(beta_vals, beta_vals)
print(beta1_grid.shape)

# ベクトルa1,a2と平行な平面の座標を計算
x1_grid = beta1_grid * a1[0] + beta2_grid * a2[0]
x2_grid = beta1_grid * a1[1] + beta2_grid * a2[1]
print(x1_grid[:5, :5])
print(x2_grid[:5, :5])
[-1.5 -1.  -0.5  0.   0.5  1.   1.5]
(7,)
(7, 7)
[[-1.5  0.   1.5  3.   4.5]
 [-2.5 -1.   0.5  2.   3.5]
 [-3.5 -2.  -0.5  1.   2.5]
 [-4.5 -3.  -1.5  0.   1.5]
 [-5.5 -4.  -2.5 -1.   0.5]]
[[-6. -5. -4. -3. -2.]
 [-5. -4. -3. -2. -1.]
 [-4. -3. -2. -1.  0.]
 [-3. -2. -1.  0.  1.]
 [-2. -1.  0.  1.  2.]]

  \mathbf{a}_1, \mathbf{a}_2を線形結合したベクトル \mathbf{b} = \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2がとり得る値(座標)を計算します。
  \beta_1, \beta_2の値をbeta_valsとし、np.meshgrid()で格子状の点(全ての組み合わせ)を作成してbeta1_grid, beta2_gridとして、x軸の値 b_1 = \beta_1 a_{1,1} + \beta_2 a_{2,1}とy軸の値 b_2 = \beta_1 a_{1,2} + \beta_2 a_{2,2}を計算してx1_grid, x2_gridとします。

 2次元空間上に、ベクトル \mathbf{a}_1, \mathbf{a}_2と平面のグラフを作成します。

# グラフサイズ用の値を設定
x_min = np.floor(x1_grid.min())
x_max =  np.ceil(x1_grid.max())
y_min = np.floor(x2_grid.min())
y_max =  np.ceil(x2_grid.max())

# 線形独立の2Dベクトルを作図
fig, ax = plt.subplots(figsize=(8, 6), facecolor='white')
ax.quiver(0, 0, *a1, 
          color='red', width=0.01, headwidth=5, headlength=5, 
          angles='xy', scale_units='xy', scale=1, 
          label='$a_1=('+', '.join(map(str, a1))+')$') # ベクトルa1
ax.quiver(0, 0, *a2, 
          color='blue', width=0.01, headwidth=5, headlength=5, 
          angles='xy', scale_units='xy', scale=1, 
          label='$a_2=('+', '.join(map(str, a2))+')$') # ベクトルa2
ax.plot(x1_grid, x2_grid, color='C0', zorder=0) # ベクトルa1,a2と平行な平面:(a2と平行な直線)
ax.plot(x1_grid.T, x2_grid.T, color='C0', 
        label=['$\\beta_1 a_1 + \\beta_2 a_2$']+['' for _ in range(len(beta_vals)-1)], zorder=0) # ベクトルa1,a2と平行な平面:(a1と平行な直線)
ax.set_xticks(ticks=np.arange(x_min, x_max+1))
ax.set_yticks(ticks=np.arange(y_min, y_max+1))
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.grid()
fig.suptitle('linear independent', fontsize=20)
ax.legend()
ax.set_aspect('equal')
plt.show()

2次元空間における線形独立であるベクトル集合

 axes.quiver()で2次元ベクトルを描画します。第1・2引数に始点の座標、第3・4引数にベクトルのサイズ(移動量)を指定します。その他に、指定した値の通りに(調整せずに)矢印を描画するための設定をしています。
 配列a1, a2の前に*を付けてアンパック(展開)して座標を指定します。始点は原点です。

 平面のグラフについては「傾いた2次元格子の作図【Matplotlib】 - からっぽのしょこ」を参照してください。

 ベクトル \mathbf{a}_1, \mathbf{a}_2それぞれと平行な直線によって平面が作られます。この平面上の点は、ベクトル \mathbf{a}_1, \mathbf{a}_2の線形結合によって表現できます。

 ベクトル \mathbf{a}_1, \mathbf{a}_2と線形結合したベクトル \mathbf{b} = \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2のグラフについて、係数(ベクトル)の値を変化させたアニメーションを作成します。

・作図コード(クリックで展開)

# フレーム数を設定
frame_num = 60

# 係数の作成用の値(ラジアン)として利用する値を指定
t_n = np.linspace(start=0.0, stop=2.0*np.pi, num=frame_num+1)[:frame_num]

# ベクトルのサイズ調整用の値を指定
r = 1.0

# グラフオブジェクトを初期化
fig, ax = plt.subplots(figsize=(8, 6), facecolor='white')
fig.suptitle('linear dependent', fontsize=20)

# 作図処理を関数として定義
def update(i):
    
    # 前フレームのグラフを初期化
    plt.cla()
    
    # i番目の係数を作成
    t = t_n[i]
    beta1 = r * np.cos(t)
    beta2 = r * np.sin(t)
    
    # 線形従属になるベクトルを作成
    b = beta1 * a1 + beta2 * a2
    
    # ラベル用の符号を設定
    sgn2 = '+' if beta2 >= 0.0 else ''
    
    # 線形従属の2Dベクトルを作図
    ax.quiver(0, 0, *a1, 
              color='red', width=0.01, headwidth=5, headlength=5, 
              angles='xy', scale_units='xy', scale=1, 
              label='$a_1=('+', '.join(map(str, a1))+')$') # ベクトルa1
    ax.quiver(0, 0, *a2, 
              color='blue', width=0.01, headwidth=5, headlength=5, 
              angles='xy', scale_units='xy', scale=1, 
              label='$a_2=('+', '.join(map(str, a2))+')$') # ベクトルa2
    ax.quiver(0, 0, *b, 
              color='purple', width=0.01, headwidth=5, headlength=5, 
              angles='xy', scale_units='xy', scale=1, 
              label='$b=('+', '.join(map(str, b.round(2)))+')$') # ベクトルb
    ax.plot(x1_grid, x2_grid, color='C0', zorder=0) # ベクトルa1,a2と平行な平面:(a2と平行な直線)
    ax.plot(x1_grid.T, x2_grid.T, color='C0', 
            label=['$\\beta_1 a_1 + \\beta_2 a_2$']+['' for _ in range(len(beta_vals)-1)], zorder=0) # ベクトルa1,a2と平行な平面:(a1と平行な直線)
    ax.set_xlabel('$x_1$')
    ax.set_ylabel('$x_2$')
    ax.set_title('$b=' + str(beta1.round(2))+'a_1' + sgn2+str(beta2.round(2))+'a_2$', loc='left')
    ax.grid()
    ax.legend()
    ax.set_aspect('equal')

# gif画像を作成
ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100)

# gif画像を保存
ani.save('independence_2d.gif')

 作図処理をupdate()として定義して、FuncAnimation()でgif画像を作成します。

2次元空間における線形従属であるベクトル集合

 サイズrを変更すると、ベクトル \mathbf{b}が平面(とその延長)上の全ての点になり得るのを確認できます。

 同一平面上に3つ以上のベクトルがある場合、それらは線形結合で等しくなる(この例だと \mathbf{a}_3 = \mathbf{b}として) \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 = \mathbf{a}_3ので、 \beta_3 = -1として( \mathbf{a}_3を移項して) \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3 = \mathbf{0}が成り立ち、線形従属の条件を満たすのでした(5.1節)。ここで、 \mathbf{0}は2次元の0ベクトルです。
 逆に、同一平面上に平行でない2つのベクトルのみの場合、 \beta_1 = \beta_2 = 0のときに限り \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 = \mathbf{0}が成り立ち、線形独立の条件を満たします。
 またこの例は、線形独立な2つの2次元ベクトルなので、基底ベクトルと言えます。

 以上が、2次元におけるベクトルの線形独立の可視化です。

3次元の場合

 次は、3次元空間上でベクトルの線形独立を可視化します。

 3次元ベクトルを指定します。

# ベクトルを指定
a1 = np.array([2.0, 2.0, 2.0])
a2 = np.array([-2.0, 1.5, 1.0])
a3 = np.array([1.0, -1.0, -3.0])

 3つのベクトル \mathbf{a}_i = (a_{i,1}, a_{i,2}, a_{i,3})^{\top}\ i = 1, 2, 3a*として値を指定します。

 ベクトル \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3それぞれと平行な直線によって作られる空間の座標を計算します。

# 空間用の係数を作成
beta_vals = np.arange(start=-1.0, stop=1.1, step=1.0)
print(beta_vals)
print(beta_vals.shape)

# 格子点を作成
beta1_grid, beta2_grid, beta3_grid = np.meshgrid(beta_vals, beta_vals, beta_vals)
print(beta1_grid.shape)

# ベクトルa1,a2,a3と平行な空間の座標を計算
x1_grid = beta1_grid * a1[0] + beta2_grid * a2[0] + beta3_grid * a3[0]
x2_grid = beta1_grid * a1[1] + beta2_grid * a2[1] + beta3_grid * a3[1]
x3_grid = beta1_grid * a1[2] + beta2_grid * a2[2] + beta3_grid * a3[2]
print(x1_grid[0])
print(x2_grid[0])
print(x3_grid[0])
[-1.  0.  1.]
(3,)
(3, 3, 3)
[[-1.  0.  1.]
 [ 1.  2.  3.]
 [ 3.  4.  5.]]
[[-2.5 -3.5 -4.5]
 [-0.5 -1.5 -2.5]
 [ 1.5  0.5 -0.5]]
[[ 0. -3. -6.]
 [ 2. -1. -4.]
 [ 4.  1. -2.]]

  \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3を線形結合したベクトル \mathbf{b} = \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3がとり得る値(座標)を計算します。
  \beta_1, \beta_2, \beta_3の値をbeta_valsとし、np.meshgrid()で格子状の点(全ての組み合わせ)を作成してbeta*_gridとして、x軸・y軸・z軸の値 b_i = \beta_1 a_{1,i} + \beta_2 a_{2,i} + \beta_3 a_{3,i}を計算してx*_gridとします。

 3次元空間上に、ベクトル \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3と空間(3方向の平面)のグラフを作成します。

# グラフサイズ用の値を設定
x_min = np.floor(x1_grid.min())
x_max =  np.ceil(x1_grid.max())
y_min = np.floor(x2_grid.min())
y_max =  np.ceil(x2_grid.max())
z_min = np.floor(x3_grid.min())
z_max =  np.ceil(x3_grid.max())

# 矢のサイズを指定
l = 0.6

# 線形独立の3Dベクトルを作図
fig, ax = plt.subplots(figsize=(8, 8), facecolor='white', 
                       subplot_kw={'projection': '3d'})
ax.quiver(0, 0, 0, *a1, 
          color='red', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a1), 
          label='$a_1=('+', '.join(map(str, a1))+')$') # ベクトルa1
ax.quiver(0, 0, 0, *a2, 
          color='blue', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a2), 
          label='$a_2=('+', '.join(map(str, a2))+')$') # ベクトルa2
ax.quiver(0, 0, 0, *a3, 
          color='green', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a3), 
          label='$a_3=('+', '.join(map(str, a3))+')$') # ベクトルa3
ax.quiver([0, a1[0], a2[0], a3[0]], [0, a1[1], a2[1], a3[1]], [0, a1[2], a2[2], a3[2]], 
          [0, 0, 0, 0], [0, 0, 0, 0], [z_min, z_min-a1[2], z_min-a2[2], z_min-a3[2]], 
          color=['gray', 'red', 'blue', 'green'], arrow_length_ratio=0, linestyle=':') # 座標用の補助線
for i in range(len(beta_vals)):
    formula_label = '$\\beta_1 a_1 + \\beta_2 a_2 + \\beta_3 a_3$' if i == 0 else '' # 1つだけ凡例を設定
    ax.plot_wireframe(x1_grid[i], x2_grid[i], x3_grid[i], alpha=0.5, 
                      label=formula_label) # ベクトルa1,a2,a3による空間:(a1,a3と平行な平面)
    ax.plot_wireframe(x1_grid[:, i], x2_grid[:, i], x3_grid[:, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a2,a3と平行な平面)
    ax.plot_wireframe(x1_grid[:, :, i], x2_grid[:, :, i], x3_grid[:, :, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a1,a2と平行な平面)
#ax.set_xticks(ticks=np.arange(x_min, x_max+1))
#ax.set_yticks(ticks=np.arange(y_min, y_max+1))
#ax.set_zticks(ticks=np.arange(z_min, z_max+1))
ax.set_zlim(z_min, z_max)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.set_zlabel('$x_3$')
fig.suptitle('linear independence', fontsize=20)
ax.legend()
ax.set_aspect('equal')
#ax.view_init(elev=90, azim=270) # xy面
#ax.view_init(elev=0, azim=270) # xz面
#ax.view_init(elev=0, azim=0) # yz面
plt.show()

3次元空間における線形独立であるベクトル集合

 axes.quiver()で3次元ベクトルを描画します。第1・2・3引数に始点の座標、第4・5・6引数にベクトルのサイズ(移動量)を指定します。
 配列a1, a2, a3の前に*を付けてアンパック(展開)して座標を指定します。始点は原点です。

 arrow_length_ratio引数で矢のサイズ(全体に対する矢の割合)を指定できます。この例では、各ベクトルのノルムの逆数を指定することで、ベクトルのサイズに関わらず、全ての矢のサイズを統一します。
 さらに、全てのベクトルで同じ値lを掛けることで、サイズを調整できます。

 空間のグラフについては「傾いた3次元格子の作図【Matplotlib】 - からっぽのしょこを参照してください。

 ベクトル \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3のそれぞれと平行な直線によって空間が作られます。この空間上の点は、ベクトル \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3の線形結合によって表現できます。

 グラフを回転させて確認します。

・作図コード(クリックで展開)

# フレーム数を指定
frame_num = 60

# 水平方向の角度として利用する値を作成
h_n = np.linspace(start=0.0, stop=360.0, num=frame_num+1)[:frame_num]

# グラフオブジェクトを初期化
fig, ax = plt.subplots(figsize=(8, 8), facecolor='white', 
                       subplot_kw={'projection': '3d'})
fig.suptitle('linear independence', fontsize=20)

# 作図処理を関数として定義
def update(i):
    
    # 前フレームのグラフを初期化
    plt.cla()

    # i番目の角度を取得
    h = h_n[i]
    
    # 線形独立の3Dベクトルを作図
    ax.quiver(0, 0, 0, *a1, 
              color='red', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a1), 
              label='$a_1=('+', '.join(map(str, a1))+')$') # ベクトルa1
    ax.quiver(0, 0, 0, *a2, 
              color='blue', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a2), 
              label='$a_2=('+', '.join(map(str, a2))+')$') # ベクトルa2
    ax.quiver(0, 0, 0, *a3, 
              color='green', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a3), 
              label='$a_3=('+', '.join(map(str, a3))+')$') # ベクトルa3
    ax.quiver([0, a1[0], a2[0], a3[0]], [0, a1[1], a2[1], a3[1]], [0, a1[2], a2[2], a3[2]], 
              [0, 0, 0, 0], [0, 0, 0, 0], [z_min, z_min-a1[2], z_min-a2[2], z_min-a3[2]], 
              color=['gray', 'red', 'blue', 'green'], arrow_length_ratio=0, linestyle=':') # 座標用の補助線
    for i in range(len(beta_vals)):
        formula_label = '$\\beta_1 a_1 + \\beta_2 a_2 + \\beta_3 a_3$' if i == 0 else '' # 1つだけ凡例を設定
        ax.plot_wireframe(x1_grid[i], x2_grid[i], x3_grid[i], alpha=0.5, 
                          label=formula_label) # ベクトルa1,a2,a3による空間:(a1,a3と平行な平面)
        ax.plot_wireframe(x1_grid[:, i], x2_grid[:, i], x3_grid[:, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a2,a3と平行な平面)
        ax.plot_wireframe(x1_grid[:, :, i], x2_grid[:, :, i], x3_grid[:, :, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a1,a2と平行な平面)
    #ax.set_xticks(ticks=np.arange(x_min, x_max+1))
    #ax.set_yticks(ticks=np.arange(y_min, y_max+1))
    #ax.set_zticks(ticks=np.arange(z_min, z_max+1))
    ax.set_zlim(z_min, z_max)
    ax.set_xlabel('$x_1$')
    ax.set_ylabel('$x_2$')
    ax.set_zlabel('$x_3$')
    ax.legend()
    ax.set_aspect('equal')
    ax.view_init(elev=30, azim=h) # 表示角度

# gif画像を作成
ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100)

# gif画像を保存
ani.save('independence360_3d.gif')

3次元空間における線形独立であるベクトル集合

3次元空間における線形独立であるベクトル集合


 ベクトル \mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3と線形結合したベクトル \mathbf{b} = \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3のグラフについて、係数(ベクトル)の値を変化させたアニメーションを作成します。

・作図コード(クリックで展開)

# フレーム数を設定
frame_num = 60

# 係数の作成用の値(ラジアン)として利用する値を指定
t_n = np.linspace(start=0.0, stop=2.0*np.pi, num=frame_num+1)[:frame_num]
u_n = np.linspace(start=2.0/3.0*np.pi, stop=2.0/3.0*np.pi, num=frame_num+1)[:frame_num]

# ベクトルのサイズ調整用の値を指定
r = 1.0

# 矢印のサイズを指定
l = 0.6

# グラフオブジェクトを初期化
fig, ax = plt.subplots(figsize=(8, 8), facecolor='white', 
                       subplot_kw={'projection': '3d'})
fig.suptitle('linear dependence', fontsize=20)

# 作図処理を関数として定義
def update(i):
    
    # 前フレームのグラフを初期化
    plt.cla()
    
    # i番目の係数を作成
    t = t_n[i]
    u = u_n[i]
    beta1 = r * np.sin(t) * np.cos(u)
    beta2 = r * np.sin(t) * np.sin(u)
    beta3 = r * np.cos(t)
    
    # 線形従属になるベクトルを作成
    b = beta1 * a1 + beta2 * a2 + beta3 * a3
    
    # ラベル用の符号を設定
    sgn2 = '+' if beta2 >= 0.0 else ''
    sgn3 = '+' if beta3 >= 0.0 else ''
    
    # 線形従属の3Dベクトルを作図
    ax.quiver(0, 0, 0, *a1, 
              color='red', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a1), 
              label='$a_1=('+', '.join(map(str, a1))+')$') # ベクトルa1
    ax.quiver(0, 0, 0, *a2, 
              color='blue', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a2), 
              label='$a_2=('+', '.join(map(str, a2))+')$') # ベクトルa2
    ax.quiver(0, 0, 0, *a3, 
              color='green', linewidth=3, arrow_length_ratio=l/np.linalg.norm(a3), 
              label='$a_3=('+', '.join(map(str, a3))+')$') # ベクトルa3
    ax.quiver(0, 0, 0, *b, 
              color='chocolate', linewidth=3, arrow_length_ratio=l/np.linalg.norm(b), 
              label='$b=('+', '.join(map(str, b.round(2)))+')$') # ベクトルb
    ax.quiver([0, a1[0], a2[0], a3[0], b[0]], [0, a1[1], a2[1], a3[1], b[1]], [0, a1[2], a2[2], a3[2], b[2]], 
              [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [z_min, z_min-a1[2], z_min-a2[2], z_min-a3[2], z_min-b[2]], 
              color=['gray', 'red', 'blue', 'green', 'chocolate'], arrow_length_ratio=0, linestyle=':') # 座標用の補助線
    for i in range(len(beta_vals)):
        formula_label = '$\\beta_1 a_1 + \\beta_2 a_2 + \\beta_3 a_3$' if i == 0 else '' # 1つだけ凡例を設定
        ax.plot_wireframe(x1_grid[i], x2_grid[i], x3_grid[i], alpha=0.5, 
                          label=formula_label) # ベクトルa1,a2,a3による空間:(a1,a3と平行な平面)
        ax.plot_wireframe(x1_grid[:, i], x2_grid[:, i], x3_grid[:, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a2,a3と平行な平面)
        ax.plot_wireframe(x1_grid[:, :, i], x2_grid[:, :, i], x3_grid[:, :, i], alpha=0.5) # ベクトルa1,a2,a3による空間:(a1,a2と平行な平面)
    ax.set_zlim(z_min, z_max)
    ax.set_xlabel('$x_1$')
    ax.set_ylabel('$x_2$')
    ax.set_zlabel('$x_3$')
    ax.set_title('$b=' + str(beta1.round(2))+'a_1' + sgn2+str(beta2.round(2))+'a_2' + sgn3+str(beta3.round(2))+'a_3$', loc='left')
    ax.legend(loc='upper left', prop={'size': 7})
    ax.set_aspect('equal')
    #ax.view_init(elev=90, azim=270) # xy面
    #ax.view_init(elev=0, azim=270) # xz面
    #ax.view_init(elev=0, azim=0) # yz面

# gif画像を作成
ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100)

# gif画像を保存
ani.save('dependence_3d.gif')

3次元空間における線形従属であるベクトル集合

 サイズrと角度t, uを変更すると、ベクトル \mathbf{b}が空間(とその延長)上の全ての点になり得るのを確認できます。

 同一空間上に4つ以上のベクトルがある場合、それらは線形結合で等しくなる(この例だと \mathbf{a}_4 = \mathbf{b}として) \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3 = \mathbf{a}_4なるので、 \beta_4 = -1として( \mathbf{a}_4を移項して) \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3 + \beta_4 \mathbf{a}_4 = \mathbf{0}が成り立ち、線形従属の条件を満たすのでした(5.1節)。ここで、 \mathbf{0}は3次元の0ベクトルです。
 逆に、同一平面上に平行でない3つのベクトルのみの場合、 \beta_1 = \beta_2 = \beta_3 = 0のときに限り \beta_1 \mathbf{a}_1 + \beta_2 \mathbf{a}_2 + \beta_3 \mathbf{a}_3 = \mathbf{0}が成り立ち、線形独立の条件を満たします。
 またこの例は、線形独立な3つの3次元ベクトルなので、基底ベクトルと言えます。

 以上が、3次元におけるベクトルの線形独立の可視化です。

 この記事では、線形独立なベクトルを可視化しました。次の記事では、正射影ベクトルを可視化します。

参考書籍

  • Stephen Boyd・Lieven Vandenberghe(著),玉木 徹(訳)『スタンフォード ベクトル・行列からはじめる最適化数学』講談社サイエンティク,2021年.

おわりに

 前回の記事と対の内容になってるのでセットで読んでください。

 (どうでもいいのですが)自分の感覚的に「従属↔独立」の関係は「従属↔非従属」ではなく「非独立↔独立」なので「dependence↔independence」の文字列と意味を対応させにくい。

【次の内容】

www.anarchive-beta.com