はじめに
『スタンフォード ベクトル・行列からはじめる最適化数学』の学習ノートです。
「数式の行間埋め」や「Pythonを使っての再現」によって理解を目指します。本と一緒に読んでください。
この記事は1.3節「ベクトルスカラー積」の内容です。
ベクトルの定数倍を可視化します。
【前の内容】
【他の内容】
【今回の内容】
ベクトルのスカラー倍の可視化
ベクトルとスカラーの積(vector-scalar product)をグラフで確認します。
利用するライブラリを読み込みます。
# 利用ライブラリ import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation
2次元の場合
まずは、2次元空間(平面)上でベクトルの和を可視化します。
2次元ベクトルと係数(スカラー値)を指定します。
# ベクトルを指定 a = np.array([4.0, 2.0]) # 係数を指定 beta = 0.75
を
a
、を
beta
として値を指定します。ただし、Pythonでは0からインデックスが割り当てられるので、の値は
a[0]
に対応します。
2次元空間上にベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1]])) + 1 # (原点からの)2Dベクトルを作図 fig, ax = plt.subplots(figsize=(6, 4.5), facecolor='white') ax.quiver(0, 0, *a, angles='xy', scale_units='xy', scale=1) # ベクトルa ax.annotate(xy=0.5*a, text='a', size=15, ha='right', va='bottom') # ベクトルaラベル ax.set_xticks(ticks=np.arange(x_min, x_max+1)) ax.set_yticks(ticks=np.arange(y_min, y_max+1)) ax.grid() ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('a=('+', '.join(map(str, a))+')', loc='left') fig.suptitle('a', fontsize=20) ax.set_aspect('equal') plt.show()
ベクトルのグラフを
axes.quiver()
で描画します。第1・2引数に始点の座標、第3・4引数にベクトルのサイズ(変化量)を指定します。この例では、原点を始点とします。
配列a
の前に*
を付けてアンパック(展開)して指定しています。
のベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], beta*a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], beta*a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], beta*a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], beta*a[1]])) + 1 # 2Dベクトルのスカラー積を作図 fig, ax = plt.subplots(figsize=(6, 4.5), facecolor='white') ax.quiver(0, 0, *a, angles='xy', scale_units='xy', scale=1, fc='none', ec='black', lw=1, ls='dashed', label='$a$') # ベクトルa ax.quiver(0, 0, *beta*a, angles='xy', scale_units='xy', scale=1, color='red', label='$\\beta a$') # ベクトルβa ax.annotate(xy=0.5*beta*a, text='$\\beta a$', size=15, ha='right', va='bottom') # ベクトルβaラベル ax.set_xticks(ticks=np.arange(x_min, x_max+1)) ax.set_yticks(ticks=np.arange(y_min, y_max+1)) ax.grid() ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('$a=('+', '.join(map(str, a))+'), ' + '\\beta='+str(beta)+'$', loc='left') fig.suptitle('$\\beta a$', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
ベクトルと
の積は、
のときは同じ方向に、
のときは反対方向に、
を
倍したベクトルになります。ただし、
のとき
はゼロベクトルになるので、点になります。
係数の値を変化させたアニメーションを作成します。
・作図コード(クリックで展開)
# フレーム数を設定 frame_num = 51 # ベクトルを指定 a = np.array([4.0, 2.0]) # 係数として利用する値を指定 beta_vals = np.linspace(start=-2.0, stop=2.0, num=frame_num) # 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], *beta_vals*a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], *beta_vals*a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], *beta_vals*a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], *beta_vals*a[1]])) + 1 # 作図用のオブジェクトを初期化 fig, ax = plt.subplots(figsize=(6, 4.5), facecolor='white') fig.suptitle('$\\beta a$', fontsize=20) # 作図処理を関数として定義 def update(i): # 前フレームのグラフを初期化 plt.cla() # i番目の係数を作成 beta = beta_vals[i] # 2Dベクトルのスカラー積を作図 ax.quiver(0, 0, *a, angles='xy', scale_units='xy', scale=1, fc='none', ec='black', lw=1, ls='dashed', label='$a$') # ベクトルa ax.quiver(0, 0, *beta*a, angles='xy', scale_units='xy', scale=1, color='red', label='$\\beta a$') # ベクトルβa ax.annotate(xy=0.5*beta*a, text='$\\beta a$', size=15, ha='right', va='bottom') # ベクトルβaラベル ax.set_xticks(ticks=np.arange(x_min, x_max+1)) ax.set_yticks(ticks=np.arange(y_min, y_max+1)) ax.grid() ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('$a=('+', '.join(map(str, a))+'), ' + '\\beta='+str(beta.round(2))+'$', loc='left') ax.legend() ax.set_aspect('equal') # gif画像を作成 ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100) # gif画像を保存 ani.save('scalarprod_vector_2d.gif')
作図処理をupdate()
として定義して、FuncAnimation()
でgif画像を作成します。
の正負によって向きが変わるのを確認できます。
3次元の場合
続いて、3次元空間上でベクトルのスカラー積を可視化します。
3次元ベクトルと係数(スカラー値)を指定します。
# ベクトルを指定 a = np.array([4.0, 2.0, 3.0]) # 係数を指定 beta = 0.75
を
a
として値を指定します。
3次元空間上にベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1]])) + 1 z_min = np.floor(np.min([0.0, a[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2]])) + 1 # (原点からの)3Dベクトルを作図 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') ax.quiver(0, 0, 0, *a, arrow_length_ratio=0.05, color='black') # ベクトルa ax.text(*0.5*a, s='a', size=15, ha='center', va='top') # ベクトルaラベル ax.quiver([0, a[0]], [0, a[1]], [z_min, z_min], [0, 0], [0, 0], [-z_min, a[2]-z_min], color='gray', arrow_length_ratio=0, linestyle=':') # 補助線 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') ax.set_ylabel('y') ax.set_zlabel('z') ax.set_title('a=('+', '.join(map(str, a))+')', loc='left') fig.suptitle('a', fontsize=20) ax.set_aspect('equal') plt.show()
axes.quiver()
の第1・2・3引数に始点の座標、第4・5・6引数にベクトルのサイズを指定します。この例では、原点を始点とします。
のベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], beta*a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], beta*a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], beta*a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], beta*a[1]])) + 1 z_min = np.floor(np.min([0.0, a[2], beta*a[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2], beta*a[2]])) + 1 # 3Dベクトルのスカラー積を作図 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') ax.quiver(0, 0, 0, *a, arrow_length_ratio=0.05, color='black', ls='dashed', label='$a$') # ベクトルa ax.quiver(0, 0, 0, *beta*a, arrow_length_ratio=0.1, color='red', label='$\\beta a$') # ベクトルβa ax.text(*0.5*beta*a, s='$\\beta a$', size=15, ha='center', va='top') # ベクトルβaラベル ax.quiver([0, a[0], beta*a[0]], [0, a[1], beta*a[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, a[2]-z_min, beta*a[2]-z_min], color='gray', arrow_length_ratio=0, linestyle=':') # 補助線 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') ax.set_ylabel('y') ax.set_zlabel('z') ax.set_title('$a=('+', '.join(map(str, a))+'), ' + '\\beta='+str(beta)+'$', loc='left') fig.suptitle('$\\beta a$', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
3次元でも同様なのを確認できます。
係数の値を変化させたアニメーションを作成します。
・作図コード(クリックで展開)
# フレーム数を設定 frame_num = 51 # ベクトルを指定 a = np.array([4.0, 2.0, 3.0]) # 係数として利用する値を指定 beta_vals = np.linspace(start=-2.0, stop=2.0, num=frame_num) # 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], *beta_vals*a[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], *beta_vals*a[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], *beta_vals*a[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], *beta_vals*a[1]])) + 1 z_min = np.floor(np.min([0.0, a[2], *beta_vals*a[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2], *beta_vals*a[2]])) + 1 # 作図用のオブジェクトを初期化 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') fig.suptitle('$\\beta a$', fontsize=20) # 作図処理を関数として定義 def update(i): # 前フレームのグラフを初期化 plt.cla() # i番目の係数を作成 beta = beta_vals[i] # 3Dベクトルのスカラー積を作図 ax.quiver(0, 0, 0, *beta*a, arrow_length_ratio=0.05, color='red', label='$\\beta a$', zorder=-100) # ベクトルβa ax.quiver(0, 0, 0, *a, arrow_length_ratio=0.1, color='black', lw=2, ls='dashed', label='$a$', zorder=100) # ベクトルa ax.text(*0.5*beta*a, s='$\\beta a$', size=15, ha='center', va='top') # ベクトルβaラベル ax.quiver([0, a[0], beta*a[0]], [0, a[1], beta*a[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, a[2]-z_min, beta*a[2]-z_min], color='gray', arrow_length_ratio=0, linestyle=':') # 補助線 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') ax.set_ylabel('y') ax.set_zlabel('z') ax.set_title('$a=('+', '.join(map(str, a))+'), ' + '\\beta='+str(beta.round(2))+'$', loc='left') ax.legend() ax.set_aspect('equal') # gif画像を作成 ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100) # gif画像を保存 ani.save('scalarprod_vector_3d.gif')
この記事では、ベクトルのスカラー倍を可視化しました。次の記事では、ベクトルの線形結合を可視化します。
参考書籍
- Stephen Boyd・Lieven Vandenberghe(著),玉木 徹(訳)『スタンフォード ベクトル・行列からはじめる最適化数学』講談社サイエンティク,2021年.
おわりに
流石にもう少し負荷のあることをしたいです。他と比べてさっぱりした内容になってしまったと思ったのですが、この内容だけでもnotebookからコピペしたら(Pythonコード・LaTeXコマンド込みで)1万文字だったので、まぁこれくらいが構成上丁度いいのかと思います。ちなみに、前回は1.7万文字で次回は1.4万文字でした。
【次の内容】