#include <iostream>
#include <vector>
#include <cstdlib>
#include <iomanip>
const int N1 = 3;
const int N2 = 4;
template <class T>
class LUDecompose {
typedef std::vector<std::vector<T> > VV;
typedef std::vector<T> V;
VV a, l, u, x, y;
V b;
int n;
void MakeSquareMatrix(VV& a) {
a.resize(n);
for (int i = 0; i < n; i++)
a[i].resize(n);
}
void MakeVector(V& b) {
b.resize(n);
}
// LU分解(ドゥーリトル法)
void LUDecomp(VV& a, VV& l, VV& u) {
int i, j, k;
for (i = 0; i < n; i++)
l[i][i] = 1.0;
for (i = 0; i < n; i++)
u[0][i] = a[0][i];
for (i = 1; i < n; i++) {
if (u[i - 1][i - 1] == 0.0) {
std::cerr << "行列Uは正則ではありません" << std::endl;
std::exit(1);
}
for (j = i; j < n; j++) {
// L成分の算出
l[j][i - 1] = a[j][i - 1];
for (k = 0; k < i - 1; k++)
l[j][i - 1] -= l[j][k] * u[k][i - 1];
l[j][i - 1] /= u[i - 1][i - 1];
// U成分の算出
u[i][j] = a[i][j];
for (k = 0; k < i; k++)
u[i][j] -= l[i][k] * u[k][j];
}
}
}
void PrintMatrix(VV& a, const char* s) {
std::cout << "*** " << s << "***\n";
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
std::cout << std::setw(11) << std::setprecision(7) << std::fixed
<< std::showpoint << std::right << a[i][j];
std::cout << " ";
}
std::cout << '\n';
}
}
// LU分解を利用して逆行列を求める
void LUInv(VV& l, VV& u, VV& x) {
int i, j, k;
double r;
VV lu;
// 上三角行列と下三角行列を合成する
MakeSquareMatrix(lu);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
lu[i][j] = (i <= j) ? u[i][j] : l[i][j];
// 逆行列を求める
for (k = 0; k < n; k++) {
for (i = 0; i < n; i++) {
r = (i == k) ? 1.0 : 0.0;
for (j = 0; j < n; j++)
r -= lu[i][j] * x[j][k];
x[i][k] = r;
}
for (i = n - 1; i >= 0; i--) {
r = x[i][k];
for (j = i + 1; j < n; j++)
r -= lu[i][j] * x[j][k];
x[i][k] = r / lu[i][i];
}
}
}
// 行列の積
void MatMul(VV& z, VV& x, VV& y) {
int i, j, k;
double s;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
s = 0.0;
for (k = 0; k < n; k++)
s += x[i][k] * y[k][j];
z[i][j] = s;
}
}
/* 三角行列の行列式は対角成分の積 */
double DetTriangularMatrix(VV& a) {
double det = 1.0;
for (int i = 0; i < n; i++)
det *= a[i][i];
return det;
}
public:
LUDecompose(int nn, T* init) : n(nn) {
MakeSquareMatrix(a);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[i][j] = init[i * n + j];
MakeSquareMatrix(l);
MakeSquareMatrix(u);
MakeSquareMatrix(x);
MakeSquareMatrix(y);
}
void Calculate() {
LUDecomp(a, l, u);
LUInv(l, u, x);
MatMul(y, a, x);
}
void PrintMatrix() {
PrintMatrix(a, "行列 A");
PrintMatrix(l, "行列 L");
PrintMatrix(u, "行列 U");
PrintMatrix(x, "逆行列 X(A^(-1))");
PrintMatrix(y, "行列 Y(A * X)");
std::cout << "行列式 |A| = " << DetTriangularMatrix(l) * DetTriangularMatrix(u) << std::endl;
}
};
int main(void)
{
double a1[] = {2.0, 3.0, -1.0, 4.0, 4.0, -3.0, 2.0, -3.0, 1.0};
double a2[] = {1.0, 1.0, 0.0, 3.0, 2.0, 1.0, -1.0, 1.0, 3.0, -1.0, -1.0, 2.0, -1.0, 2.0, 3.0, -2.0};
LUDecompose<double> lu1(N1, a1);
lu1.Calculate();
lu1.PrintMatrix();
std::cout << '\n';
LUDecompose<double> lu2(N2, a2);
lu2.Calculate();
lu2.PrintMatrix();
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8Y3N0ZGxpYj4KI2luY2x1ZGUgPGlvbWFuaXA+Cgpjb25zdCBpbnQgTjEgPSAzOwpjb25zdCBpbnQgTjIgPSA0OwoKdGVtcGxhdGUgPGNsYXNzIFQ+CmNsYXNzIExVRGVjb21wb3NlIHsKICB0eXBlZGVmIHN0ZDo6dmVjdG9yPHN0ZDo6dmVjdG9yPFQ+ID4gVlY7CiAgdHlwZWRlZiBzdGQ6OnZlY3RvcjxUPiBWOwogIFZWIGEsIGwsIHUsIHgsIHk7CiAgViBiOwogIGludCBuOwoKICB2b2lkIE1ha2VTcXVhcmVNYXRyaXgoVlYmIGEpIHsKICAgIGEucmVzaXplKG4pOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgIGFbaV0ucmVzaXplKG4pOwogIH0KICB2b2lkIE1ha2VWZWN0b3IoViYgYikgewogICAgYi5yZXNpemUobik7CiAgfQogIC8vIExV5YiG6KejKOODieOCpeODvOODquODiOODq+azlSkKICB2b2lkIExVRGVjb21wKFZWJiBhLCBWViYgbCwgVlYmIHUpIHsKICAgIGludCBpLCBqLCBrOwoKICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgIGxbaV1baV0gPSAxLjA7CiAgICBmb3IgKGkgPSAwOyBpIDwgbjsgaSsrKQogICAgICB1WzBdW2ldID0gYVswXVtpXTsKCiAgICBmb3IgKGkgPSAxOyBpIDwgbjsgaSsrKSB7CiAgICAgIGlmICh1W2kgLSAxXVtpIC0gMV0gPT0gMC4wKSB7CiAgICAgICAgc3RkOjpjZXJyIDw8ICLooYzliJdV44Gv5q2j5YmH44Gn44Gv44GC44KK44G+44Gb44KTIiA8PCBzdGQ6OmVuZGw7CiAgICAgICAgc3RkOjpleGl0KDEpOwogICAgICB9CiAgICAgIGZvciAoaiA9IGk7IGogPCBuOyBqKyspIHsKICAgICAgICAvLyBM5oiQ5YiG44Gu566X5Ye6CiAgICAgICAgbFtqXVtpIC0gMV0gPSBhW2pdW2kgLSAxXTsKICAgICAgICBmb3IgKGsgPSAwOyBrIDwgaSAtIDE7IGsrKykKICAgICAgICAgIGxbal1baSAtIDFdIC09IGxbal1ba10gKiB1W2tdW2kgLSAxXTsKICAgICAgICBsW2pdW2kgLSAxXSAvPSB1W2kgLSAxXVtpIC0gMV07CiAgICAgICAgLy8gVeaIkOWIhuOBrueul+WHugogICAgICAgIHVbaV1bal0gPSBhW2ldW2pdOwogICAgICAgIGZvciAoayA9IDA7IGsgPCBpOyBrKyspCiAgICAgICAgICB1W2ldW2pdIC09IGxbaV1ba10gKiB1W2tdW2pdOwogICAgICB9CiAgICB9CiAgfQogIHZvaWQgUHJpbnRNYXRyaXgoVlYmIGEsIGNvbnN0IGNoYXIqIHMpIHsKICAgIHN0ZDo6Y291dCA8PCAiKioqICIgPDwgcyA8PCAiKioqXG4iOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKSB7CiAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbjsgaisrKSB7CiAgICAgICAgc3RkOjpjb3V0IDw8IHN0ZDo6c2V0dygxMSkgPDwgc3RkOjpzZXRwcmVjaXNpb24oNykgPDwgc3RkOjpmaXhlZAogICAgICAgICAgPDwgc3RkOjpzaG93cG9pbnQgPDwgc3RkOjpyaWdodCA8PCBhW2ldW2pdOwogICAgICAgIHN0ZDo6Y291dCA8PCAiICAiOwogICAgICB9CiAgICAgIHN0ZDo6Y291dCA8PCAnXG4nOwogICAgfQogIH0KICAvLyBMVeWIhuino+OCkuWIqeeUqOOBl+OBpumAhuihjOWIl+OCkuaxguOCgeOCiwogIHZvaWQgTFVJbnYoVlYmIGwsIFZWJiB1LCBWViYgeCkgewogICAgaW50IGksIGosIGs7CiAgICBkb3VibGUgcjsKICAgIFZWIGx1OwoKICAgIC8vIOS4iuS4ieinkuihjOWIl+OBqOS4i+S4ieinkuihjOWIl+OCkuWQiOaIkOOBmeOCiwogICAgTWFrZVNxdWFyZU1hdHJpeChsdSk7CgogICAgZm9yIChpID0gMDsgaSA8IG47IGkrKykKICAgICAgZm9yIChqID0gMDsgaiA8IG47IGorKykKICAgICAgICBsdVtpXVtqXSA9IChpIDw9IGopID8gdVtpXVtqXSA6IGxbaV1bal07CgogICAgLy8g6YCG6KGM5YiX44KS5rGC44KB44KLCiAgICBmb3IgKGsgPSAwOyBrIDwgbjsgaysrKSB7CiAgICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgICByID0gKGkgPT0gaykgPyAxLjAgOiAwLjA7CiAgICAgICAgZm9yIChqID0gMDsgaiA8IG47IGorKykKICAgICAgICAgIHIgLT0gbHVbaV1bal0gKiB4W2pdW2tdOwogICAgICAgIHhbaV1ba10gPSByOwogICAgICB9CiAgICAgIGZvciAoaSA9IG4gLSAxOyBpID49IDA7IGktLSkgewogICAgICAgIHIgPSB4W2ldW2tdOwogICAgICAgIGZvciAoaiA9IGkgKyAxOyBqIDwgbjsgaisrKQogICAgICAgICAgciAtPSBsdVtpXVtqXSAqIHhbal1ba107CiAgICAgICAgeFtpXVtrXSA9IHIgLyBsdVtpXVtpXTsKICAgICAgfQogICAgfQogIH0KICAvLyDooYzliJfjga7nqY0KICB2b2lkIE1hdE11bChWViYgeiwgVlYmIHgsIFZWJiB5KSB7CiAgICBpbnQgaSwgaiwgazsKICAgIGRvdWJsZSBzOwoKICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgIGZvciAoaiA9IDA7IGogPCBuOyBqKyspIHsKICAgICAgICBzID0gMC4wOwogICAgICBmb3IgKGsgPSAwOyBrIDwgbjsgaysrKQogICAgICAgIHMgKz0geFtpXVtrXSAqIHlba11bal07CiAgICAgIHpbaV1bal0gPSBzOwogICAgfQogIH0KICAvKiDkuInop5LooYzliJfjga7ooYzliJflvI/jga/lr77op5LmiJDliIbjga7nqY0gKi8KICBkb3VibGUgRGV0VHJpYW5ndWxhck1hdHJpeChWViYgYSkgewogICAgZG91YmxlIGRldCA9IDEuMDsKICAgIAogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgIGRldCAqPSBhW2ldW2ldOwogIAogICAgcmV0dXJuIGRldDsKICB9CgpwdWJsaWM6CiAgTFVEZWNvbXBvc2UoaW50IG5uLCBUKiBpbml0KSA6IG4obm4pIHsKICAgIE1ha2VTcXVhcmVNYXRyaXgoYSk7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IG47IGkrKykKICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBuOyBqKyspCiAgICAgICAgYVtpXVtqXSA9IGluaXRbaSAqIG4gKyBqXTsKICAgIE1ha2VTcXVhcmVNYXRyaXgobCk7CiAgICBNYWtlU3F1YXJlTWF0cml4KHUpOwogICAgTWFrZVNxdWFyZU1hdHJpeCh4KTsKICAgIE1ha2VTcXVhcmVNYXRyaXgoeSk7CiAgfQogIHZvaWQgQ2FsY3VsYXRlKCkgewogICAgTFVEZWNvbXAoYSwgbCwgdSk7CiAgICBMVUludihsLCB1LCB4KTsKICAgIE1hdE11bCh5LCBhLCB4KTsKICB9CiAgdm9pZCBQcmludE1hdHJpeCgpIHsKICAgIFByaW50TWF0cml4KGEsICLooYzliJcgQSIpOwogICAgUHJpbnRNYXRyaXgobCwgIuihjOWIlyBMIik7CiAgICBQcmludE1hdHJpeCh1LCAi6KGM5YiXIFUiKTsKICAgIFByaW50TWF0cml4KHgsICLpgIbooYzliJcgWChBXigtMSkpIik7CiAgICBQcmludE1hdHJpeCh5LCAi6KGM5YiXIFkoQSAqIFgpIik7CiAgICBzdGQ6OmNvdXQgPDwgIuihjOWIl+W8jyB8QXwgPSAiIDw8IERldFRyaWFuZ3VsYXJNYXRyaXgobCkgKiBEZXRUcmlhbmd1bGFyTWF0cml4KHUpIDw8IHN0ZDo6ZW5kbDsKICB9Cn07CgppbnQgbWFpbih2b2lkKQp7CiAgZG91YmxlIGExW10gPSB7Mi4wLCAzLjAsIC0xLjAsIDQuMCwgNC4wLCAtMy4wLCAyLjAsIC0zLjAsIDEuMH07CiAgZG91YmxlIGEyW10gPSB7MS4wLCAxLjAsIDAuMCwgMy4wLCAyLjAsIDEuMCwgLTEuMCwgMS4wLCAzLjAsIC0xLjAsIC0xLjAsIDIuMCwgLTEuMCwgMi4wLCAzLjAsIC0yLjB9OwoKICBMVURlY29tcG9zZTxkb3VibGU+IGx1MShOMSwgYTEpOwogIGx1MS5DYWxjdWxhdGUoKTsKICBsdTEuUHJpbnRNYXRyaXgoKTsKCiAgc3RkOjpjb3V0IDw8ICdcbic7CgogIExVRGVjb21wb3NlPGRvdWJsZT4gbHUyKE4yLCBhMik7CiAgbHUyLkNhbGN1bGF0ZSgpOwogIGx1Mi5QcmludE1hdHJpeCgpOwp9Cg==