vbaで数値計算 08 行列

27
2017-01 更新 熊本高専 森下功啓 VBA数値計算08

Upload: katsuhiro-morishita

Post on 10-Feb-2017

78 views

Category:

Education


2 download

TRANSCRIPT

Page 1: VBAで数値計算 08 行列

2017-01更新 熊本高専森下功啓

VBAで数値計算08

Page 2: VBAで数値計算 08 行列

本資料の目次

行列の計算練習問題その他

2

計算を行列として扱うと様々な計算が素早く行うことができ、且つこれまでの人類の知見をふんだんに実装したライブラリを使うことができるというメリットがあります。GPUを使って演算できるのもメリットです(CPUの10倍速も容易い)。

Page 3: VBAで数値計算 08 行列

行列計算の利用先

行列の応用分野は幅広い。画像処理、回路設計、回路シミュレータ、ロボットアーム制御、制御工学、機械学習、計画法、構造計算、流体力学、熱解析、応力解析、etc.

3

Page 4: VBAで数値計算 08 行列

本資料のカバー範囲

行列には様々な計算がありますが、本資料ではよく使われる基本演算に限定して取り扱います。VBAは行列を扱うための便利なオブジェクトや演算子が標準では用意されていないので、本スライドでは演算の中身を書き下しています。他のプログラミング言語で行列計算を行う際には「ああ、中ではこうやってんだろうな」と想像してみてください。また、VBAには複素型が用意されていません。行列演算ではしばしば複素型の計算が必要になりますが、VBAの複素数への対応も省略します。

4

Page 5: VBAで数値計算 08 行列

行列の計算5

Page 6: VBAで数値計算 08 行列

行列とは

行列とは、式(1)に示すような数値の列です。m行n列の行列のことをm×n行列と呼びます。表記方法は式(2)に示すように複数存在します。本スライドでは、行列は𝐀𝐀の様に大文字の太字で表します。行列に格納された数値の特性により、零行列や単位行列や対角行列や正方行列や上三角行列や直交行列やユニタリ行列やエルミート行列などの固有名称が多数あります。

6

𝐀𝐀 = 𝐴𝐴 = A =𝑎𝑎11 ⋯ 𝑎𝑎1𝑛𝑛⋮ ⋱ ⋮

𝑎𝑎𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛(2)

𝑎𝑎11𝑎𝑎21𝑎𝑎31⋮

𝑎𝑎𝑚𝑚1

𝑎𝑎12𝑎𝑎22𝑎𝑎32⋮

𝑎𝑎𝑚𝑚2

𝑎𝑎1𝑛𝑛𝑎𝑎2𝑛𝑛𝑎𝑎3𝑛𝑛⋮

𝑎𝑎𝑚𝑚𝑛𝑛

(1)𝑎𝑎𝑖𝑖𝑖𝑖

行番号 列番号

添字の見方

Page 7: VBAで数値計算 08 行列

行列のプログラムにおける表現

プログラムにおいて、行列を表す型が存在しない場合は2次元配列もしくはジャグ配列を用いて行列の計算を行う。以下にVBAの宣言方法の例を示す。

7

row1 = Array(11, 12, 13) ' 行ベクトルのつもりrow2 = Array(21, 22, 23)row3 = Array(31, 32, 33)matrix_data = Array(row1, row2, row3) ‘ 要素追加は面倒

@VBA*VBAでは2次元配列の他に普通のジャグ配列とArray型によるジャグ配列を使う方法がある。

Page 8: VBAで数値計算 08 行列

要素へのアクセス方法𝑎𝑎𝑖𝑖𝑖𝑖へのアクセス方法を下記に示す。アクセスに使う添字が数式上の添字よりも1だけ少ないことに注意して欲しい。

8

row1 = Array(11, 12) ' 行ベクトルのつもりrow2 = Array(21, 22)matrix_data = Array(row1, row2) date11 = matrix_data(0)(0) ‘ 11が代入される

@VBA

*VBAのプログラムを読む際には、hoge(x)が関数へのアクセスなのか、配列へのアクセスなのか、注意する必要がある。

**VBAでは2次元配列とジャグ配列とでアクセスのための記述方法が異なる。

