はじめに
『スタンフォード ベクトル・行列からはじめる最適化数学』の学習ノートです。
「数式の行間埋め」や「Pythonを使っての再現」によって理解を目指します。本と一緒に読んでください。
この記事は1.3節「ベクトルスカラー積」の内容です。
ベクトルのアフィン結合を可視化します。
【前の内容】
【他の内容】
【今回の内容】
ベクトルのアフィン結合の可視化
ベクトルのアフィン結合(affine combination)をグラフで確認します。アフィン結合は、係数の和が1になる場合のベクトルの線形結合です。
任意の係数による線形結合については「www.anarchive-beta.com」を参照してください。
利用するライブラリを読み込みます。
# 利用ライブラリ import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation
2次元の場合
まずは、2次元空間(平面)上でベクトルのアフィン結合を可視化します。
2次元ベクトルと係数(スカラー値)を指定します。
# ベクトルを指定 a = np.array([-3.0, 1.0]) b = np.array([2.0, 3.0]) # 係数を指定 theta = -0.4
をa, b
、係数をtheta
として値を指定します。ただし、Pythonでは0からインデックスが割り当てられるので、の値はa[0]
に対応します。
2次元空間上に2つのベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1]])) + 1 # (原点からの)2Dベクトルを作図 fig, ax = plt.subplots(figsize=(6, 5), facecolor='white') ax.quiver(0, 0, *a, color='red', angles='xy', scale_units='xy', scale=1) # ベクトルa ax.quiver(0, 0, *b, color='blue', angles='xy', scale_units='xy', scale=1) # ベクトルb ax.annotate(xy=0.5*a, text='a', size=15, ha='center', va='top') # ベクトルaラベル ax.annotate(xy=0.5*b, text='b', size=15, ha='left', va='top') # ベクトルbラベル 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))+'), ' + 'b=('+', '.join(map(str, b))+')', loc='left') fig.suptitle('vector a, b', fontsize=20) ax.set_aspect('equal') plt.show()
ベクトルのグラフをaxes.quiver()
で描画します。第1・2引数に始点の座標、第3・4引数にベクトルのサイズ(変化量)を指定します。この例では、原点を始点とします。
配列a, b
の前に*
を付けてアンパック(展開)して指定しています。
点を通る直線を計算します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], b[0], (1.0-theta)*a[0], (1.0-theta)*a[0]+theta*b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0], (1.0-theta)*a[0], (1.0-theta)*a[0]+theta*b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1], (1.0-theta)*a[1], (1.0-theta)*a[1]+theta*b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1], (1.0-theta)*a[1], (1.0-theta)*a[1]+theta*b[1]])) + 1 # 傾きを計算 slope = (b[1] - a[1]) / (b[0] - a[0]) print(slope) # 切片を計算 intercept = a[1] - slope * a[0] print(intercept) # x軸の値を作成 x_line = np.linspace(start=x_min, stop=x_max, num=101) # y軸の値を計算 y_line = slope * x_line + intercept #y_line = (x_line - a[0]) * (b[1] - a[1]) / (b[0] - a[0]) + a[1]
0.4
2.2
2点を通る直線の傾き(変化量)は、切片は(または)で計算できます。
各軸の描画範囲*_min, *_max
を使ってx軸の値を作成して、y軸の値をで計算します。
原点と点、2点を通る直線を描画します。
# 点a,bを通る直線を作図 fig, ax = plt.subplots(figsize=(6, 4), facecolor='white') ax.quiver(0, 0, *a, color='red', angles='xy', scale_units='xy', scale=1, label='a') # ベクトルa ax.quiver(0, 0, *b, color='blue', angles='xy', scale_units='xy', scale=1, label='b') # ベクトルb ax.scatter(0, 0, c='orange', s=50) # 原点 ax.scatter(*a, c='red', s=50) # 点a ax.scatter(*b, c='blue', s=50) # 点b ax.plot(x_line, y_line) # 点a,bを通る直線 ax.annotate(xy=[0, 0], text='O', size=15, ha='left', va='top') # 原点ラベル ax.annotate(xy=a, text='a', size=15, ha='right', va='bottom') # 点aラベル ax.annotate(xy=b, text='b', size=15, ha='left', va='bottom') # 点bラベル 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))+'), ' + 'b=('+', '.join(map(str, b))+')', loc='left') fig.suptitle('point a, b', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
原点から移動した点がです(1.1節・1.2節)。
のベクトルを描画します。
# 2Dベクトルの線形結合を作図 fig, ax = plt.subplots(figsize=(6, 4), facecolor='white') ax.scatter(0, 0, c='orange', s=50) # 原点 ax.scatter(*a, c='red', s=50, label='a') # 点a ax.scatter(*b, c='blue', s=50, label='b') # 点b ax.scatter(*(1.0-theta)*a+theta*b, c='purple', s=50, label='c') # 点c ax.plot(x_line, y_line) # 点a,bを通る直線 ax.quiver(0, 0, *(1.0-theta)*a, color='red', angles='xy', scale_units='xy', scale=1) # ベクトル(1-θ)a ax.quiver(*(1.0-theta)*a, *theta*b, color='blue', angles='xy', scale_units='xy', scale=1) # ベクトルθb ax.quiver(0, 0, *(1.0-theta)*a+theta*b, color='purple', angles='xy', scale_units='xy', scale=1) # ベクトルc ax.annotate(xy=0.5*(1.0-theta)*a, text='$(1 - \\theta) a$', size=15, ha='left', va='bottom') # ベクトル(1-θ)aラベル ax.annotate(xy=(1.0-theta)*a+0.5*theta*b, text='$\\theta b$', size=15, ha='right', va='bottom') # ベクトルθbラベル ax.annotate(xy=0.5*((1.0-theta)*a+theta*b), text='$c$', size=15, ha='center', va='top') # ベクトルcラベル 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))+'), ' + 'b=('+', '.join(map(str, b))+'), ' + '$\\theta$='+str(theta), loc='left') fig.suptitle('$c = (1 - \\theta) a + \\theta b$', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
ベクトルとスカラーの積和(線形結合)をとします。
係数の値を変化させたアニメーションを作成します。
・作図コード(クリックで展開)
# フレーム数を設定 frame_num = 51 # ベクトルを指定 a = np.array([-3.0, 1.0]) b = np.array([2.0, 3.0]) # 係数として利用する値を指定 theta_vals = np.linspace(start=-2.0, stop=3.0, num=frame_num) # 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], b[0], *(1.0-theta_vals)*a[0], *(1.0-theta_vals)*a[0]+theta_vals*b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0], *(1.0-theta_vals)*a[0], *(1.0-theta_vals)*a[0]+theta_vals*b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1], *(1.0-theta_vals)*a[1], *(1.0-theta_vals)*a[1]+theta_vals*b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1], *(1.0-theta_vals)*a[1], *(1.0-theta_vals)*a[1]+theta_vals*b[1]])) + 1 # 点a,bを通る直線を計算 slope = (b[1] - a[1]) / (b[0] - a[0]) intercept = a[1] - a[0] * slope x_line = np.linspace(start=x_min, stop=x_max, num=101) y_line = slope * x_line + intercept # 作図用のオブジェクトを初期化 fig, ax = plt.subplots(figsize=(8, 4), facecolor='white') fig.suptitle('$c = (1 - \\theta) a + \\theta b$', fontsize=20) # 作図処理を関数として定義 def update(i): # 前フレームのグラフを初期化 plt.cla() # i番目の係数を作成 theta = theta_vals[i] # 2Dベクトルの線形結合を作図 ax.scatter(0, 0, c='orange', s=50) # 原点 ax.scatter(*a, c='red', s=50, label='a') # 点a ax.scatter(*b, c='blue', s=50, label='b') # 点b ax.scatter(*(1.0-theta)*a+theta*b, c='purple', s=50, label='c') # 点c ax.plot(x_line, y_line) # 点a,bを通る直線 ax.quiver(0, 0, *(1.0-theta)*a, color='red', angles='xy', scale_units='xy', scale=1) # ベクトル(1-θ)a ax.quiver(*(1.0-theta)*a, *theta*b, color='blue', angles='xy', scale_units='xy', scale=1) # ベクトルθb ax.quiver(0, 0, *(1.0-theta)*a+theta*b, color='purple', angles='xy', scale_units='xy', scale=1) # ベクトルc ax.annotate(xy=0.5*(1.0-theta)*a, text='$(1 - \\theta) a$', size=10, ha='left', va='bottom') # ベクトル(1-θ)aラベル ax.annotate(xy=(1.0-theta)*a+0.5*theta*b, text='$\\theta b$', size=10, ha='right', va='bottom') # ベクトルθbラベル ax.annotate(xy=0.5*((1.0-theta)*a+theta*b), text='$c$', size=10, ha='center', va='top') # ベクトルcラベル 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))+'), ' + 'b=('+', '.join(map(str, b))+'), ' + '$\\theta$='+str(theta.round(2)), loc='left') ax.set_aspect('equal') ax.legend() # gif画像を作成 ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100) # gif画像を保存 ani.save('affinecomb_2d.gif')
作図処理をupdate()
として定義して、FuncAnimation()
でgif画像を作成します。
3次元の場合
続いて、3次元空間上でのアフィン結合を可視化します。
3次元ベクトルと係数を指定します。
# ベクトルを指定 a = np.array([-3.0, 1.0, 2.0]) b = np.array([2.0, 3.0, 4.0]) # 係数を指定 theta = -0.4
をa, b
、係数をtheta
として値を指定します。
3次元空間上に2つのベクトルを描画します。
# 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1]])) + 1 z_min = np.floor(np.min([0.0, a[2], b[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2], b[2]])) + 1 # (原点からの)3Dベクトルを作図 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') ax.quiver(0, 0, 0, *a, color='red', arrow_length_ratio=0.1) # ベクトルa ax.quiver(0, 0, 0, *b, color='blue', arrow_length_ratio=0.1) # ベクトルb ax.text(*0.5*a, s='a', size=15, ha='center', va='top') # ベクトルaラベル ax.text(*0.5*b, s='b', size=15, ha='left', va='top') # ベクトルbラベル ax.quiver([0, a[0], b[0]], [0, a[1], b[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, a[2]-z_min, b[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))+'), ' + 'b=('+', '.join(map(str, b))+')', loc='left') fig.suptitle('vector a, b', 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], b[0], (1.0-theta)*a[0], (1.0-theta)*a[0]+theta*b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0], (1.0-theta)*a[0], (1.0-theta)*a[0]+theta*b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1], (1.0-theta)*a[1], (1.0-theta)*a[1]+theta*b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1], (1.0-theta)*a[1], (1.0-theta)*a[1]+theta*b[1]])) + 1 z_min = np.floor(np.min([0.0, a[2], b[2], (1.0-theta)*a[2], (1.0-theta)*a[2]+theta*b[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2], b[2], (1.0-theta)*a[2], (1.0-theta)*a[2]+theta*b[2]])) + 1 # 傾きを計算 slope_xy = (b[1] - a[1]) / (b[0] - a[0]) slope_xz = (b[2] - a[2]) / (b[0] - a[0]) print(slope_xy, slope_xz) # 切片を計算 intercept_xy = a[1] - slope_xy * a[0] intercept_xz = a[2] - slope_xz * a[0] print(intercept_xy, intercept_xz) # x軸の値を作成 x_line = np.linspace(start=x_min, stop=x_max, num=101) # y・z軸の値を計算 y_line = slope_xy * x_line + intercept_xy z_line = slope_xz * x_line + intercept_xz #d = b - a #y_line = (x_line - a[0]) * d[1] / d[0] + a[1] #z_line = (x_line - a[0]) * d[2] / d[0] + a[2]
0.4 0.4
2.2 3.2
x軸とy軸に注目すると、2点を通る直線の傾き(変化量)は、切片は(または)で計算できます。同様にx軸とz軸に注目すると、傾きは、切片は(または)で計算できます。
各軸の描画範囲*_min, *_max
を使ってx軸の値を作成して、y軸の値を、z軸の値をで計算します。
原点と点、2点を通る直線を描画します。
# 点a,bを通る直線を作図 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') ax.scatter(0, 0, c='orange', s=50, zorder=0) # 原点 ax.scatter(*a, c='red', s=50) # 点a ax.scatter(*b, c='blue', s=50) # 点b ax.plot(x_line, y_line, z_line) # 点a,bを通る直線 ax.quiver(0, 0, 0, *a, color='red', arrow_length_ratio=0.1, label='a', zorder=50) # ベクトルa ax.quiver(0, 0, 0, *b, color='blue', arrow_length_ratio=0.1, label='b', zorder=50) # ベクトルb ax.text(0, 0, 0, s='O', size=15, ha='left', va='top', zorder=20) # 原点ラベル ax.text(*a, s='a', size=15, ha='right', va='bottom', zorder=20) # 点aラベル ax.text(*b, s='b', size=15, ha='left', va='bottom', zorder=20) # 点bラベル ax.quiver([0, a[0], b[0]], [0, a[1], b[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, a[2]-z_min, b[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))+'), ' + 'b=('+', '.join(map(str, b))+')', loc='left') fig.suptitle('point a, b', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
3次元でも同様なのを確認できます。
のベクトルを描画します。
# 3Dベクトルの線形結合を作図 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') ax.scatter(0, 0, c='orange', s=50, zorder=0) # 原点 ax.scatter(*a, c='red', s=50, label='a') # 点a ax.scatter(*b, c='blue', s=50, label='b') # 点b ax.scatter(*(1.0-theta)*a+theta*b, c='purple', s=50, label='c') # 点c ax.plot(x_line, y_line, z_line) # 点a,bを通る直線 ax.quiver(0, 0, 0, *(1.0-theta)*a, color='red', arrow_length_ratio=0.1, zorder=50) # ベクトル(1-θ)a ax.quiver(*(1.0-theta)*a, *theta*b, color='blue', arrow_length_ratio=0.1, zorder=50) # ベクトルθb ax.quiver(0, 0, 0, *(1.0-theta)*a+theta*b, color='purple', arrow_length_ratio=0.1, zorder=50) # ベクトル ax.text(0, 0, 0, s='O', size=15, ha='left', va='top', zorder=20) # 原点ラベル ax.text(*0.5*(1.0-theta)*a, s='$(1 - \\theta) a$', size=15, ha='left', va='bottom', zorder=20) # ベクトル(1-θ)aラベル ax.text(*(1.0-theta)*a+0.5*theta*b, s='$\\theta b$', size=15, ha='right', va='bottom', zorder=20) # ベクトルθbラベル ax.text(*0.5*((1.0-theta)*a+theta*b), s='c', size=15, ha='center', va='top', zorder=20) # ベクトルcラベル ax.quiver([0, a[0], b[0]], [0, a[1], b[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, a[2]-z_min, b[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))+'), ' + 'b=('+', '.join(map(str, b))+'), ' + '$\\theta$='+str(theta), loc='left') fig.suptitle('$c = (1 - \\theta) a + \\theta b$', fontsize=20) ax.legend() ax.set_aspect('equal') plt.show()
アフィン結合したベクトルをとします。
係数の値を変化させたアニメーションを作成します。
・作図コード(クリックで展開)
# フレーム数を設定 frame_num = 51 # ベクトルを指定 a = np.array([-3.0, 1.0, 2.0]) b = np.array([2.0, 3.0, 4.0]) # 係数として利用する値を指定 theta_vals = np.linspace(start=-2.0, stop=3.0, num=frame_num) # 作図用の値を設定 x_min = np.floor(np.min([0.0, a[0], b[0], *(1.0-theta_vals)*a[0], *(1.0-theta_vals)*a[0]+theta_vals*b[0]])) - 1 x_max = np.ceil(np.max([0.0, a[0], b[0], *(1.0-theta_vals)*a[0], *(1.0-theta_vals)*a[0]+theta_vals*b[0]])) + 1 y_min = np.floor(np.min([0.0, a[1], b[1], *(1.0-theta_vals)*a[1], *(1.0-theta_vals)*a[1]+theta_vals*b[1]])) - 1 y_max = np.ceil(np.max([0.0, a[1], b[1], *(1.0-theta_vals)*a[1], *(1.0-theta_vals)*a[1]+theta_vals*b[1]])) + 1 z_min = np.floor(np.min([0.0, a[2], b[2], *(1.0-theta_vals)*a[2], *(1.0-theta_vals)*a[2]+theta_vals*b[2]])) - 1 z_max = np.ceil(np.max([0.0, a[2], b[2], *(1.0-theta_vals)*a[2], *(1.0-theta_vals)*a[2]+theta_vals*b[2]])) + 1 # 点a,bを通る直線を計算 d = b - a x_line = np.linspace(start=x_min, stop=x_max, num=101) y_line = (x_line - a[0]) * d[1] / d[0] + a[1] z_line = (x_line - a[0]) * d[2] / d[0] + a[2] # 作図用のオブジェクトを初期化 fig, ax = plt.subplots(subplot_kw={'projection': '3d'}, figsize=(7, 7), facecolor='white') fig.suptitle('$c = (1 - \\theta) a + \\theta b$', fontsize=20) # 作図処理を関数として定義 def update(i): # 前フレームのグラフを初期化 plt.cla() # i番目の係数を作成 theta = theta_vals[i] # 3Dベクトルの線形結合を作図 ax.scatter(0, 0, c='orange', s=50, zorder=0) # 原点 ax.scatter(*a, c='red', s=50, label='a') # 点a ax.scatter(*b, c='blue', s=50, label='b') # 点b ax.scatter(*(1.0-theta)*a+theta*b, c='purple', s=50, label='c') # 点c ax.plot(x_line, y_line, z_line) # 点a,bを通る直線 ax.quiver(0, 0, 0, *(1.0-theta)*a, arrow_length_ratio=0.1, color='red', zorder=50) # ベクトル(1-θ)a ax.quiver(*(1.0-theta)*a, *theta*b, arrow_length_ratio=0.1, color='blue', zorder=50) # ベクトルθb ax.quiver(0, 0, 0, *(1.0-theta)*a+theta*b, arrow_length_ratio=0.1, color='purple', zorder=50) # ベクトル ax.text(*0.5*(1.0-theta)*a, s='$(1 - \\theta) a$', size=10, ha='center', va='center', zorder=20) # ベクトル(1-θ)aラベル ax.text(*(1.0-theta)*a+0.5*theta*b, s='$\\theta b$', size=10, ha='left', va='top', zorder=20) # ベクトルθbラベル ax.text(*0.5*((1.0-theta)*a+theta*b), s='c', size=10, ha='right', va='top', zorder=20) # ベクトルcラベル ax.quiver([0.0, (1.0-theta)*a[0], (1.0-theta)*a[0]+theta*b[0]], [0.0, (1.0-theta)*a[1], (1.0-theta)*a[1]+theta*b[1]], [z_min, z_min, z_min], [0, 0, 0], [0, 0, 0], [-z_min, (1.0-theta)*a[2]-z_min, (1.0-theta)*a[2]+theta*b[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))+'), ' + 'b=('+', '.join(map(str, b))+'), ' + '$\\theta$='+str(theta.round(2)), loc='left') ax.set_aspect('equal') ax.legend() # gif画像を作成 ani = FuncAnimation(fig=fig, func=update, frames=frame_num, interval=100) # gif画像を保存 ani.save('affinecomb_3d.gif')
この記事では、アフィン結合を可視化しました。次の記事では、内積の計算を確認します。
参考書籍
- Stephen Boyd・Lieven Vandenberghe(著),玉木 徹(訳)『スタンフォード ベクトル・行列からはじめる最適化数学』講談社サイエンティク,2021年.
おわりに
3次元空間上の2点を通る直線を引くのに一苦労しました。調べても謎の等式が出てくるばかりで、でそれは何なんだ?となってました。ダメ元でyとxの式とzとxの式に整理してみたら上手く直線を描けて、だったらそう言って!となりました。変形後の式を見たら2次元のときの傾きと切片の計算式と同じ形になってますね、あの等式を見れば自明なんでしょうか。
そんなこんなで、アフィン結合の結果が直線上を通ることを可視化できました。見ていて気持ちいアニメになって満足です。でもなぜ直線になるのかは分かってません。
【次の内容】