コンピュータとオセロ対戦40　～行列計算～

https://qiita.com/tt_and_tk/items/068f2afde6db637e189f

[前回](https://qiita.com/tt_and_tk/items/e91bfc5c83bd8ee73d75)

# 今回の目標
行列計算用のクラスが必要だと思ったので作ります。
# ここから本編
## 現在のディレクトリ構成
現在のディレクトリ構成は以下の通りです。
ファイルは省略しています。

```
MyNet
├── layer    // 層のパッケージ（今は空）
├── matrix   // 行列のパッケージ（今回作成）
├── nodes    // ノードのパッケージ（前回作成）
│   └── out_function  // 活性化関数のパッケージ（前回作成）
└── optimzer // 最適化関数のパッケージ（今は空）
```

## メンバ変数とコンストラクタ
できるだけnumpyのndarrayに近い形にしたいと考えています。
演算子のオーバーライドができない時点で不可能ではありますが、できるだけ近い感覚で使いたいです。
なんとなくいろんな引数に対応できるようにしました。実際こんなに使うかは分かりませんが・・・。

```java
/**
 * Class for calculation and save of matrix.
 */
public class Matrix{
    /** Matrix's value. */
    public double matrix[][];
    /** Matrix's row, col. */
    public int row, col;
    /** Matrix's shape */
    public int shape[];

    /**
     * Constructor for this class.
     * Set the matrix and its size.
     * @param in Two dimensional matrix of type Matrix.
     */
    public Matrix(Matrix in){
        this.matrix = new double[in.row][in.col];
        this.shape = new int[2];
        this.row = in.row;
        this.col = in.col;
        this.shape[0] = this.row; this.shape[1] = this.col;

        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                this.matrix[i][j] = in.matrix[i][j];
            }
        }
    }

    /**
     * Constructor for this class.
     * Set the matrix and its size.
     * @param in Two dimensional matrix of type double[][].
     */
    public Matrix(double in[][]){
        this.matrix = new double[in.length][in[0].length];
        this.shape = new int[2];
        this.row = in.length;
        this.col = in[0].length;
        this.shape[0] = this.row; this.shape[1] = this.col;

        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                this.matrix[i][j] = in[i][j];
            }
        }
    }

    /**
     * Constructor for this class.
     * Set the matrix and its size.
     * @param in Two dimensional matrix of type Double[][].
     */
    public Matrix(Double in[][]){
        this.matrix = new double[in.length][in[0].length];
        this.shape = new int[2];
        this.row = in.length;
        this.col = in[0].length;
        this.shape[0] = this.row; this.shape[1] = this.col;

        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                this.matrix[i][j] = in[i][j];
            }
        }
    }
```

## 足し算
行列に行列を足す、行列に数字を足す、自分が持つ行列に行列を足す、自分が持つ行列に数字を足すの四種類を実装しました。

```java
    /**
     * Add a matrix to a matrix.
     * @param a Augend matrix.
     * @param b Addend matrix.
     * @return New added Matrix instance.
     */
    public static Matrix add(Matrix a, Matrix b){
        if (a.row != b.row || a.col != b.col){
            System.out.println("adding error");
            System.exit(-1);
        }

        Matrix rtn = new Matrix(new double[a.row][a.col]);
        for (int i = 0; i < a.row; i++){
            for (int j = 0; j < a.col; j++){
                rtn.matrix[i][j] = a.matrix[i][j] + b.matrix[i][j];
            }
        }

        return rtn;
    }

    /**
     * Add a number to a matirx.
     * @param a Matrix.
     * @param num Number.
     * @return New added Matrix instance.
     */
    public static Matrix add(Matrix a, double num){
        Matrix rtn = new Matrix(new double[a.row][a.col]);
        for (int i = 0; i < a.row; i++){
            for (int j = 0; j < a.col; j++){
                rtn.matrix[i][j] = a.matrix[i][j] + num;
            }
        }

        return rtn;
    }

    /**
     * Add a matrix to this matrix.
     * @param a Addend matrix.
     */
    public void add(Matrix a){
        if (this.row != a.row || this.col != a.col){
            System.out.println("adding error");
            System.exit(-1);
        }

        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                this.matrix[i][j] += a.matrix[i][j];
            }
        }
    }

    /**
     * Add a number to this matirx.
     * @param a Matrix.
     * @return New added Matrix instance.
     */
    public void add(double num){
        Matrix rtn = new Matrix(new double[this.row][this.col]);
        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                rtn.matrix[i][j] = this.matrix[i][j] + num;
            }
        }
    }
```

## 引き算
足し算と違い、自分の行列に対して作用するようなものは作りませんでした。
理由として、引く数と引かれる数の順番が変わると違う結果になるからです。引き算するときは、-1倍して足すなど工夫が必要になりそうです。
プログラムは足し算とほぼ同じなので省略します。

## 掛け算
数字との掛け算を、静的動的療法用意しました。

```java
    /**
     * Multiply a matrix by a number.
     * @param a Matrix.
     * @param num Number.
     * @return New multiplied Matrix instance.
     */
    public static Matrix mult(Matrix a, double num){
        Matrix rtn = new Matrix(new double[a.row][a.col]);
        for (int i = 0; i < a.row; i++){
            for (int j = 0; j < a.col; j++){
                rtn.matrix[i][j] = a.matrix[i][j] * num;
            }
        }

        return rtn;
    }

    /**
     * Multiply this matrix by a number.
     * @param num Number.
     */
    public void mult(double num){
        Matrix rtn = new Matrix(new double[this.row][this.col]);
        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                rtn.matrix[i][j] = this.matrix[i][j] * num;
            }
        }
    }
```

## 割り算
行列を数字で割るのは順番なんてないので、掛け算と同様二種類用意しました。
掛け算とほぼ同じプログラムなので省略。

## 内積
内積計算です。
特筆すべきことはなし。

```java
    /**
     * Dot product for two matrices.
     * @param a Matrix to be dot producted.
     * @param b Matrix to dot product.
     * @return New dot producted Matrix instance.
     */
    public static Matrix dot(Matrix a, Matrix b){
        if (a.col != b.row){
            System.out.println("dot producting error");
            System.exit(-1);
        }

        Matrix rtn = new Matrix(new double[a.row][b.col]);
        double num = 0;
        for (int i = 0; i < a.row; i++){
            for (int j = 0; j < b.col; j++){
                num = 0;
                for (int k = 0; k < a.col; k++){
                    num += a.matrix[i][j] * b.matrix[j][i];
                }
                rtn.matrix[i][j] = num;
            }
        }

        return rtn;
    }
```

## 転置行列
内積と同様、特筆すべきことはなし。

```java
    /**
     * Create transpose of this matrix.
     * @return New Matrix instance transposed of this matrix .
     */
    public Matrix T(){
        Matrix rtn = new Matrix(new double[col][row]);
        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                rtn.matrix[j][i] = this.matrix[i][j];
            }
        }

        return rtn;
    }
```

## toString
せっかくなのでndarrayっぽく表示されるようにしました。

```java
    @Override
    public String toString(){
        String str = "[";

        int i = 0;
        for (double[] ele: matrix){
            if (i == 0){
                str += "[";
            }else{
                str += "\n [";
            }
            i++;
            for (double num: ele){
                str += String.format("%.4f ", num);
            }
            str += "]";
        }
        str += "]\n";

        return str;
    }
```

## equals
Matrixオブジェクトだけでなく、double[][]、Double[][]とも比較できるようにしました。使うかは分かりませんが。
シンプルに全要素が同じなら同一判定です。

```java
    /**
     * Method to compare this Matrix instance and a Matrix instance.
     * Without override.
     * @param o A Matrix instance.
     * @return Is equal?
     */
    public boolean equals(Matrix o){
        if (o == this){
            return true;
        }
        if (this.row != o.row || this.col != o.col){
            return false;
        }

        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                if (this.matrix[i][j] != o.matrix[i][j]){
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Method to compare this Matrix instance and a double[][] instance.
     * Without override.
     * @param o A double[][] instance.
     * @return Is equal?
     */
    public boolean equals(double o[][]){
        if (this.row != o.length || this.col != o[0].length){
            return false;
        }
        for (int i = 0; i < o.length; i++){
            for (int j = 0; j < o[0].length; j++){
                if (this.matrix[i][j] != o[i][j]){
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Method to compare this Matrix instance and a double[][] instance.
     * Without override.
     * @param o A Double[][] instance.
     * @return Is equal?
     */
    public boolean equals(Double o[][]){
        if (this.row != o.length || this.col != o[0].length){
            return false;
        }
        for (int i = 0; i < o.length; i++){
            for (int j = 0; j < o[0].length; j++){
                if (this.matrix[i][j] != o[i][j]){
                    return false;
                }
            }
        }

        return true;
    }
```

## clone
特筆すべきことはなし。

```java
    @Override
    public Matrix clone(){
        Matrix rtn = new Matrix(new double[this.row][this.col]);
        
        for (int i = 0; i < this.row; i++){
            for (int j = 0; j < this.col; j++){
                rtn.matrix[i][j] = this.matrix[i][j];
            }
        }

        return rtn;
    }
```

## hashCode
合計求めてintにしてます。

```java
    @Override
    public int hashCode(){
        double sum = 0;

        for (double[] ele: this.matrix){
            for (double num: ele){
                sum += num;
            }
        }

        return (int)sum;
    }
```

# 次回は
層作ります。

[次回](https://qiita.com/tt_and_tk/items/bd49dd220f8c9a8eadd5)

https://qiita.com/tt_and_tk/items/068f2afde6db637e189f

# 参考文献
[【Java】行列計算用のクラス - 元理系院生の新入社員がPythonとJavaで色々頑張るブログ](https://t.co/d6YcGDgHtX)