からっぽのしょこ

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

3.4:なす角の計算式【『スタンフォード線形代数入門』のノート】

はじめに

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

 この記事は3.4節「角度」の内容です。
 なす角の定義を確認します。

【前の内容】

www.anarchive-beta.com

【他の内容】

www.anarchive-beta.com

【今回の内容】

なす角の定義

 まずは、2つのベクトルのなす角の定義を数式で確認します。
 内積については「1.4:内積の性質と計算例【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」、ユークリッドノルムについては「3.1-2:ユークリッドノルム・ユークリッド距離の性質と計算例【『スタンフォード線形代数入門』のノート】 - からっぽのしょこ」を参照してください。

 同じサイズ(次元数)のベクトル \mathbf{a}, \mathbf{b}のなす角は、次の式で定義されます。

 \displaystyle
\theta
    = \arccos \left(
          \frac{
              \mathbf{a}^{\top} \mathbf{b}
          }{
              \|\mathbf{a}\| \|\mathbf{b}\|
          }
      \right)

 ただし、 \mathbf{a}または \mathbf{b}が0ベクトルだと0除算になるため定義できません。

  \arccos xは逆コサイン関数(コサイン関数 \cos xの逆関数)、 \|\mathbf{x}\|はユークリッドノルムです。
  \thetaは、弧度法における角度であり、ラジアンと呼びます。度数法における角度を \theta^{\circ}で表すと、 \theta \theta^{\circ} \theta = \theta^{\circ} \frac{2 \pi}{360} \theta^{\circ} = \theta \frac{360}{2 \pi}で変換できます。よって、 \theta^{\circ} = 0^{\circ}のとき \theta = 0であり、 \theta^{\circ} = 180^{\circ}のとき \theta = \piです。

 逆関数の性質より x = \cos(\arccos x)なので、定義式を次の式に変形できます。

 \displaystyle
\cos \theta
    = \frac{
          \mathbf{a}^{\top} \mathbf{b}
      }{
          \|\mathbf{a}\| \|\mathbf{b}\|
      }

 さらに、両辺にノルムの積を掛けると、「内積」と「ノルムの積」の関係が得られます。

 \displaystyle
\mathbf{a}^{\top} \mathbf{b}
    = \|\mathbf{a}\| \|\mathbf{b}\|
      \cos \theta

 例えば、 \theta = 0のとき \cos \theta = 1なので \mathbf{a}^{\top} \mathbf{b} = \|\mathbf{a}\| \|\mathbf{b}\|になります。

余弦関数と逆余弦関数

 次は、余弦関数(コサイン関数・cosine function)と、余弦関数の逆関数である逆余弦関数(逆コサイン関数・inverse cosine function)をグラフで確認します。

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

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


 コサイン関数を計算します。

# 余弦関数の変数(ラジアン)を作成
t_vals = np.linspace(start=-2.0*np.pi, stop=2.0*np.pi, num=500)
print(t_vals[:10].round(2))

# 余弦関数を計算
cos_vals = np.cos(t_vals)
print(cos_vals[:10].round(2))
[-6.28 -6.26 -6.23 -6.21 -6.18 -6.16 -6.13 -6.11 -6.08 -6.06]
[1.   1.   1.   1.   0.99 0.99 0.99 0.98 0.98 0.97]

 コサイン関数の入力変数(ラジアン)を作成して、コサイン関数を計算します。コサイン関数 \cos xnp.cos()で計算できます。
 円周率 \pinp.piで扱えます。
 

 コサイン関数のグラフを作成します。

# 軸目盛ラベル用の値を設定
denom = 3.0
n_ticks = np.arange(
    start=np.floor(t_vals.min() / np.pi * denom), 
    stop=np.ceil(t_vals.max() / np.pi * denom) + 1, 
    step=1)
#t_labels = ['$\\frac{' + str(int(n)) + '}{' + str(int(denom)) + '} \pi$' for n in n_ticks]
t_labels = ['$' + ('-' if n < 0.0 else '') + '\\frac{' + str(int(abs(n))) + '}{' + str(int(denom)) + '} \pi$' for n in n_ticks]

# 余弦関数を作図
fig, ax = plt.subplots(figsize=(8, 6), facecolor='white')
ax.plot(t_vals, cos_vals, label='cos t')
ax.set_xticks(ticks=n_ticks*np.pi/denom, labels=t_labels)
ax.set_xlim(left=t_vals.min(), right=t_vals.max())
ax.grid()
ax.set_xlabel('t')
ax.set_ylabel('cos t')
fig.suptitle('cosine function', fontsize=20)
ax.legend()
plt.show()

コサイン関数のグラフ

 コサイン関数は -1 \leq \cos t \leq 1の値をとります。また、ラジアンが 2 \pi(角度だと 360^{\circ})のサイズで周期的に推移します。

 続いて、逆コサイン関数を計算します。

# 逆余弦関数の変数(余弦関数の出力)を作成
#u_vals = np.linspace(start=-1.5, stop=1.5, num=500)
u_vals = np.sort(np.unique(cos_vals))
print(u_vals[:10].round(2))

# 逆余弦関数を計算
arccos_vals = np.arccos(u_vals)
print(arccos_vals[:10].round(2))
[-1. -1. -1. -1. -1. -1. -1. -1. -1. -1.]
[3.14 3.12 3.11 3.1  3.08 3.08 3.07 3.06 3.06 3.05]

 逆コサイン関数の入力変数を作成して、逆コサイン関数を計算します。逆コサイン関数 \arccos x = \cos^{-1} xnp.arccos()で計算できます。

 逆コサイン関数のグラフを作成します。

# 軸目盛ラベル用の値を設定
denom = 3.0
n_ticks = np.arange(
    start=0.0, 
    stop=np.ceil(1.0 * denom) + 1, 
    step=1)
t_labels = ['$\\frac{'+str(int(n)) + '}{' + str(int(denom)) + '} \pi$' for n in n_ticks]

# 逆余弦関数を作図
fig, ax = plt.subplots(figsize=(8, 6), facecolor='white')
ax.plot(u_vals, arccos_vals, label='arccos u')
ax.set_yticks(ticks=n_ticks*np.pi/denom, labels=t_labels)
ax.grid()
ax.set_xlabel('u')
ax.set_ylabel('arccos u')
fig.suptitle('inverse cosine function', fontsize=20)
ax.legend()
plt.show()

逆コサイン関数のグラフ

 「逆コサイン関数の入力」は「コサイン関数の出力」、「逆コサイン関数の出力」は「コサイン関数の入力」つまり「ラジアン」に対応します。
 よって、入力は -1 \leq u \leq 1の範囲に限られ、出力は 0 \leq \arccos u \leq \pi(角度だと 0^{\circ} \leq \arccos u \leq 180^{\circ})の範囲の値をとります。入力が範囲外の場合はnanになります。

 この記事では、なす角の定義式を確認しました。次の記事では、なす角を可視化します。

参考書籍

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

おわりに

 やっぱり内容的に少し薄いんですけど、ラジアンの話とかコサイン関数と逆コサイン関数がとる範囲の話とかを書いておく必要があったので、引用用に記事にしておきます。

【次の内容】

www.anarchive-beta.com