void SparseMat::solve_upper_triangle(const DoubleVec &rhs, DoubleVec &x) const { // Solve an upper triangular matrix with explicit diagonal elements. // rhs and x can be the same vector. assert(is_upper_triangular(true)); // x_i = (1/U_ii) (rhs_i - \sum_{n=i+1}^M U_in x_n ) // rowno must be an int, not an unsigned int, or else rowno>=0 will // always be true. for(int rowno=int(rhs.size())-1; rowno>=0; rowno--) { const_row_iterator ij=begin(rowno); double diagterm = *ij; if(ij.row() != ij.col() || diagterm == 0.0) throw ErrSetupError("Zero divisor in solve_upper_triangle!"); double sum = rhs[rowno]; for(++ij; ij<end(rowno); ++ij) sum -= (*ij)*x[ij.col()]; x[rowno] = sum/diagterm; } }
void SparseMat::solve_upper_triangle_trans(const DoubleVec &rhs, DoubleVec &x) const { // Solve the transpose of an upper triangular matrix with explicit // diagonal elements. rhs and x can be the same vector. assert(is_upper_triangular(true)); // x_i = (1/U_ii) (rhs_i - \sum_{j=0}^{i-1} U_ji x_j) // Copy rhs into x. This does all of the rhs_i terms. if(&x[0] != &rhs[0]) x = rhs; for(unsigned int i=0; i<x.size(); i++) { const_row_iterator ji=begin(i); // loop over i^th col of the transpose // We're already done with the sums for x_i. if(ji.row() != ji.col() || *ji == 0.0) throw ErrSetupError("Zero divisor in solve_upper_triangle_trans!"); x[i] /= *ji; // divide by the diagonal // Accumulate contributions to later x[i]'s. for(++ji; ji<end(i); ++ji) x[ji.col()] -= (*ji) * x[i]; } }
void inv(A&& a, C&& c) { // The inverse of a permutation matrix is its transpose if (is_permutation_matrix(a)) { c = transpose(a); return; } const auto n = etl::dim<0>(a); // Use forward propagation for lower triangular matrix if (is_lower_triangular(a)) { c = 0; // The column in c for (size_t s = 0; s < n; ++s) { // The row in a for (size_t row = 0; row < n; ++row) { auto b = row == s ? 1.0 : 0.0; if (row == 0) { c(0, s) = b / a(0, 0); } else { value_t<A> acc(0); // The column in a for (size_t col = 0; col < row; ++col) { acc += a(row, col) * c(col, s); } c(row, s) = (b - acc) / a(row, row); } } } return; } // Use backward propagation for upper triangular matrix if (is_upper_triangular(a)) { c = 0; // The column in c for (int64_t s = n - 1; s >= 0; --s) { // The row in a for (int64_t row = n - 1; row >= 0; --row) { auto b = row == s ? 1.0 : 0.0; if (row == int64_t(n) - 1) { c(row, s) = b / a(row, row); } else { value_t<A> acc(0); // The column in a for (int64_t col = n - 1; col > row; --col) { acc += a(row, col) * c(col, s); } c(row, s) = (b - acc) / a(row, row); } } } return; } auto L = force_temporary_dim_only(a); auto U = force_temporary_dim_only(a); auto P = force_temporary_dim_only(a); etl::lu(a, L, U, P); c = inv(U) * inv(L) * P; }