Java ベクトルと行列って言われてもね...、行列を試してみる

ベクトルと行列、高校の数学でそんな言葉を聞いた気がする、20年ぐらい前の遠い記憶ですかね...どうもボクです。

人の記憶を呼び覚ます契機になりうる、最も強い情報、それは「におい」であると。「プルースト効果プルースト現象)」として有名になっていますが、


失われた時を求めて 全13巻・全巻セット (失われた時を求めて)

⇧  24歳ぐらいの頃、図書館で借りて読んだけども、内容ほとんど覚えてないや...マドレーヌも食べてないしな~、当時の記憶を呼び覚ますにおいって何じゃろうか...

 

そんなこんなで、今回は、「ベクトル、行列」なんかの話です、Javaで使ってみますかね。

ちなみに、

tech.nikkeibp.co.jp

⇧  上記サイト様にあるように、『SIMD(Single Instruction, Multiple Data)のベクトル演算をサポートするための「Vector API」の開発』ってどうなったんじゃろうか...

 

そんでは、レッツ~トライ。

 

行列って?

行列って、どんなものでしたっけ?

いきなり、パンチが飛んできそうですが...何はともあれ、「敵を知り己を知れば百戦殆うからず」ということで、改めて、行列とは?

kateikyousi.doorblog.jp

⇧  上記サイト様が分かりやすいです。今年も、他力本願寺~、どんだけ~!

んで、Wikipediaさんによりますと、

行列の各々の行および列はそれぞれ行ベクトルおよび列ベクトルとして言及されることもある。例えば行列

に対して、(a11
a21
), (a12
a22
)
 はその列ベクトル、(a11a12), (a21a22) はその行ベクトルである。

行列 - Wikipedia

⇧  「ベクトル」と密接な関係にあるそうな。 

行列の「厳密な定義」の説明では、

行列は二重に添字づけられたであり、きちんと言えば、添字の各対 (ij) に成分 aij を割り当てる二変数写像

である。例えば添字の対 (1, 2) には写像の値として a12 が割り当てられる。即ち、値 aij は行列の i-行 j-列成分であり、m および n はそれぞれ行および列の数を意味する。写像としての行列の定義と行列が表す線型写像とを混同してはならない。

K に成分を持つ m × n 行列の全体は、したがって配置集合

であり、省略形として Km×n(あるいはやや稀だが mKn)や M(m×nK) などと書くことの一つの根拠になる。

行の数と列の数が一致するような行列は正方行列と呼ばれる。

行列 - Wikipedia

となっており、

ただ一つの列を持つ行列は列ベクトル、ただ一つの行を持つ行列は行ベクトルと呼ばれる。Kn のベクトルは、文脈によって行ベクトル空間 Kn または列ベクトル空間 Kn×1 の元を表すのにも用いられる。

行列 - Wikipedia

と...いかん、頭がクラクラしてきた(涙)。 

まぁ、よく分からんのだけども、「行列」と「ベクトル」は密な関係にあると。 

 

ベクトルって?

そんじゃ、ベクトルって何よ?

ベクトルと行列 ベクトル空間

tadaoyamaoka.hatenablog.com

⇧  上記サイト様が詳しいです。

 

Wikipediaさんによりますと、

数学、特に線型代数学におけるベクトル空間(ベクトルくうかん、vector space)、または、線型空間(せんけいくうかん、linear space)は、ベクトルと呼ばれる元からなる集まりの成す数学的構造である。

ベクトル空間 - Wikipedia

となっており、 

ベクトルにはが定義され、またスカラーと呼ばれる数による(「スケール変換」)を行える。スカラー実数とすることも多いが、複素数有理数あるいは一般のの元によるスカラー乗法を持つベクトル空間もある。ベクトルの和とスカラー倍の演算は、「ベクトル空間の公理」と呼ばれる特定の条件(定義)を満足するものでなければならない。

ベクトル空間 - Wikipedia

ベクトル自体の説明があんまり無い感じ?

「定義」の説明を見てみると、

 F 上のベクトル空間 V 」とは、後に述べるような、二種類の演算を備えた集合 V のことである。ベクトル空間 V のベクトル (vector ) と呼ばれる。体 F は係数体 (coefficient field, scalar field ) と呼ばれる。係数体 F の元はスカラー(scalar ) あるいは係数 (coefficient ) と呼ばれる。

ベクトル空間 - Wikipedia

とあり、2種類の演算は、

ベクトルの加法と呼ばれ、任意の二つのベクトル v と w とからそれらのと呼ばれる第三のベクトル v + w を割り当てるものである。

ベクトル空間 - Wikipedia

任意のスカラー a と任意のベクトル v とから別のベクトル av を割り当てるもので、最初の例でのこの乗法がベクトル v をスカラー a 倍に拡大縮小(スケーリング)するものになっていることから、この乗法は v の a によるスカラー乗法と呼ばれる。

ベクトル空間 - Wikipedia

という説明になってますが... 

複素数とかも関わっているらしい。