Page 9: VBAで数値計算 08 行列

行列の基本演算と基本関数

基本関数行列の作成転置単位行列作成

基本関数足し算・引き算行列同士の積ベクトルと行列の積

9

Page 10: VBAで数値計算 08 行列

VBAにおける任意サイズの行列作成任意サイズの行列を作成する関数例を以下に示します。なお、この関数が返す変数に格納されている値はEmpty値です。

10

Function create_matrix(row_size, col_size)' 任意サイズの行列を作成するDim ans, row As Variant

ans = Array()ReDim ans(row_size - 1)For i = 0 To row_size - 1

row = Array() ' 新しいオブジェクトのインスタンスが代入されるReDim row(col_size - 1)ans(i) = row

Next i

create_matrix = ansEnd Function

@VBA

VBAにおいて、変数に格納されている数値を使ってArrayの要素数を変更するには、Dimを使ったVariant型の変数宣言と、Array()の代入†とReDimを使った再宣言が必要となる。

†正確にはArray型のインスタンスの代入である。

Page 11: VBAで数値計算 08 行列

行列の転置

転置とは、式(3)の様に行列の行と列をひっくり返す操作である。ここで、転置を行列の右上のTで表している。転置表記の流儀としては 𝑡𝑡𝐀𝐀も在るが、本スライドではTを右上につける。

11

𝑎𝑎11 ⋯ 𝑎𝑎1𝑛𝑛⋮ ⋱ ⋮

𝑎𝑎𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛

T

=𝑎𝑎11 ⋯ 𝑎𝑎𝑚𝑚1⋮ ⋱ ⋮𝑎𝑎1𝑛𝑛 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛

(3)

Page 12: VBAで数値計算 08 行列

行列の転置の実装例

行列を転置させる関数の実装例を以下に示します。

12

Function matrix_t(m)' 行列の転置ans = create_matrix(UBound(m(0)) + 1, UBound(m) + 1)For i = 0 To UBound(ans)

For j = 0 To UBound(ans(0))ans(i)(j) = m(j)(i)

Next jNext imatrix_t = ans

End Function

@VBA

iとjが左辺と右辺で入れ替わっている

Page 13: VBAで数値計算 08 行列

単位行列

対角成分が1でそれ以外が0の成分を持つ行列を単位行列といい、 𝐈𝐈や𝐄𝐄で表す。式(4)に3次の単位行列を示す。単位行列は式(5)に示すように、他の行列に掛けても影響しないという特徴がある。

13

𝐈𝐈 = 𝐄𝐄 =1 0 00 1 00 0 1

𝐈𝐈𝐀𝐀 = 𝐀𝐀

(4)

(5)

Page 14: VBAで数値計算 08 行列

単位行列作成の実装例

単位行列を作成する関数の実装例を以下に示します。

14

Function create_identity_matrix(size)' 単位行列を作成するans = create_matrix(size, size)

For i = 0 To size - 1For j = 0 To size - 1

If i = j Thenans(i)(j) = 1

Elseans(i)(j) = 0

End IfNext j

Next icreate_identity_matrix = ans

End Function@VBA

Page 15: VBAで数値計算 08 行列

行列の足し算・引き算

要素数やshape(行数や列数などの形状を一般化したしたもの)が一致している場合、行列の足し算または引き算を定義できる。以下に行列の足し算の計算を示す。要素毎に計算されることに注目して欲しい。

15

𝐀𝐀 + 𝐁𝐁 =𝑎𝑎11 ⋯ 𝑎𝑎1𝑛𝑛⋮ ⋱ ⋮

𝑎𝑎𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛

+𝑏𝑏11 ⋯ 𝑏𝑏1𝑛𝑛⋮ ⋱ ⋮

𝑏𝑏𝑚𝑚1 ⋯ 𝑏𝑏𝑚𝑚𝑛𝑛

=𝑎𝑎11 + 𝑏𝑏11 ⋯ 𝑎𝑎1𝑛𝑛 + 𝑏𝑏1𝑛𝑛

⋮ ⋱ ⋮𝑎𝑎𝑚𝑚1 + 𝑏𝑏𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛 + 𝑏𝑏𝑚𝑚𝑛𝑛

