『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

鏡映変換(対称移動)

【Pythonで学ぶ線形代数学講座(15)】鏡映変換(対称移動)

対称移動

前回記事で、あらゆる種類の線形変換は行列形式で表現できることを解説しました。中でも鏡映変換(反転・折り返し)は基本的な線形変換です。

軸に関する鏡映変換

任意の点を $x$ 軸に関して折り返す表現行列は
 \[A=\begin{bmatrix}1&0\\0&-1\\\end{bmatrix}\tag{1}\]
で与えられます。実際、行列 $A$ によって、ベクトル $\boldsymbol{r}=\begin{bmatrix}x\\y\end{bmatrix}$ は
 \[\begin{bmatrix}1&0\\0&-1\\\end{bmatrix}
\begin{bmatrix}x\\y\end{bmatrix}=\begin{bmatrix}x\\-y\end{bmatrix}\tag{2}\]
に変換されます。同様に、$y$ 軸に関する鏡映変換は
 \[B=\begin{bmatrix}-1&0\\0&1\\\end{bmatrix}\tag{3}\]
で与えられます。鏡映変換を $2$ 回ほどこすと元に戻るので、鏡映変換行列 $Q$ について、常に $Q^2=I$ が成り立ちます。たとえば、(1) の $A$ を $2$ 乗してみると、
 \[A^2=\begin{bmatrix}1&0\\0&-1\\\end{bmatrix}\begin{bmatrix}1&0\\0&-1\\\end{bmatrix}=\begin{bmatrix}1&0\\0&1\\\end{bmatrix}\]
となっています。同様に $B^2=I$ も成り立ちます。
 
Python を使って、行列 $A$ による $P(3,3)$ の点の移り先を確認しておきましょう。点を表示するために、当サイトの コードライブラリ に収められている coordinate() と pointer() を予め実装しておいてください。

# python_reflection

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# ここにcoordinate()を実装
# ここにpointer()を実装

# FigureとAxes
fig = plt.figure(figsize = (5, 5))
ax = fig.add_subplot(111)

# FigureとAxes
fig = plt.figure(figsize = (6, 6))
ax = fig.add_subplot(111)

# 座標を準備
coordinate(ax, [-6, 6], [-6, 6])

# 鏡映行列aを定義
a = np.array([[1,  0],
              [0, -1]])

# 変換前の点
p0 = np.array([3, 3])

# 変換後の点
p1 = np.dot(a, p0)

# 変換前の点p0をプロット
pointer(ax, p0[0], p0[1], "P0",
        pcolor = "red", textsize = 15)

# 変換前の後の点p1をプロット
pointer(ax, p1[0], p1[1], "P1",
        pcolor = "blue", textsize = 15)

plt.show()

x軸に関する対称移動 (symmetric movement)
線形変換は点の集合をまとめて変換することもできます。
たとえば、直線 $y=2x$ 上の点を $\begin{bmatrix}t\\2t\end{bmatrix}$ で表すと、行列 $A$ によって
 \[\begin{bmatrix}1&0\\0&-1\\\end{bmatrix}\begin{bmatrix}t\\2t\end{bmatrix}=\begin{bmatrix}t\\-2t\end{bmatrix}\]
に変換されます。これは直線 $y=2x$ 上の点が直線 $y=-2x$ 上に写ることを意味します。これも Python で確認してみましょう。
 
numpy.linspace() で x のデータを作成し、x と 2*x を numpy.vstack で縦に連結すると、直線 $y=2x$ 上の各点を表す 2 次元ベクトルを横に並べた
 \[\begin{bmatrix}-6.0&-5.8125&-5.625&-5.4375& … \\-12.0&-11.625&-11.25&-10.825& …\end{bmatrix}\]
という行列が生成されます。これに行列を作用させると、すべての点をまとめて変換できます。

# In[2]

# FigureとAxes
fig = plt.figure(figsize = (6, 6))
ax = fig.add_subplot(111)

# 座標を設定
coordinate(ax, [-6, 6], [-6, 6])

# 鏡映行列aを定義
a = np.array([[1,  0],
              [0, -1]])

# x座標データ
x = np.linspace(-6, 6, 65)

# xと2xを縦に結合して直線データを作成
line_0 = np.vstack((x, 2*x))

# 行列aで直線を変換
line_1 = np.dot(a, line_0)

# 変換前の直線と変換後の直線をプロット
ax.plot(line_0[0], line_0[1],
        color = "red", label = "y = 2x")

ax.plot(line_1[0], line_1[1],
        color = "blue", label = "y = -2x")

# 凡例を表示
ax.legend()

plt.show()

x軸に関する直線の対称移動 (symmetric movement)

直線に関する鏡映変換

任意の傾きをもつ直線 $y=mx$ について折り返しは
 \[C=\frac{1}{1+m^2}\begin{bmatrix}1-m^2&2m\\2m&m^2-1\\\end{bmatrix}\tag{4}\]
によって表されます。この変換を実行する reflection()関数を定義して、点 $P_0(3, 3)$ の直線 $y=x/2$ に関する鏡映変換 (対称移動) を確認してみます。

# In[3]

def reflection(x, m):
    a = np.array([[1 - m**2, 2*m],
                  [2*m, m**2 - 1]])
    a = a / (1 + m**2)
    ax = np.dot(a, x)
    return ax

# FigureとAxes
fig = plt.figure(figsize = (6, 6))
ax = fig.add_subplot(111)

# 座標を準備
coordinate(ax, [-6, 6], [-6, 6])

# 鏡映行列aを定義
a = np.array([[1,  0],
              [0, -1]])

# 変換前の点
p0 = np.array([3, 3])

# p0をy=0.5xに関して折り返す
p1 = reflection(p0, 0.5)

# y=0.5xをプロット
x = np.linspace(-6, 6, 65)
ax.plot(x, 0.5*x, color = "gray")

# 変換前の点p0をプロット
pointer(ax, p0[0], p0[1], "P0",
        pcolor = "red", textsize = 15)

# 変換前の後の点p1をプロット
pointer(ax, p1[0], p1[1], "P1",
        pcolor = "blue", textsize = 15)

直線y=mxに関する鏡映変換 (折り返し)

 

コメント