ベクトル空間は、係数体 F が実数体 R のとき 実ベクトル空間 (real vector space )、複素数体 C のとき複素ベクトル空間(complex vector space ) と呼ばれ、これら二つの場合が工学においてもっともよく用いられる。

ベクトル空間 - Wikipedia

「体」は自由に決められる?らしい。 

最も一般のベクトル空間の定義では、スカラーは任意に選んだ F の元とすることができる。これを F-ベクトル空間 (F-vector space ) あるいは F 上のベクトル空間 (vector space over F) という。

ベクトル空間 - Wikipedia

「体」はというと、「四則演算」できるものであれば良いらしい。

体というのは本質的に、四則演算が自由にできる数の集合である[文献によっては(例えば Brown 1991係数体を R か C に制限するものあるが、理論の大部分は変更なしに任意の体上で成り立つものである]。例えば有理数の全体 Q もまた体を成す。

ベクトル空間 - Wikipedia

 

ベクトルは、かなりいろいろなものとコラボレーションしてるらしい。その1つが、「行列」ですかね。

 

ベクトルと行列って?

例のごとく、Wikipediaさんによりますと、

二つのベクトル空間の間の関係性は線型写像あるいは線型変換によって表すことができる。これは、ベクトル空間の構造を反映した写像、即ち任意の xy ∈ V と任意の a ∈ F に対して

ƒ(x + y) = ƒ(x) + ƒ(y), ƒ(a · x) = a · ƒ(x)

を満たすという意味で和とスカラー倍を保つものである。

ベクトル空間 - Wikipedia

となっており、「線型写像」はというと、

数学の特に線型代数学における線型変換(せんけいへんかん、linear transformation一次変換)あるいは線型写像(せんけいしゃぞう、linear mapping)は、ベクトルの加法スカラー乗法を保つ特別の写像である。

線型写像 - Wikipedia

⇧  ベクトルの定義を満たす、「ベクトルの加法」「スカラー乗法」 を持ったものが「写像」であると。

写像(しゃぞう、mappingmap)とは、二つの集合が与えられたときに、一方の集合の各に対し、他方の集合のただひとつの元を指定して結びつける対応のことである。函数関数)、変換作用素などが写像の同義語として用いられることもある。

写像 - Wikipedia

 

そんでは、行列との関係は?

行列 (matrix ) は線型写像の情報を記述するのに有効な概念である。行列は、図のように、スカラーの矩形配列として書かれる。任意の m × n 行列 A は Fn から Fm への線型写像

として生じる( は総和を表す)。

ベクトル空間 - Wikipedia

⇧  「線型写像」を表せるのだと。 つまり、ベクトルを表せるのだと言っても過言ではないのではなかろうか、教えて偉い人。

これはまた行列 A と座標ベクトル x との行列の積を用いて

x ↦ Ax

と書くこともできる。さらに言えば、V と W の基底を選ぶことで、任意の線型写像 ƒ : V → W は同様の方法で行列によって一意的に表される。

ベクトル空間 - Wikipedia

う、う~ん...よく分からん、のだけども、「行列の積」の説明では、

しかし最も重要な行列の乗法は連立一次方程式やベクトルの一次変換に関するもので、応用数学工学へも広く応用がある。

行列の乗法 - Wikipedia 

これは通例、行列の積(ぎょうれつのせき、matrix product)と呼ばれるもので、A が n × m 行列で、B が m × p 行列ならば、それらの行列の積 AB が n × p 行列として与えられ、その成分は A の各行の m 個の成分がそれぞれ順番に B の各列の m 個の成分と掛け合わされる形で与えられる

行列の乗法 - Wikipedia

となっていますかね。

行列のサイズが大きくなれば、二つあるいはそれ以上の行列の積の計算を定義に従って行うには、非常に膨大な時間が掛かるようになってしまうため、効果的に行列の積を計算できるアルゴリズムが考えられてきた。

行列の乗法 - Wikipedia 

 

機械学習なんかをやっていこうとする場合、 

qiita.com

⇧  「行列」「ベクトル」なんかの知識が無いと厳しいらしい...

微分積分なんかも必要になりそうですかね...

qiita.com

絶望の畳み込みが...あ...畳み込みニューラルネットワーク(Convolutional Neural Network: CNNまたはConvNet)も必要になってくるらしい......

deepage.net

すみません、脱線しました...

 

Java で行列

さぁ、気分が極限まで落ち込んだところで、Javaで行列してみますか~

問題はこんな感じ。

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_6_D&lang=jp

f:id:ts0818:20190105205532p:plain

 

ソースコードはこんな感じにしてみました。

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);
    }
  }
}

んで、実行。

f:id:ts0818:20190105225924p:plain

f:id:ts0818:20190105230054p:plain

一応、OK出ました。 

f:id:ts0818:20190105224950p:plain

提出したコード。

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);
        }
 
    }
 
}

f:id:ts0818:20190105230418p:plain

先は長いですかね......

f:id:ts0818:20190105230722p:plain

 

ちょいと、「行列」の計算とかも勉強していかねばですかね...そして、思うことは、普通の開発で、標準入力とか使わないよね...

今回はこのへんで。