ベクトルと行列、高校の数学でそんな言葉を聞いた気がする、20年ぐらい前の遠い記憶ですかね...どうもボクです。
人の記憶を呼び覚ます契機になりうる、最も強い情報、それは「におい」であると。「プルースト効果(プルースト現象)」として有名になっていますが、
失われた時を求めて 全13巻・全巻セット (失われた時を求めて)
⇧ 24歳ぐらいの頃、図書館で借りて読んだけども、内容ほとんど覚えてないや...マドレーヌも食べてないしな~、当時の記憶を呼び覚ますにおいって何じゃろうか...
そんなこんなで、今回は、「ベクトル、行列」なんかの話です、Javaで使ってみますかね。
ちなみに、
⇧ 上記サイト様にあるように、『SIMD(Single Instruction, Multiple Data)のベクトル演算をサポートするための「Vector API」の開発』ってどうなったんじゃろうか...
そんでは、レッツ~トライ。
行列って?
行列って、どんなものでしたっけ?
いきなり、パンチが飛んできそうですが...何はともあれ、「敵を知り己を知れば百戦殆うからず」ということで、改めて、行列とは?
⇧ 上記サイト様が分かりやすいです。今年も、他力本願寺~、どんだけ~!
んで、Wikipediaさんによりますと、
に対して、(a11
a21), (a12
a22) はその列ベクトル、(a11 a12), (a21 a22) はその行ベクトルである。
⇧ 「ベクトル」と密接な関係にあるそうな。
行列の「厳密な定義」の説明では、
行列は二重に添字づけられた族であり、きちんと言えば、添字の各対 (i, j) に成分 aij を割り当てる二変数写像
である。例えば添字の対 (1, 2) には写像の値として a12 が割り当てられる。即ち、値 aij は行列の i-行 j-列成分であり、m および n はそれぞれ行および列の数を意味する。写像としての行列の定義と行列が表す線型写像とを混同してはならない。
K に成分を持つ m × n 行列の全体は、したがって配置集合
であり、省略形として Km×n(あるいはやや稀だが mKn)や M(m×n; K) などと書くことの一つの根拠になる。
行の数と列の数が一致するような行列は正方行列と呼ばれる。
となっており、
と...いかん、頭がクラクラしてきた(涙)。
まぁ、よく分からんのだけども、「行列」と「ベクトル」は密な関係にあると。
ベクトルって?
そんじゃ、ベクトルって何よ?
⇧ 上記サイト様が詳しいです。
Wikipediaさんによりますと、
となっており、
ベクトル自体の説明があんまり無い感じ?
「定義」の説明を見てみると、
とあり、2種類の演算は、
という説明になってますが...
複素数とかも関わっているらしい。
「体」は自由に決められる?らしい。
「体」はというと、「四則演算」できるものであれば良いらしい。
ベクトルは、かなりいろいろなものとコラボレーションしてるらしい。その1つが、「行列」ですかね。
ベクトルと行列って?
例のごとく、Wikipediaさんによりますと、
二つのベクトル空間の間の関係性は線型写像あるいは線型変換によって表すことができる。これは、ベクトル空間の構造を反映した写像、即ち任意の x, y ∈ V と任意の a ∈ F に対して
- ƒ(x + y) = ƒ(x) + ƒ(y), ƒ(a · x) = a · ƒ(x)
を満たすという意味で和とスカラー倍を保つものである。
となっており、「線型写像」はというと、
数学の特に線型代数学における線型変換(せんけいへんかん、英: linear transformation、一次変換)あるいは線型写像(せんけいしゃぞう、英: linear mapping)は、ベクトルの加法とスカラー乗法を保つ特別の写像である。
⇧ ベクトルの定義を満たす、「ベクトルの加法」「スカラー乗法」 を持ったものが「写像」であると。
写像(しゃぞう、mapping, map)とは、二つの集合が与えられたときに、一方の集合の各元に対し、他方の集合のただひとつの元を指定して結びつける対応のことである。函数(関数)、変換、作用素、射などが写像の同義語として用いられることもある。
そんでは、行列との関係は?
行列 (matrix ) は線型写像の情報を記述するのに有効な概念である。行列は、図のように、スカラーの矩形配列として書かれる。任意の m × n 行列 A は Fn から Fm への線型写像を
として生じる(∑ は総和を表す)。
⇧ 「線型写像」を表せるのだと。 つまり、ベクトルを表せるのだと言っても過言ではないのではなかろうか、教えて偉い人。
これはまた行列 A と座標ベクトル x との行列の積を用いて
- x ↦ Ax
と書くこともできる。さらに言えば、V と W の基底を選ぶことで、任意の線型写像 ƒ : V → W は同様の方法で行列によって一意的に表される。
う、う~ん...よく分からん、のだけども、「行列の積」の説明では、
これは通例、行列の積(ぎょうれつのせき、英: matrix product)と呼ばれるもので、A が n × m 行列で、B が m × p 行列ならば、それらの行列の積 AB が n × p 行列として与えられ、その成分は A の各行の m 個の成分がそれぞれ順番に B の各列の m 個の成分と掛け合わされる形で与えられる。
となっていますかね。
行列のサイズが大きくなれば、二つあるいはそれ以上の行列の積の計算を定義に従って行うには、非常に膨大な時間が掛かるようになってしまうため、効果的に行列の積を計算できるアルゴリズムが考えられてきた。
機械学習なんかをやっていこうとする場合、
⇧ 「行列」「ベクトル」なんかの知識が無いと厳しいらしい...
絶望の畳み込みが...あ...畳み込みニューラルネットワーク(Convolutional Neural Network: CNNまたはConvNet)も必要になってくるらしい......
すみません、脱線しました...
Java で行列
さぁ、気分が極限まで落ち込んだところで、Javaで行列してみますか~
問題はこんな感じ。
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_6_D&lang=jp
ソースコードはこんな感じにしてみました。
package aizu; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class TestMatrix { public static void main(String[] args) throws IOException { // 標準入力用 BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); // 標準入力の値を、半角スペースで分割 String[] inputRowAndCol = (input.readLine()).split("\\s"); int row = Integer.parseInt(inputRowAndCol[0]); // 行 int col = Integer.parseInt(inputRowAndCol[1]); // 列 // 行列A int[][] matrixA = new int[row][col]; String[] matrixData = null; // 実際の行列のデータ用 // 行の数だけ繰り返し for (int i = 0; i < row; i++) { // 標準入力の値を、半角スペースで分割 matrixData = (input.readLine()).split("\\s"); // 列の数だけ繰り返し for (int j = 0; j < col; j++) { // 行列Aに、標準入力の値を設定していく matrixA[i][j] = Integer.parseInt(matrixData[j]); } } // ベクトルb int[] vectorB = new int[col]; for (int k = 0; k < col; k++) { vectorB[k] = Integer.parseInt(input.readLine()); } // 行列の積 // 行の数だけ繰り返し for (int l = 0; l < row; l++) { int result = 0; // リセット(次の行の計算のため初期化) // 列の数だけ繰り返し for (int m = 0; m < col; m++) { // 計算 result += (matrixA[l][m] * vectorB[m]); } // 表示 System.out.println(result); } } }
んで、実行。
一応、OK出ました。
提出したコード。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws IOException { // TODO 自動生成されたメソッド・スタブ BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); String[] inputRowAndCol = (input.readLine()).split("\\s"); int row = Integer.parseInt(inputRowAndCol[0]); int col = Integer.parseInt(inputRowAndCol[1]); // 行列A int[][] matrixA = new int[row][col]; String[] matrixData = null; for (int i = 0; i < row; i++) { matrixData = (input.readLine()).split("\\s"); for (int j = 0; j < col; j++) { matrixA[i][j] = Integer.parseInt(matrixData[j]); } } // ベクトルb int[] vectorB = new int[col]; for (int k = 0; k < col; k++) { vectorB[k] = Integer.parseInt(input.readLine()); } // 行列の積 for (int l = 0; l < row; l++) { int result = 0; for (int m = 0; m < col; m++) { result += (matrixA[l][m] * vectorB[m]); } System.out.println(result); } } }
先は長いですかね......
ちょいと、「行列」の計算とかも勉強していかねばですかね...そして、思うことは、普通の開発で、標準入力とか使わないよね...
今回はこのへんで。