Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

【C言語】行列が特異行列かどうかを判定するプログラムの書き方

行列を mat[行][列] の形式で与えたとき、関数を使ってその行列が「特異行列」かどうかを判定し、結果を表示するのが本記事の目的です。

特異行列とは、行列式(determinant)が 0 になる行列のことを指します。逆に、行列式が 0 でない行列は「非特異行列(正則行列)」と呼ばれます。

したがって、行列が特異かどうかを調べるには、まず行列式を計算する必要があります。3×3 行列の行列式は、次の式で求められます。

$$M1[3][3]\:=\:\begin{bmatrix}a & b & c \\d & e & f \\g & h & i \end{bmatrix}$$

|m1| = a(e×i − f×h) − b(d×i − f×g) + c(d×h − e×g)

入力例

入力 -: mat[3][3]= { 4, 10, 1 },
    { 0, 2, 3 },
    { 1, 4, -3 }
出力 -: 非特異行列である

入力 -: mat[3][3]= { 0, 0, 0 },
    { 10, 20, 30 },
    { 1, 4, -3 }
出力 -: 特異行列である
最初の行がすべて 0 のため、行列式は必ず 0 になります

アルゴリズム

開始
関数 cofactor(int matrix[N][N], int matrix2[N][N], int p, int q, int n)
{
    ステップ 1-> i = 0, j = 0, row, col を宣言・初期化
    ステップ 2-> row = 0 ~ row < n まで row++ のループ
    col = 0 ~ col < n まで col++ のループ
        if (row != p && col != q) の場合、
        matrix2[i][j++] に matrix[row][col] を代入
            j == n - 1 の場合、
                j = 0 に設定し、i を 1 増やす
        ループ終了
関数 int check_singular(int matrix[N][N], int n)
    ステップ 1-> int D = 0 を宣言・初期化
    ステップ 2-> n == 1 の場合、
        matrix[0][0] を返す
    ステップ 3-> matrix2[N][N]、sign = 1 を宣言
    ステップ 4-> f = 0 ~ f < n まで f++ のループ
        cofactor(matrix, matrix2, 0, f, n) を呼び出す
        D += sign * matrix[0][f] * check_singular(matrix2, n - 1)
        sign = -sign に設定(符号を交互に入れ替える)
    ループ終了
    ステップ 5-> D を返す
main()
    ステップ 1-> matrix[N][N] を宣言・初期化
    ステップ 2-> check_singular(matrix, N) の戻り値が 0 の場合、
        「Matrix is Singular」と表示
    ステップ 3-> それ以外の場合、
        「Matrix is non-Singular」と表示
終了

C言語での実装例

#include <stdio.h>
#define N 4
// 余因子を求める関数
int cofactor(int matrix[N][N], int matrix2[N][N], int p, int q, int n) {
    int i = 0, j = 0;
    int row, col;
    // 行列の各要素に対してループ処理を行う
    for (row = 0; row < n; row++) {
        for (col = 0; col < n; col++) {
            // 指定された行・列に含まれない要素だけを
            // 一時的な行列へコピーする
            if (row != p && col != q) {
                matrix2[i][j++] = matrix[row][col];
                // 1 行分のコピーが完了したら、
                // 行インデックスを進め、列インデックスをリセットする
                if (j == n - 1) {
                    j = 0;
                    i++;
                }
            }
        }
    }
    return 0;
}
/* matrix[][] が特異行列かどうかを再帰的に判定する関数 */
int check_singular(int matrix[N][N], int n) {
    int D = 0; // 結果の初期化
    // 基底ケース:行列の要素が 1 つだけの場合
    if (n == 1)
    return matrix[0][0];
    int matrix2[N][N]; // 余因子を格納するための行列
    int sign = 1; // 符号の係数を保持
    // 1 行目の各要素について繰り返す
    for (int f = 0; f < n; f++) {
        // matrix[0][f] の余因子を取得
        cofactor(matrix, matrix2, 0, f, n);
        D += sign * matrix[0][f] * check_singular(matrix2, n - 1);
        // 各項は符号を交互に変えながら加算する
        sign = -sign;
    }
    return D;
}
// 上記の関数をテストするドライバプログラム
int main() {
    int matrix[N][N] = { { 4, 10, 1 },
    { 0, 2, 3 },
    { 1, 4, -3 } };
    if (check_singular(matrix, N) == 0)
        printf("Matrix is Singular\n");
    else
        printf("Matrix is non-Singular\n");
    return 0;
}

実行結果

上記のコードを実行すると、次の出力が得られます。

Matrix is non-Singular

解説

このプログラムでは、余因子展開(cofactor expansion)を用いて行列式を再帰的に計算しています。1 行目の各要素について、その行と列を取り除いた小行列の余因子を求め、符号(+と−)を交互に付けながら掛け合わせていくことで、任意のサイズ n の正方行列の行列式を求められます。

計算結果の行列式 D が 0 であれば特異行列、0 以外であれば非特異行列と判定できます。なお、この再帰的な手法は理解しやすい反面、計算量が O(n!) と大きいため、大規模な行列を扱う場合は LU 分解などの効率的な手法を検討するとよいでしょう。

  1. C++で対合行列(インボリュートリー行列)を判定するプログラムの実装方法

    行列 M[r][c] が与えられたとき、「r」は行数、「c」は列数を表します。ここでは r = c、つまり正方行列である場合を考えます。この記事では、与えられた正方行列が対合行列(インボリュートリー行列)であるかどうかを判定する方法を解説します。 対合行列とは 対合行列とは、ある行列を自分自身と掛け合わせたとき、その積が単位行列になるような行列のことです。単位行列 I とは、主対角成分がすべて 1 で、それ以外の要素がすべて 0 である行列を指します。 したがって、行列 M が対合行列であるための必要十分条件は次のように表せます。 M × M = I ここで、M は任意の行列、I は単位行列で

  2. C++でべき等行列を判定するプログラムの作成方法

    行数を r、列数を c とする行列 M[r][c] が与えられ、r = c となる正方行列を考えます。この記事では、与えられた正方行列がべき等行列(アイデンポテント行列)であるかどうかを判定するC++プログラムを解説します。 べき等行列とは 行列 M がべき等行列であるとは、行列 M と自分自身の積が元の行列 M と等しくなること、すなわち M × M = M が成り立つことを指します。 例えば、次の行列を見てください。 この行列を自分自身で掛け合わせても、結果は元の行列とまったく同じになります。したがって、この行列はべき等行列であると言えます。 べき等行列の代表的な例としては、ベクトルを