#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cassert>
#include <cmath>
enum ErrorCode { None = 0, Singular, BadFormat, NotFound };
class Exception {
enum ErrorCode ErrorCode;
public:
Exception() : ErrorCode(None) {}
Exception(enum ErrorCode e) : ErrorCode(e) {}
enum ErrorCode getErrorCode() { return ErrorCode; }
};
class Matrix {
public:
int n;
std::vector<std::vector<double> > m;
Matrix() : n(0) { m.clear(); };
Matrix(int n, double diag);
void readFromFile(char const *filename);
friend std::ostream &operator<<(std::ostream &stream, Matrix m);
friend Matrix operator*(Matrix &a, Matrix &b);
};
Matrix::Matrix(int n, double diag) {
this->n = n;
std::vector<double> v;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
if (i == j)
v.push_back(diag);
else
v.push_back(0.0);
m.push_back(v);
v.clear();
}
}
void Matrix::readFromFile(char const *filename) {
std::ifstream fin(filename);
if(fin) {
std::vector<double> line;
std::string buff;
int index = 0;
while (getline(fin, buff)) {
double data;
std::stringstream ss;
ss << buff;
int i;
for (i = 0; ss >> data; i++) {
line.push_back(data);
ss.ignore();
}
m.push_back(line);
line.clear();
if (index == 0) {
this->n = i;
} else if (i != this->n) {
std::cerr << "line: " << index << "'s colomn num is not " << this->n << " but " << i << std::endl;
throw Exception();
} else if (index >= this->n) {
std::cerr << "line: " << index << " is too large: " << this->n << std::endl;
throw Exception();
}
index++;
}
fin.close();
} else {
throw Exception(NotFound);
}
}
std::ostream &operator<<(std::ostream &stream, Matrix m) {
std::vector<std::vector<double> >::iterator p;
std::vector<double>::iterator q;
for (p = m.m.begin(); p != m.m.end(); p++) {
for (q = (*p).begin(); q != (*p).end(); q++)
stream << *q << ", ";
stream << std::endl;
}
return stream;
}
Matrix operator*(Matrix &a, Matrix &b) {
Matrix c(a.n, 0.0);
for (int i = 0; i < a.n; i++)
for (int j = 0; j < b.n; j++) {
double s = 0.0;
for (int k = 0; k < c.n; k++)
s += a.m[i][k] * b.m[k][j];
c.m[i][j] = s;
}
return c;
}
class GaussianEliminationPartial : public Matrix {
public:
void operator()(Matrix &m, Matrix &e) {
assert(m.n == e.n);
/* forward */
for (int i = 0; i < m.n; i++) {
/* partial-pivotting */
double max = std::fabs(m.m[i][i]);
int k = i;
for (int j = i + 1; j < m.n; j++) {
double tmp;
if (max < (tmp = std::fabs(m.m[j][i]))) {
max = tmp;
k = j;
}
}
if (k != i)
for (int j = 0; j < m.n; j++) {
double r;
r = m.m[k][j];
m.m[k][j] = m.m[i][j];
m.m[i][j] = r;
r = e.m[k][j];
e.m[k][j] = e.m[i][j];
e.m[i][j] = r;
}
/* pivotting finished */
if (std::fabs(max) < 1.0e-6) {
throw Exception(Singular);
}
double r;
r = m.m[i][i];
for (int j = 0; j < m.n; j++) {
m.m[i][j] /= r;
e.m[i][j] /= r;
}
for (int j = i + 1; j < m.n; j++) {
if ((r = m.m[j][i]) != 0) {
assert(std::fabs(r) > 0);
for (int k = 0; k < m.n; k++) {
m.m[j][k] /= r;
m.m[j][k] -= m.m[i][k];
e.m[j][k] /= r;
e.m[j][k] -= e.m[i][k];
}
}
}
}
/* backward */
for (int i = m.n - 1; i >= 0; --i) {
for (int j = i - 1; j >= 0; --j) {
e.m[j][0] -= e.m[i][0] * m.m[j][i];
for (int k = 1; k < e.n; k++) {
e.m[j][k] -= e.m[i][k] * m.m[j][i];
}
m.m[j][i] = 0.0;
}
}
}
};
Matrix inverse(Matrix m) {
Matrix e(m.n, 1.0);
GaussianEliminationPartial ge;
ge(/*ref*/m, /*ref*/e);
std::cout << m << '\n' << e << std::endl;
return e;
}
char const *fileName = "matrix.csv";
int main() {
Matrix a, b;
try {
a.readFromFile(fileName);
std::cout << "a = \n" << a << std::endl;
b = inverse(a);
std::cout << "b = \n" << b << std::endl;
std::cout << "a * b = \n" << a * b << std::endl;
} catch (Exception e) {
switch (e.getErrorCode()) {
case NotFound:
std::cerr << "cannnot open the file." << std::endl;
break;
case BadFormat:
std::cerr << "matrix: bad format." << std::endl;
break;
case Singular:
std::cout << "not have an inverse matrix." << std::endl;
break;
default:
std::cout << "Internal Error." << std::endl;
;
}
}
return 0;
}
/* end */