[C言語] 対称行列を作成する方法
C言語で対称行列を作成するには、まず正方行列を用意し、行列の要素を設定する際に、行列の対角線を基準にして対称性を保つようにします。
具体的には、行列の要素 \(A[i][j]\) を設定したら、対応する \(A[j][i]\) も同じ値に設定します。
これにより、行列の上三角部分と下三角部分が対称になります。
対称行列とは
対称行列とは、行列の特別な形状の一つで、行列の要素が対角線を中心に対称であるものを指します。
具体的には、行列 \( A \) の要素 \( a_{ij} \) が \( a_{ji} \) と等しい場合、すなわち \( A = A^T \)(転置行列と等しい)であるとき、行列は対称行列と呼ばれます。
対称行列は、数値計算や物理学、工学などの分野で広く利用されており、特に固有値問題や最適化問題において重要な役割を果たします。
対称行列の性質を理解することは、行列計算を行う上で非常に重要です。
C言語での行列の基本
行列の定義方法
C言語では、行列は二次元配列として定義されます。
行列のサイズを指定して、次のように宣言します。
int matrix[行数][列数];
例えば、3行2列の整数型行列を定義する場合は以下のようになります。
int matrix[3][2];
行列のメモリ確保
行列のメモリを動的に確保する場合、malloc関数
を使用します。
以下のように、ポインタを使って二次元配列を動的に確保することができます。
int **matrix;
matrix = (int **)malloc(行数 * sizeof(int *));
for (int i = 0; i < 行数; i++) {
matrix[i] = (int *)malloc(列数 * sizeof(int));
}
この方法では、行数分のポインタを確保し、各行に対して列数分のメモリを確保します。
行列の要素へのアクセス方法
行列の要素には、インデックスを使ってアクセスします。
行列の要素 \( a_{ij} \) にアクセスするには、次のように記述します。
matrix[i][j] = 値; // 要素への代入
int value = matrix[i][j]; // 要素の取得
例えば、行列の1行2列目の要素に値を代入する場合は以下のようになります。
matrix[0][1] = 5; // 1行2列目に5を代入
このようにして、C言語では行列を定義し、メモリを確保し、要素にアクセスすることができます。
対称行列を作成する手順
行列の初期化
対称行列を作成するためには、まず行列を初期化する必要があります。
C言語では、二次元配列を使って行列を定義し、初期化することができます。
以下のように、すべての要素を0で初期化する例を示します。
int matrix[行数][列数] = {0}; // 行列の初期化
例えば、3行3列の行列を初期化する場合は次のようになります。
int matrix[3][3] = {0}; // 3x3の行列を0で初期化
対称性を保つためのルール
対称行列を作成する際には、対称性を保つためのルールを守る必要があります。
具体的には、行列の要素 \( a_{ij} \) と \( a_{ji} \) が常に等しくなるように値を設定します。
これにより、行列の対称性が保たれます。
上三角部分と下三角部分の関係
対称行列では、上三角部分と下三角部分の要素が互いに対応しています。
つまり、上三角部分の要素を設定する際に、同時に下三角部分の要素も設定する必要があります。
以下のように、上三角部分の要素を設定する際に、下三角部分も同時に設定することが重要です。
matrix[i][j] = 値; // 上三角部分の要素
matrix[j][i] = 値; // 下三角部分の要素
対角線の要素の扱い
対称行列において、対角線上の要素は自分自身と等しいため、特別な扱いは必要ありません。
対角線上の要素 \( a_{ii} \) は、任意の値を設定することができます。
例えば、次のように対角線の要素を設定します。
matrix[i][i] = 値; // 対角線上の要素の設定
このように、対称行列を作成する際には、行列の初期化、対称性を保つルール、上三角部分と下三角部分の関係、対角線の要素の扱いを理解しておくことが重要です。
実際のコード例
forループを使った対称行列の生成
以下のコードは、forループを使用して対称行列を生成する例です。
この例では、行列の上三角部分の要素を設定し、同時に下三角部分の要素も設定しています。
#include <stdio.h>
#define SIZE 3 // 行列のサイズ
int main() {
int matrix[SIZE][SIZE] = {0}; // 行列の初期化
// 対称行列の生成
for (int i = 0; i < SIZE; i++) {
for (int j = i; j < SIZE; j++) {
matrix[i][j] = i + j; // 上三角部分の要素を設定
matrix[j][i] = matrix[i][j]; // 下三角部分の要素を設定
}
}
// 行列の表示
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
このコードを実行すると、次のような出力が得られます。
0 1 2
1 2 3
2 3 4
ランダムな値を使った対称行列の作成
次に、ランダムな値を使用して対称行列を作成する例を示します。
この例では、rand()関数
を使ってランダムな整数を生成し、対称行列を構築します。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 3 // 行列のサイズ
int main() {
int matrix[SIZE][SIZE] = {0}; // 行列の初期化
srand(time(NULL)); // 乱数の初期化
// 対称行列の生成
for (int i = 0; i < SIZE; i++) {
for (int j = i; j < SIZE; j++) {
int randomValue = rand() % 10; // 0から9のランダムな値を生成
matrix[i][j] = randomValue; // 上三角部分の要素を設定
matrix[j][i] = matrix[i][j]; // 下三角部分の要素を設定
}
}
// 行列の表示
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
このコードを実行すると、出力は毎回異なりますが、例えば次のような結果が得られます。
0 4 2
4 3 1
2 1 5
このように、forループを使って対称行列を生成する方法や、ランダムな値を使って対称行列を作成する方法を理解することができます。
応用例
対称行列の転置
対称行列の転置は、元の行列と同じになります。
つまり、行列 \( A \) が対称行列である場合、\( A^T = A \) です。
以下のコードは、対称行列の転置を確認する例です。
#include <stdio.h>
#define SIZE 3 // 行列のサイズ
void printMatrix(int matrix[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main() {
int matrix[SIZE][SIZE] = {
{1, 2, 3},
{2, 4, 5},
{3, 5, 6}
};
printf("元の行列:\n");
printMatrix(matrix);
printf("転置行列:\n");
printMatrix(matrix); // 転置は元の行列と同じ
return 0;
}
このコードを実行すると、元の行列と転置行列が同じであることが確認できます。
対称行列の加算
対称行列の加算は、対応する要素を単純に加算することで行います。
以下のコードは、2つの対称行列を加算する例です。
#include <stdio.h>
#define SIZE 3 // 行列のサイズ
void addSymmetricMatrices(int A[SIZE][SIZE], int B[SIZE][SIZE], int C[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
C[i][j] = A[i][j] + B[i][j]; // 対応する要素を加算
}
}
}
int main() {
int A[SIZE][SIZE] = {
{1, 2, 3},
{2, 4, 5},
{3, 5, 6}
};
int B[SIZE][SIZE] = {
{1, 1, 1},
{1, 1, 1},
{1, 1, 1}
};
int C[SIZE][SIZE] = {0}; // 結果行列の初期化
addSymmetricMatrices(A, B, C);
printf("加算結果行列:\n");
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%d ", C[i][j]);
}
printf("\n");
}
return 0;
}
このコードを実行すると、2つの対称行列の加算結果が表示されます。
対称行列の積
対称行列の積も、通常の行列の積と同様に計算しますが、結果が対称行列になるとは限りません。
以下のコードは、2つの対称行列の積を計算する例です。
#include <stdio.h>
#define SIZE 3 // 行列のサイズ
void multiplySymmetricMatrices(int A[SIZE][SIZE], int B[SIZE][SIZE], int C[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
C[i][j] = 0; // 結果行列の初期化
for (int k = 0; k < SIZE; k++) {
C[i][j] += A[i][k] * B[k][j]; // 行列の積
}
}
}
}
int main() {
int A[SIZE][SIZE] = {
{1, 2, 3},
{2, 4, 5},
{3, 5, 6}
};
int B[SIZE][SIZE] = {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}
};
int C[SIZE][SIZE] = {0}; // 結果行列の初期化
multiplySymmetricMatrices(A, B, C);
printf("積の結果行列:\n");
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%d ", C[i][j]);
}
printf("\n");
}
return 0;
}
このコードを実行すると、2つの対称行列の積が表示されます。
対称行列の逆行列
対称行列の逆行列は、行列が正則である場合にのみ存在します。
以下のコードは、対称行列の逆行列を計算する例です。
ここでは、簡単のために、行列の逆行列を求めるためにガウス・ジョルダン法を使用します。
#include <stdio.h>
#define SIZE 3 // 行列のサイズ
void printMatrix(float matrix[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
printf("%.2f ", matrix[i][j]);
}
printf("\n");
}
}
void inverseMatrix(float A[SIZE][SIZE], float inverse[SIZE][SIZE]) {
float augmented[SIZE][2 * SIZE];
// 行列を拡張行列に変換
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
augmented[i][j] = A[i][j];
augmented[i][j + SIZE] = (i == j) ? 1 : 0; // 単位行列
}
}
// ガウス・ジョルダン法
for (int i = 0; i < SIZE; i++) {
float pivot = augmented[i][i];
for (int j = 0; j < 2 * SIZE; j++) {
augmented[i][j] /= pivot; // ピボットを1にする
}
for (int j = 0; j < SIZE; j++) {
if (i != j) {
float factor = augmented[j][i];
for (int k = 0; k < 2 * SIZE; k++) {
augmented[j][k] -= factor * augmented[i][k]; // 行の消去
}
}
}
}
// 逆行列を抽出
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
inverse[i][j] = augmented[i][j + SIZE];
}
}
}
int main() {
float A[SIZE][SIZE] = {
{4, 2, 2},
{2, 4, 2},
{2, 2, 4}
};
float inverse[SIZE][SIZE] = {0}; // 逆行列の初期化
inverseMatrix(A, inverse);
printf("逆行列:\n");
printMatrix(inverse);
return 0;
}
このコードを実行すると、対称行列の逆行列が表示されます。
対称行列の逆行列を求めることは、数値計算や最適化問題において非常に重要です。
まとめ
この記事では、C言語を用いて対称行列を作成する方法やその特性について詳しく解説しました。
対称行列の初期化や要素の設定、さらには行列の加算や積、逆行列の計算に至るまで、具体的なコード例を通じて理解を深めることができました。
これを機に、対称行列の特性を活かしたプログラミングに挑戦し、より効率的なアルゴリズムの実装を目指してみてください。