N元連立1次方程式にはいろいろ解き方あるけど、アルゴリズムが一番楽なクラメルの公式
クラメルの公式とは
$A$を正方行列としたとき $Ax=b$で与えられる連立方程式の$i$番目の解は \[ x_i=\frac{det(A_i)}{det(A)} \]計算の流れ
公式だけでは説明不足で解らいので、例を使って解説
\[ \left\{ \begin{array} _2x_1 + 4x_2 = 10 & \\ x_1 + 3x_2 = 6 & \end{array} \right. \tag{1} \] 式1をクラメルの式を使って解く
行列で$Ax=b$の形に直すと
\[ \left( \begin{array}{ccc} 2 & 4 \\ 1 & 3 \end{array} \right) \left( \begin{array}{ccc} x_1 \\ x_2 \end{array} \right) = \left( \begin{array}{ccc} 10 \\ 6 \end{array} \right) \] よって、 \[ A = \left( \begin{array}{ccc} 2 & 4 \\ 1 & 3 \end{array} \right) 、 b = \left( \begin{array}{ccc} 10\\ 6 \end{array} \right) \]
\[ \left\{ \begin{array} _2x_1 + 4x_2 = 10 & \\ x_1 + 3x_2 = 6 & \end{array} \right. \tag{1} \] 式1をクラメルの式を使って解く
行列で$Ax=b$の形に直すと
\[ \left( \begin{array}{ccc} 2 & 4 \\ 1 & 3 \end{array} \right) \left( \begin{array}{ccc} x_1 \\ x_2 \end{array} \right) = \left( \begin{array}{ccc} 10 \\ 6 \end{array} \right) \] よって、 \[ A = \left( \begin{array}{ccc} 2 & 4 \\ 1 & 3 \end{array} \right) 、 b = \left( \begin{array}{ccc} 10\\ 6 \end{array} \right) \]
- クラメルの公式の分母 分母は行列$A$の行列式
- クラメルの公式の分子 $x_i$の場合の行列$A_i$は行列$A$の$i$番目の列と$b$を入れ替えた行列
- $x_1$の場合 : $A$の1列目を$b$と入れ替える \[ A_1 = \left( \begin{array}{ccc} 10 & 4 \\ 6 & 3 \end{array} \right) \] 計算すると \[ det(A_1) = 10\times3-4\times6=6 \]
- $x_2$の場合 : $A$の2列目を$b$と入れ替える \[ A_2 = \left( \begin{array}{ccc} 2 & 10 \\ 1 & 6 \end{array} \right) \] 計算すると \[ det(A_2) = 2\times6-1\times10=2 \]
- 解を求める \[ \left\{ \begin{array} _x_1 = \frac{6}{2}=3 \\ x_2 = \frac{2}{2}=1 \end{array} \right. \]
\[ det(A) = 2\times3-4\times1=2 \]
プログラム
これをN次元でも解けるようにするプログラムを組む
上のアルゴリズムから、
数値計算プログラムはCとかFortranで書いた方がいいんだけど、環境がなかったので。。javaを使用
できるだけ、プリミティブ型で書いて、別言語に書き換えやすくしとく
行列の列を入れ替えるモジュール
まぁこれは簡単か。
メイン文
モジュールができたので、組み立てる
上のアルゴリズムから、
- 行列式を求めるモジュール
- 行列の列を入れ替えるモジュール
数値計算プログラムはCとかFortranで書いた方がいいんだけど、環境がなかったので。。javaを使用
できるだけ、プリミティブ型で書いて、別言語に書き換えやすくしとく
- 行列式を求めるモジュール 余因子展開使って再帰関数で作ってく。N×N行列の余因子展開の公式はコレ
\begin{eqnarray} det(A)=\sum^n_{j=0}(-1)^j \cdot a_{0j} \cdot det(A_j) \end{eqnarray} プログラムにするとこんな感じ。
/** 行列式の計算.
* @param A 行列
* @param n 行列の長さ
* @return 計算結果
*/
static double dat(double[][] matrix, int n) {
if(n == 1) return matrix[0][0];
if(n == 2) return matrix[0][0] * matrix[1][1] - matrix[1][0] * matrix[0][1];
double sum = 0;
for(int j = 0; j < n; j++) {
int sign = ((j % 2) == 0) ? 1 : -1;
double[][] laplace_marix = createLaplaceMarix(matrix,n,0,j);
sum += sign * matrix[j][0] * dat(laplace_marix, n-1);
}
return sum;
}
/** 余因子展開で使う行列を作る.
* @param A 元の行列
* @param n 元の行列の長さ
* @param line 消す行
* @param col 消す列
* @return
*/
static double[][] createLaplaceMarix(double[][] matrix, int n, int line, int col) {
double laplace_marix[][] = new double[n-1][n-1]; // 余因子展開で使う行列
for(int i = 0, y = 0; i < n; i++) {
if(i == col)continue;
for(int j = 0, x = 0; j < n; j++){
if(j == line)continue;
laplace_marix[y][x] = matrix[i][j];
x++;
}
y++;
}
return laplace_marix;
}
/** 行列の列を入れ替える.
* @param matrix 元の行列
* @param n 列の長さ
* @param col1 入れ替える列
* @param col2 入れ替わる列
* @return 変換後の行列
*/
static double[][] changeColumn(double[][] matrix, int n, int col1, int col2) {
double[][] temp_matrix = new double[n][n+1];
// 配列コピー
for(int i = 0; i < n; i++){
for(int j = 0; j < n + 1; j++) {
temp_matrix[i][j] = matrix[i][j];
}
}
// 列の入れ替え
for(int i = 0; i < n; i++) {
double temp = temp_matrix[i][col1];
temp_matrix[i][col1] = temp_matrix[i][col2];
temp_matrix[i][col2] = temp;
}
return temp_matrix;
}
public static void main(String[] args) {
int n = 2; // 連立方程式の元
double matrix[][]={ // 連立方程式を行列化
{2, 4, 10}, // 2x + 4y = 10 - 式1
{1, 3, 6}, // x + 3y = 6 - 式2
};
double denominator = dat(matrix, n); // dat(A) 分母
double[] result = new double[n]; // 答えの配列
for(int i = 0; i < n; i++) {
double[][] molecules_matrix = changeColumn(matrix, n, i, n);// 分子の行列
result[i] = dat(molecules_matrix, n) / denominator;
}
// 解を表示
for(int i = 0; i < n; i++) {
System.out.println("result["+ i +"] : " + result[i]);
}
}
実行してみる
4元連立方程式で試してみる。
\[
\left\{
\begin{array}
_2x_1 + x_2+3x_3+4x_4 = 2 & \\
3x_1 + 2x_2+5x_3+2x_4 = 12 & \\
3x_1 + 4x_2+x_3-x_4 = 4 & \\
-x_1 + -3x_2+x_3+3x_4 = -1 & \\
\end{array}
\right.
\tag{2}
\]
配列にすると、こう書けばOK
double matrix[][]={ // 連立方程式を行列化
// x1 x2 x3 x4 b ※bは移行してるわけではないので、右辺のbを書けばOK
{ 2.0, 1.0, 3.0, 4.0, 2.0}, //式1: 2x + y + 3z + 4w = 2
{ 3.0, 2.0, 5.0, 2.0, 12.0},//式2: 3x + 2y + 5z + 2w = 12
{ 3.0, 4.0, 1.0,-1.0, 4.0}, //式3: 3x + 4y + z - 1w = 4
{-1.0,-3.0, 1.0, 3.0,-1.0} //式4:-1x - 3y + z + 3w = -1
};
回答がこんな感じ
result[0] : 1.0 result[1] : -1.0 result[2] : 3.0 result[3] : -2.0できたー!
0 件のコメント:
コメントを投稿