Page 16: VBAで数値計算 08 行列

行列の足し算の実装例

16

行列の足し算の実装例を以下に示します。実用上は、引数のm1とm2はサイズが等しいことを確認したほうが良いでしょう。

Function matrix_plus(m1, m2)' 行列同士の足し算ans = m1 ' 同じ大きさのオブジェクトを生成For i = 0 To UBound(m1)

For j = 0 To UBound(m1(0))ans(i)(j) = m1(i)(j) + m2(i)(j)

Next jNext imatrix_plus = ans

End Function

@VBA

Page 17: VBAで数値計算 08 行列

Function matrix_minus(m1, m2)' 行列同士の足し算ans = m1 ' 同じ大きさのオブジェクトを生成For i = 0 To UBound(m1)

For j = 0 To UBound(m1(0))ans(i)(j) = m1(i)(j) - m2(i)(j)

Next jNext imatrix_minus = ans

End Function

行列の引き算の実装例

行列の引き算の実装例を以下に示します。この他にも、行列に-1を掛けて、さらに足し算関数を呼び出すという方法も有ります。

17@VBA

ここだけ異なる

Page 18: VBAで数値計算 08 行列

行列の積

m×n行列𝐀𝐀とn×k行列𝐁𝐁は積を定義できます。行列の積は、左の行列の列数と右の行列の行数が一致していなければ計算できません。また、 𝐀𝐀と𝐁𝐁がサイズの等しい正方行列であれば𝐁𝐁𝐀𝐀も定義できますが、一般的には𝐀𝐀𝐁𝐁 ≠ 𝐁𝐁𝐀𝐀となります。 𝐀𝐀𝐁𝐁𝐂𝐂など、行列の積が連続する場合は左から計算します。

18

𝐀𝐀𝐁𝐁 = 𝐀𝐀 � 𝐁𝐁 =𝑎𝑎11 ⋯ 𝑎𝑎1𝑛𝑛⋮ ⋱ ⋮

𝑎𝑎𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛�𝑏𝑏11 ⋯ 𝑏𝑏1𝑘𝑘⋮ ⋱ ⋮𝑏𝑏𝑛𝑛1 ⋯ 𝑏𝑏𝑛𝑛𝑘𝑘

=

�𝑖𝑖=1

𝑛𝑛

𝑎𝑎1𝑖𝑖𝑏𝑏𝑖𝑖1 ⋯ �𝑖𝑖=1

𝑛𝑛

𝑎𝑎1𝑖𝑖𝑏𝑏𝑖𝑖𝑘𝑘

⋮ ⋱ ⋮

�𝑖𝑖=1

𝑛𝑛

𝑎𝑎𝑚𝑚𝑖𝑖𝑏𝑏𝑖𝑖1 ⋯ �𝑖𝑖=1

𝑛𝑛

𝑎𝑎𝑚𝑚𝑖𝑖𝑏𝑏𝑖𝑖𝑘𝑘行列の積の演算子

dot, ドット𝐀𝐀の行ベクトルと𝐁𝐁の列ベク

トルの内積が並んでいる

Page 19: VBAで数値計算 08 行列

行列の積の実装例

行列の積の計算を行う関数の実装例を示します。

19

Function matrix_cross(m1, m2)' 行列同士の掛け算ans = create_matrix(UBound(m1) + 1, UBound(m2(0)) + 1)For i = 0 To UBound(ans)

For j = 0 To UBound(ans(0))sum_ = 0For k = 0 To UBound(m1(0))

sum_ = sum_ + m1(i)(k) * m2(k)(j)Next kans(i)(j) = sum_

Next jNext imatrix_cross = ans

End Function

@VBA

Page 20: VBAで数値計算 08 行列

ベクトルと行列の積

上記のようなベクトルと行列の積を行うプログラムを考えます。1次元配列のベクトルをm行×1列の行列に変換できれば、これまでに実装した行列の積の関数が使えます。

アルゴリズム案1. まずベクトルをm行×1列の行列に変換2. 次に、行列の積を実行

20

𝑦𝑦1⋮𝑦𝑦𝑚𝑚

