ガウス・ザイデル法を使用して連立方程式 Ax = b を解くルーチンを C++ で作成しました。ただし、スパースな特定の "A" 行列 (ほとんどの要素がゼロ) にこのコードを使用したいと考えています。このように、このソルバーにかかる時間のほとんどは、いくつかの要素をゼロで乗算するのに忙しいです。
たとえば、次の連立方程式の場合:
| 4 -1 0 0 0 | | x1 | | b1 |
|-1 4 -1 0 0 | | x2 | | b2 |
| 0 -1 4 -1 0 | | x3 | = | b3 |
| 0 0 -1 4 -1 | | x4 | | b4 |
| 0 0 0 -1 4 | | x5 | | b5 |
Gauss-Seidel 法を使用すると、x1 に対して次の反復式が得られます。
x1 = [b1 - (-1 * x2 + 0 * x3 + 0 * x4 + 0 * x5)] / 4
ご覧のとおり、ソルバーはゼロ要素を乗算することで時間を浪費しています。大きな行列 (たとえば、10^5 x 10^5) を扱っているため、これは合計 CPU 時間に悪影響を及ぼします。ソルバーを最適化して、ゼロ要素の乗算に関連する計算の部分を省略する方法があるのだろうかと思います。
上記の例の "A" 行列の形式は任意であり、ソルバーは任意の "A" 行列を処理できなければならないことに注意してください。
コードは次のとおりです。
void GaussSeidel(double **A, double *b, double *x, int arraySize)
{
const double tol = 0.001 * arraySize;
double error = tol + 1;
for (int i = 1; i <= arraySize; ++i)
x[i] = 0;
double *xOld;
xOld = new double [arraySize];
for (int i = 1; i <= arraySize; ++i)
xOld[i] = 101;
while (abs(error) > tol)
{
for (int i = 1; i <= arraySize; ++i)
{
sum = 0;
for (int j = 1; j <= arraySize; ++j)
{
if (j == i)
continue;
sum = sum + A[i][j] * x[j];
}
x[i] = 1 / A[i][i] * (b[i] - sum);
}
//cout << endl << "Answers:" << endl << endl;
error = errorCalc(xOld, x, arraySize);
for (int i = 1; i <= arraySize; ++i)
xOld[i] = x[i];
cout << "Solution converged!" << endl << endl;
}