#pragma once #include #include #include #include #include #include #include "Storage.hh" namespace linear { // bool gaussian_elimination(const std::vector >&, const std::vector& ); bool gaussian_elimination_inplace(std::vector >&, std::vector& ); // Class for solving equations of the form Ax = y for x. First call // factorize with the matrix A and then call solve as many times as needed template struct Solver { public: using matrix_type = boost::numeric::ublas::matrix; using vector_type = boost::numeric::ublas::vector; // Initialise the solver with the matrix A bool factorize(const matrix_type& A_); // Solve for Ax = y vector_type solve(const vector_type& y); private: matrix_type A; boost::numeric::ublas::vector P; vector_type x; size_t N; }; template bool Solver::factorize(const matrix_type& A_) { assert(A_.size1() == A_.size2()); N = A_.size1(); A = A_; P.resize(N); // Bring swap and abs into namespace using namespace std; using namespace boost::numeric::ublas; std::iota(P.begin(), P.end(), 0); for (size_t i = 0; i < N; ++i) { T maxA = 0; size_t imax = i; for (size_t k = i; k < N; ++k) { T absA = abs(A(k, i)); if (absA > maxA) { maxA = absA; imax = k; } } if (imax != i) { swap(P(i), P(imax)); //pivoting P swap(row(A, i), row(A, imax)); //pivoting rows of A } if (A(i, i) == 0) return false; for (size_t j = i + 1; j < N; ++j) { A(j, i) /= A(i, i); for (size_t k = i + 1; k < N; ++k) A(j, k) -= A(j, i) * A(i, k); } } return true; } template typename Solver::vector_type Solver::solve(const vector_type& y) { x.resize(y.size()); for (size_t i = 0; i < N; ++i) { x(i) = y(P(i)); for (size_t k = 0; k < i; ++k) x(i) -= A(i, k) * x(k); } for (size_t i = N; i > 0; --i) { for (size_t k = i; k < N; ++k) x(i - 1) -= A(i - 1, k) * x(k); x(i - 1) = x(i - 1) / A(i - 1, i - 1); } return x; } }