In the following we show some examples for solving a system of linear equations using a LU-factorization. The coefficient matrix in all examples will be a regular, square, non-symmetric matrix:
Let us first recall how to apply the LU-factorization for solving the system of linear equations given by
Using Gaussian elimination one can find a permutation matrix P, a lower unit triangular matrix L and an upper triangular matrix U such that
This constitutes the LU factorization of A. Thus, solving Ax=b is equivalent to solving
which can be done in three steps:
Permutation matrix P is defined through row-interchanges carried out during the factorization. Therefore a favorable representation of P is a vector p containing the pivot indices. A pivot vector
documents that during the factorization the i-th row was interchanged with the pi-th row (more formally, p stores a sequence of transpositions and their composition gives the permutation P). An implementation can compute
efficiently in a single loop:
for i = 1,..,n swap b(i) and b(p(i))
Traversing the same loop backwards allows one to compute the inverse permutation
analogously through
for i = n,..,1 swap b(i) and b(p(i))
Note that this means: no extra vector is needed for storing the permutation of b instead vector b gets overwritten with P-1b.
The coefficient matrix A can be overwritten with L and U during the factorization, that is
This is due to the fact that L is a lower unit triangular matrix, that means contains only ones on the diagonal. The total number of floating-point operation is of order .
Brief summary:
LU-factorization Input: A coefficient matrix Output: A overwritten with the LU factorization P integer valued vector containing the pivots
The names of the functions are derived from corresponding LAPACK routines.
template <typename MA, typename MB> int sv(GeMatrix<MA> &A, DenseVector<Array<int> > &P, GeMatrix<MB> &B);
template <typename MA, typename VB> int sv(GeMatrix<MA> &A, DenseVector<Array<int> > &P, DenseVector<VB> &B);
template <typename FS> int trf(GeMatrix<FS> &A, DenseVector<Array<int> > &P);
template <typename MA, typename MB> int trs(Transpose trans, const GeMatrix<MA> &LU, const DenseVector<Array<int> > &P, GeMatrix<MB> &B);
template <typename MA, typename VB> int trs(Transpose trans, const GeMatrix<MA> &LU, const DenseVector<Array<int> > &P, DenseVector<VB> &B);
The examples will briefly cover the following cases:
We choose as coefficient matrix
which is known from the discrete sine transform. Hence we already know what solution we get when choosing
as the right-hand side: That's right, it should be
#include <flens/flens.h> using namespace flens; using namespace std; typedef GeMatrix<FullStorage<double, ColMajor> > DGeMatrix; typedef DenseVector<Array<double> > DDenseVector; typedef DenseVector<Array<int> > IDenseVector; int main() { int n = 4; // setup a coefficient matrix DGeMatrix A(n,n); Index i,j; A(i,j) = sin(M_PI*i*j/(n+1)); // setup a right-hand side DDenseVector b(n); b(i) = sin(M_PI*i/(n+1)) + 3*sin(3*M_PI*i/(n+1)); // display A and b cout << "A = " << A << endl; cout << "b = " << b << endl; // solve A*x = b using a LU decomposition: // b gets overwritten with the solution x // P contains afterwards the pivot indices used in the LU factorization IDenseVector P(n); sv(A, P, b); cout << "x = A^{-1}*b = " << b << endl; }
And here the result:
A = [4, 4] 0.587785 0.951057 0.951057 0.587785 ; 0.951057 0.587785 -0.587785 -0.951057 ; 0.951057 -0.587785 -0.587785 0.951057 ; 0.587785 -0.951057 0.951057 -0.587785 ; b = [ 3.440955 -0.812299 -0.812299 3.440955 ] x = A^{-1}*b = [ 1.000000 -0.000000 3.000000 0.000000 ]