=𝑎𝑎11 ⋯ 𝑎𝑎1𝑛𝑛⋮ ⋱ ⋮

𝑎𝑎𝑚𝑚1 ⋯ 𝑎𝑎𝑚𝑚𝑛𝑛

𝑥𝑥1⋮𝑥𝑥𝑚𝑚

Page 21: VBAで数値計算 08 行列

ベクトルと行列の積の実装例右の計算を行う例を以下に示す。

21

Function vector2matrix(vect)' ベクトルを行列に変換する(列ベクトル扱いにする)matrix = Array(vect) ' このままでは行ベクトル扱いvector2matrix = matrix_t(matrix) ' これで列ベクトル扱い

End Function

Sub matrix_test()row1 = Array(11, 12, 13)row2 = Array(21, 22, 23)row3 = Array(31, 32, 33)temp_matrix1 = Array(row1, row2, row3)

vect = Array(1, 2, 3)result = matrix_cross(temp_matrix1, vector2matrix(vect))

End Sub

@VBA

11 12 1321 22 2331 32 33

123

Page 22: VBAで数値計算 08 行列

練習問題22

Page 23: VBAで数値計算 08 行列

問1 回転行列

2次元ベクトルを平面内で回転させる関数を作成せよ。ここで、引数はθ[rad](変数名はtheta)とする。また、反時計回りを正とする。ヒント:https://ja.wikipedia.org/wiki/%E5%9B%9E%E8%BB%A2%E8%A1%8C%E5%88%97#2.E6.AC.A1.E5.85.83.E3.81.AE.E5.9B.9E.E8.BB.A2.E8.A1.8C.E5.88.97

23

*ゲーム画面の描画では常にこの計算が行われている。

Page 24: VBAで数値計算 08 行列

問2 2次元配列の変換

VBAのマクロでベクトルや行列を宣言するとき、Array()を使うと楽なのは解説した。したがって、このスライドで示した行列宣言や関数で使われる行列データはArray(Array(), Array(), Array())の様にArray()の入れ子構造を取っている。ところで、VBAの関数をPythonから呼び出す際の引数の型は普通の2次元配列に限定されている。Dim a(2,3) as Doubleといった感じで宣言された配列が渡される。ここで、2次元配列と入れ子のArray()ではアクセス方法が異なるため、Array()の入れ子を想定した関数をPythonから直接呼び出せない。そこで、引数で渡された2次元配列を基にArray()の入れ子構造にデータ構造を変換する関数を作成せよ。

24

Page 25: VBAで数値計算 08 行列

問3 行列式

行列から行列式を求める関数を作成せよ。

ヒント:2×2の行列の行列式は公式がある。3次以上(一応、3次も公式はある)の行列式の場合は余因子を用いて解くが、余因子自体を求めるために行列式を解く必要がある。すなわち、n次の行列式を求めるには公式が使える2×2のサイズの行列式が出現するまで計算する必要がある。この手計算の手順そのままだと再帰構造が必要となり、まぁ大変だ。手っ取り早く、C言語で実装された下記のコードを書き換えてもいい。http://thira.plavox.info/blog/2008/06/_c.html

25

Page 26: VBAで数値計算 08 行列

その他26

Page 27: VBAで数値計算 08 行列

参考文献SAK Streets - VB 開発言語資料 http://sak.cool.coocan.jp/w_sak3/doc/sysbrd/sak3vb.htm 基本的にVB6.0の解説だが、VBAにほぼそのまま適用できる。かなり詳しい。

[1] Excel で行列計算, http://www2.kaiyodai.ac.jp/~takenawa/app-analysis/Excel%E3%81%A7%E8%A1%8C%E5%88%97%E8%A8%88%E7%AE%97.pdf[2] EXCEL_VBAで行列計算!, http://home.hiroshima-u.ac.jp/ete131/index.cgi?page=EXCEL_VBA%A4%C7%B9%D4%CE%F3%B7%D7%BB%BB%A1%AA[3] Wikipedia 行列, https://ja.wikipedia.org/wiki/%E8%A1%8C%E5%88%97#.E8.A1.8C.E5.88.97.E3.81.AE.E5.88.86.E8.A7.A3

27