【C#】行列の積を計算する

行列の積はいろんなところで使えるので、練習がてら実装してみます。

1. 行列と型

行列は数字や文字を羅列したもので、行と列に並べて表現します。

f:id:takunology:20200303132433p:plain

例えば図の例では「3行3列の行列」といいます。行列式という言葉もありますが、行列とは違うモノです。

他にも、3行3列の行列を [3×3]型の行列と表現することがあります。また、行列の形は様々でいろんな型があります。

f:id:takunology:20200303133641p:plain

f:id:takunology:20200303134558p:plain

2. 行列の積

行列同士の掛け算は「行×列の和」 で進めていきます。ただし、ルールがあります。掛けられる行列の列の数と、掛ける行列の行の数が同じでないと計算ができません。つまり、[a × n]型 × [n × b]型 でしか計算できません。

f:id:takunology:20200303134613p:plain

これを計算をさせるプログラムを書いていきます。

行列の計算を本格的に勉強したい方はこの本をおススメします。

3. 実装

.NET Core 3.0 のコンソールアプリで実装します。フローはこんな感じです。

  1. 入力する行列の行数と列数を定義
  2. これを掛けられる行列A、掛ける行列Bの2つ分定義する
  3. 行列を入力した値で初期化
  4. 行列AとBの積をとり、その和を結果として結果行列に代入
  5. 結果行列を出力する(必要なら入力行列も表現)

必要なパラメータは行列A, Bとその行数と列数、結果を格納するための結果行列とその行数と列数です。

static int ROW_A = 0;
static int COL_A = 0;

static int ROW_B = 0;
static int COL_B = 0;

static int[,] MatrixA = new int[ROW_A, COL_A];
static int[,] MatrixB = new int[ROW_B, COL_B];
static int[,] MatrixResult = new int[ROW_A, COL_B];

行と列を2重for文で初期化して行列を作ります。初期化するパラメータは任意の入力値なのでコンソール入力を行います。

static void Input()
{
    Console.Write("行列Aの行数:");
    ROW_A = int.Parse(Console.ReadLine());
    Console.Write("行列Aの列数:");
    COL_A = int.Parse(Console.ReadLine());
    Console.WriteLine("行列Aのパラメータ入力");

    MatrixA = new int[ROW_A, COL_A];

    for (int i = 0; i < ROW_A; i++)
    {
        for (int j = 0; j < COL_A; j++)
        {
            MatrixA[i, j] = int.Parse(Console.ReadLine());
        }
    }

    Console.WriteLine("行列Bの行数:");
    ROW_B = int.Parse(Console.ReadLine());
    if (COL_A != ROW_B)
    {
        Console.WriteLine("行列Aの列数と行列Bの行数が異なるため計算できません。");
        return;
    }

    Console.WriteLine("行列Bの列数:");
    COL_B = int.Parse(Console.ReadLine());
    Console.WriteLine("行列Bのパラメータ入力");

    MatrixB = new int[ROW_B, COL_B];

    for (int i = 0; i < ROW_B; i++)
    {
        for (int j = 0; j < COL_B; j++)
        {
            MatrixB[i, j] = int.Parse(Console.ReadLine());
        }
    }

}

ここからがポイントですね。行列の積は [i × j] だけでは計算できません。なぜなら共通の要素を回せないからです。よって、行数と列数を回すfor文に加えて、共通要素を回すためのfor文が必要です。つまり、[i × k]型 × [k × j]型 で計算できるようにしなければなりません。

行列の積の要素数は、掛ける行列の行数と掛けられる行列の列数すなわち、行列Aの行数と行列Bの列数で結果行列の行数と列数を定義します。共通要素は行列Aの列数または行列Bの行数のどちらでも良いです。

static void Calc()
{
    MatrixResult = new int[ROW_A, COL_B]; //結果行列は行列Aの行数と行列Bの列数で再定義
    for (int i = 0; i < ROW_A; i++)
    {
        for (int j = 0; j < COL_B; j++)
        {
            for (int k = 0; k < COL_A; k++) //ROW_BでもOK
            {
                MatrixResult[i, j] += MatrixA[i, k] * MatrixB[k, j];
            }
        }
    }
}

結果を表示するには結果行列の成分をそのまま回せば表示できますが、GetLength() メソッドを用いれば定義された行列(配列)の次元の要素数にアクセスできます。

static void ShowResult()
{
    Console.WriteLine("====== 計算結果 =====");
    for (int i = 0; i < MatrixResult.GetLength(0); i++)
    {
        Console.Write("|");
        for (int j = 0; j < MatrixResult.GetLength(1); j++)
        {
            Console.Write(string.Format("{0,4}", MatrixResult[i, j]));
        }
        Console.WriteLine(" |");
    }
    Console.ReadKey();
}

4. 実行結果

行列AとBの要素数、およびパラメータを入力することで計算が可能です。

f:id:takunology:20200303151210p:plain


行列計算は活用方法も様々あるので、やっておいて損はないと思います。

今回作成したコード

参考にどうぞ

github.com