0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-02-08

前回

今回の目標

行列計算用のクラスが必要だと思ったので作ります。

ここから本編

現在のディレクトリ構成

現在のディレクトリ構成は以下の通りです。
ファイルは省略しています。

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

メンバ変数とコンストラクタ

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

/**
 * 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];
            }
        }
    }

足し算

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

    /**
     * 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倍して足すなど工夫が必要になりそうです。
プログラムは足し算とほぼ同じなので省略します。

掛け算

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

    /**
     * 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;
            }
        }
    }

割り算

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

内積

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

    /**
     * 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;
    }

転置行列

内積と同様、特筆すべきことはなし。

    /**
     * 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っぽく表示されるようにしました。

    @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[][]とも比較できるようにしました。使うかは分かりませんが。
シンプルに全要素が同じなら同一判定です。

    /**
     * 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

特筆すべきことはなし。

    @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にしてます。

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

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

        return (int)sum;
    }

次回は

層作ります。

次回

参考文献

【Java】行列計算用のクラス - 元理系院生の新入社員がPythonとJavaで色々頑張るブログ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0