LU decomposition
Template:Short description In numerical analysis and linear algebra, lowerโupper (LU) decomposition or factorization factors a matrix as the product of a lower triangular matrix and an upper triangular matrix (see matrix multiplication and matrix decomposition). The product sometimes includes a permutation matrix as well. LU decomposition can be viewed as the matrix form of Gaussian elimination. Computers usually solve square systems of linear equations using LU decomposition, and it is also a key step when inverting a matrix or computing the determinant of a matrix. It is also sometimes referred to as LR decomposition (factors into left and right triangular matrices). The LU decomposition algorithm for general matrices was introduced by the Polish astronomer Tadeusz Banachiewicz in 1938.[1]
Definitions

Let Template:Mvar be a square matrix. An LU factorization refers to expression of Template:Mvar into product of two factors โ a lower triangular matrix Template:Mvar and an upper triangular matrix Template:Mvar such that Template:Math. Sometimes factorization is impossible without prior reordering of Template:Mvar to prevent division by zero or uncontrolled growth of rounding errors. Hence alternative expression becomes Template:Math, where in formal notation permutation matrix factors Template:Mvar and Template:Mvar indicate permutation of rows (or columns) of Template:Mvar. In theory Template:Mvar (or Template:Mvar) is obtained by permutations of rows (or columns) of the identity matrix; in practice the corresponding permutations are applied directly to rows (or columns) of Template:Mvar.
Matrix Template:Mvar of side Template:Mvar has coefficients while two triangle matrices combined contain Template:Math coefficients, and therefore Template:Mvar coefficients of matrices Template:Mvar are not independent. The convention is to set Template:Mvar unitriangular, i.e. with all Template:Mvar main diagonal elements equal to one. However, setting instead Template:Mvar matrix unitriangular reduces to the same procedure after transpose of matrix product (cf. properties of matrix transposition): After transposition, Template:Math is lower triangle while Template:Math is upper unitriangular factor of Template:Mvar. This demonstrates also, that operations on rows (e.g. pivoting) are equivalent to those on columns of a transposed matrix, and in general choice of row or column algorithm offers no advantage.
In the lower triangular matrix all elements above the main diagonal are zero, in the upper triangular matrix, all the elements below the diagonal are zero. For example, for a Template:Resx matrix Template:Mvar, its LU decomposition looks like this:
Without a proper ordering or permutations in the matrix, the factorization may fail to materialize. For example, it is easy to verify (by expanding the matrix multiplication) that . If , then at least one of and has to be zero, which implies that either Template:Mvar or Template:Mvar is singular. This is impossible if Template:Mvar is nonsingular (invertible). In terms of operations, zeroing/elimination of remaining elements of first column of Template:Mvar involves division of with , impossible if it is 0. This is a procedural problem. It can be removed by simply reordering the rows of Template:Mvar so that the first element of the permuted matrix is nonzero. The same problem in subsequent factorization steps can be removed the same way. For numerical stability against rounding errors/division by small numbers it is important to select of large absolute value (cf. pivoting).
LU through recursion
The above example of Template:Resx matrices demonstrates that matrix product of top row and leftmost columns of involved matrices plays special role for Template:Mvar to succeed. Let us mark consecutive versions of matrices with and then let us write matrix product in such way that these rows and columns are separated from the rest. In doing so we shall use block matrix notation, such that e.g. is an ordinary number, is a row vector and is a column vector and is sub-matrix of matrix without top row and leftmost column. Then we can replace with a block matrix product. Namely it turns out that one can multiply matrix blocks in such way as if they were ordinary numbers, i.e. row times column, except that now their components are sub-matrices, sometimes reduced to scalars or vectors. Thus denotes a vector obtained from after multiplication of each component by a number Template:Nowrap is an outer product of vectors Template:Nowrap i.e. a matrix which first column is Template:Nowrap next is and so on for all components of and is a product of sub-matrices of
From equality of first and last matrices follow final Template:Nowrap Template:Nowrap while matrix becomes updated/replaced with Template:Nowrap Now comes the crucial observation: nothing prevents us to treat the same way as we did with Template:Nowrap repeatedly. If dimension of is Template:Resx, after Template:Math such steps all columns form sub-diagonal part of triangle matrix and all pivots combined with rows form upper triangle matrix Template:Nowrap as required. In the above example Template:Math so only two steps suffice.
The above procedure demonstrates that at no step the top diagonal pivot element of consecutive sub-matrices can be zero. To avoid it columns or rows may be swapped so that becomes nonzero. Such procedure involving permutation is called LUP, decomposition with pivoting.
Permutation of columns corresponds to matrix product where is a permutation matrix, i.e. the identity matrix after the same column permutation. After all steps such LUP decomposition applies to Template:Nowrap Present computation scheme and similar in Cormen et al.Template:Sfnp are examples of Template:Dfni. They demonstrate two general properties of LU factorization: Template:Ordered list Recurrence algorithms are not overly costly in terms of algebraic operations yet they suffer from practical disadvantage due to need to update and store most elements of Template:Mvar at each step. It will be seen that by reordering calculations it is possible to dispose with storage of intermediate values.
LU factorization with partial pivoting
It turns out that a proper permutation of rows (or columns) to select column (or row) absolute maximal pivot Template:Math is sufficient for numerically stable LU factorization, except for known pathological cases. It is called 'Template:Dfni' (LUP): where Template:Mvar and Template:Mvar are again lower and upper triangular matrices, and Template:Mvar and Template:Mvar are corresponding permutation matrices, which, when correspondingly left- and right-multiplied to Template:Mvar, reorder the rows and columns of Template:Mvar. It turns out that all square matrices can be factorized in this form,[2] and the factorization is numerically stable in practice.Template:Sfnp This makes LUP decomposition a useful technique in practice.
A variant called 'Template:Dfni' at each step involves search of maximum element the way rook moves on a chessboard, along column, row, column again and so on till reaching a pivot maximal in both its row and column. It can be proven that for large matrices of random elements its cost of operations at each step is similarly to partial pivoting proportional to the length of matrix side unlike its square for full pivoting.
LU factorization with full pivoting
An 'Template:Dfni' involves both row and column permutations to find absolute maximum element in the whole submatrix: where Template:Mvar, Template:Mvar, and Template:Mvar are defined as before, and Template:Mvar is a permutation matrix that reorders the columns of Template:Mvar.Template:Sfnp
Lower-diagonal-upper (LDU) decomposition
A 'Template:Dfni' (LDU) is a decomposition of the form where Template:Mvar is a diagonal matrix, and Template:Mvar and Template:Mvar are unitriangular matrices, meaning that all the entries on the diagonals of Template:Mvar and Template:Mvar are one.
Rectangular matrices
Above we required that Template:Mvar be a square matrix, but these decompositions can all be generalized to rectangular matrices as well.Template:Sfnmp In that case, Template:Mvar and Template:Mvar are square matrices both of which have the same number of rows as Template:Mvar, and Template:Mvar has exactly the same dimensions as Template:Mvar. 'Upper triangular' should be interpreted as having only zero entries below the main diagonal, which starts at the upper left corner. Similarly, the more precise term for Template:Mvar is that it is the row echelon form of the matrix Template:Mvar.
Example
We factor the following Template:Resx matrix:
One way to find the LU decomposition of this simple matrix would be to simply solve the linear equations by inspection. Expanding the matrix multiplication gives
This system of equations is underdetermined. In this case any two nonzero elements of Template:Mvar and Template:Mvar matrices are parameters of the solution and can be set arbitrarily to any nonzero value. Therefore, to find the unique LU decomposition, it is necessary to put some restriction on Template:Mvar and Template:Mvar matrices. For example, we can conveniently require the lower triangular matrix Template:Mvar to be a unit triangular matrix, so that all the entries of its main diagonal are set to one. Then the system of equations has the following solution:
Substituting these values into the LU decomposition above yields
Existence and uniqueness
Square matrices
Any square matrix Template:Mvar admits LUP and PLU factorizations.[2] If Template:Mvar is invertible, then it admits an LU (or LDU) factorization if and only if all its leading principal minors are nonzeroTemplate:Sfnp[3] (for example does not admit an LU or LDU factorization). If Template:Mvar is a singular matrix of rank Template:Mvar, then it admits an LU factorization if the first Template:Mvar leading principal minors are nonzero, although the converse is not true.Template:Sfnp
If a square, invertible matrix has an LDU factorization (with all diagonal entries of Template:Mvar and Template:Mvar equal to Template:Math), then the factorization is unique.[3] In that case, the LU factorization is also unique if we require that the diagonal of either Template:Mvar or Template:Mvar consists of ones.
In general, any square matrix Template:Math could have one of the following:
- a unique LU factorization (as mentioned above);
- infinitely many LU factorizations if any of the first Template:Math columns are linearly dependent;
- no LU factorization if the first Template:Math columns are linearly independent and at least one leading principal minor is zero.
In Case 3, one can approximate an LU factorization by changing a diagonal entry Template:Mvar to Template:Math to avoid a zero leading principal minor.[4]
Symmetric positive-definite matrices
If Template:Mvar is a symmetric (or Hermitian, if Template:Mvar is complex) positive-definite matrix, we can arrange matters so that Template:Mvar is the conjugate transpose of Template:Mvar. That is, we can write Template:Mvar as
This decomposition is called the Cholesky decomposition. If Template:Mvar is positive definite, then the Cholesky decomposition exists and is unique. Furthermore, computing the Cholesky decomposition is more efficient and numerically more stable than computing some other LU decompositions.
General matrices
For a (not necessarily invertible) matrix over any field, the exact necessary and sufficient conditions under which it has an LU factorization are known. The conditions are expressed in terms of the ranks of certain submatrices. The Gaussian elimination algorithm for obtaining LU decomposition has also been extended to this most general case.Template:Sfnp
Algorithms
Closed formula
When an LDU factorization exists and is unique, there is a closed (explicit) formula for the elements of Template:Mvar, Template:Mvar, and Template:Mvar in terms of ratios of determinants of certain submatrices of the original matrix Template:Mvar.Template:Sfnp In particular, Template:Math, and for Template:Math, Template:Mvar is the ratio of the Template:Mvar-th principal submatrix to the Template:Math-th principal submatrix. Computation of the determinants is computationally expensive, so this explicit formula is not used in practice.
Using Gaussian elimination
The following algorithm is essentially a modified form of Gaussian elimination. Computing an LU decomposition using this algorithm requires Template:Math floating-point operations, ignoring lower-order terms. Partial pivoting adds only a quadratic term; this is not the case for full pivoting.Template:Sfnp
Generalized explanation
Notation
Given an Template:Times matrix Template:Nowrap define as the original, unmodified version of the matrix Template:Mvar. The parenthetical superscript (e.g., Template:Math) of the matrix Template:Mvar is the version of the matrix. The matrix Template:Math is the Template:Mvar matrix in which the elements below the main diagonal have already been eliminated to 0 through Gaussian elimination for the first Template:Mvar columns.
Below is a matrix to observe to help us remember the notation (where each Template:Math represents any real number in the matrix):
Procedure
During this process, we gradually modify the matrix Template:Mvar using row operations until it becomes the matrix Template:Mvar in which all the elements below the main diagonal are equal to zero. During this, we will simultaneously create two separate matrices Template:Mvar and Template:Mvar, such that Template:Math.
We define the final permutation matrix Template:Mvar as the identity matrix which has all the same rows swapped in the same order as the Template:Mvar matrix while it transforms into the matrix Template:Mvar. For our matrix Template:Math, we may start by swapping rows to provide the desired conditions for the Template:Mvar-th column. For example, we might swap rows to perform partial pivoting, or we might do it to set the pivot element Template:Mvar on the main diagonal to a nonzero number so that we can complete the Gaussian elimination.
For our matrix Template:Math, we want to set every element below to zero (where is the element in the Template:Mvar-th column of the main diagonal). We will denote each element below as (where Template:Math). To set to zero, we set Template:Math for each row Template:Mvar. For this operation, Template:Nowrap Once we have performed the row operations for the first Template:Math columns, we have obtained an upper triangular matrix Template:Math which is denoted by Template:Mvar.
We can also create the lower triangular matrix denoted as Template:Mvar, by directly inputting the previously calculated values of Template:Mvar via the formula below.
Example
If we are given the matrix we will choose to implement partial pivoting and thus swap the first and second row so that our matrix Template:Mvar and the first iteration of our Template:Mvar matrix respectively become Once we have swapped the rows, we can eliminate the elements below the main diagonal on the first column by performing such that, Once these rows have been subtracted, we have derived from Template:Math the matrix
Because we are implementing partial pivoting, we swap the second and third rows of our derived matrix and the current version of our Template:Mvar matrix respectively to obtain Now, we eliminate the elements below the main diagonal on the second column by performing Template:Math such that Template:Math. Because no nonzero elements exist below the main diagonal in our current iteration of Template:Mvar after this row subtraction, this row subtraction derives our final Template:Mvar matrix (denoted as Template:Mvar) and final Template:Mvar matrix: After also switching the corresponding rows, we obtain our final Template:Mvar matrix:
Now these matrices have a relation such that Template:Math.
Relations when no rows are swapped
If we did not swap rows at all during this process, we can perform the row operations simultaneously for each column Template:Mvar by setting where is the Template:Times identity matrix with its Template:Mvar-th column replaced by the transposed vector Template:Math.
In other words, the lower triangular matrix
Performing all the row operations for the first Template:Math columns using the formula is equivalent to finding the decomposition Denote Template:Math so that Template:Math.
Now let's compute the sequence of Template:Math. We know that Template:Mvar has the following formula:
If there are two lower triangular matrices with 1s in the main diagonal, and neither have a nonzero item below the main diagonal in the same column as the other, then we can include all nonzero items at their same location in the product of the two matrices. For example:
Finally, multiply Template:Mvar together and generate the fused matrix denoted as Template:Mvar (as previously mentioned). Using the matrix Template:Mvar, we obtain Template:Math.
It is clear that in order for this algorithm to work, one needs to have at each step (see the definition of Template:Mvar. If this assumption fails at some point, one needs to interchange Template:Mvar-th row with another row below it before continuing. This is why an LU decomposition in general looks like Template:Math.
LU Banachiewicz decomposition

Although Banachiewicz (1938) LU decomposition algorithm preceded the advent of programmed electronic computers, it was ready made for direct implementation into code as index swapping, transpose and column by column multiplication remain native built capabilities of the most programming languages and they are handled by compilers alone with little delay of the actual execution. The peculiar matrix notation used by Banachiewicz enabled him to multiply matrices column by column, a convenient feature for mechanical calculations as he could reveal consecutive factors by sliding a ruler to next rows of matrices. For human readers however, his equations are best transformed into standard matrix notation. To obtain from a full matrix Template:Mvar triangle matrices Template:Mvar and Template:Mvar calculations, start by copying top row and leftmost column of Template:Mvar respectively into corresponding positions of matrices Template:Mvar and Template:Mvar. The known unit diagonal elements of Template:Mvar are not stored nor used throughout the whole process. Next calculations continue for the subsequent rows and columns till the bottom right corner of Template:Mvar.
The figure illustrates calculations for 3rd row and column, assuming previous stages were already completed. Involved matrices are named above squares marking their content. Matrix products and subtractions are applied only to elements in the thick frame boxes. Green filled thin frame boxes indicate values already known, from previous stages. Blue boxes indicate places in Template:Mvar and Template:Mvar matrices for storing of results. Note that at each stage the result elements of Template:Mvar need to be divided by the corresponding pivot element on the main diagonal of Template:Mvar. This applies to the leftmost column of Template:Mvar too.
Note that after completion of 3rd stage the involved elements of matrix Template:Mvar are no longer used and neither those from the previous stages. This enables replacement of these elements with the result values of Template:Mvar and Template:Mvar, i.e. execution of LU decomposition Template:Em, so that the whole Template:Mvar is replaced with Template:Mvar and Template:Mvar except for the unit diagonal of Template:Mvar. Banachiewicz LU algorithm is well suited for partial pivoting by choosing the absolute maximum pivot from the newly calculated row of Template:Mvar and subsequently swapping its columns so that it lands on the main diagonal. More details can be figured out from inspection of the enclosed Fortran90 code.
All partial pivoting LU algorithms cost roughly the same amount, of order operations, where Template:Mvar is the number of rows or columns of Template:Mvar.
LU Crout decomposition
Note that the decomposition obtained through this procedure is a Template:Dfni: the main diagonal of Template:Mvar is composed solely of ones. If one would proceed by removing elements Template:Em the main diagonal by adding multiples of the Template:Em (instead of removing elements Template:Em the diagonal by adding multiples of the Template:Em), we would obtain a Crout decomposition, where the main diagonal of Template:Mvar is of ones.
Another (equivalent) way of producing a Crout decomposition of a given matrix Template:Mvar is to obtain a Doolittle decomposition of the transpose of Template:Mvar. Indeed, if Template:Math is the LU-decomposition obtained through the algorithm presented in this section, then by taking Template:Math and Template:Math, we have that Template:Math is a Crout decomposition.
Randomized algorithm
It is possible to find a low rank approximation to an LU decomposition using a randomized algorithm. Given an input matrix Template:Mvar and a desired low rank Template:Mvar, the randomized LU returns permutation matrices Template:Mvar, Template:Mvar and lower/upper trapezoidal matrices Template:Mvar, Template:Mvar of size Template:Times and Template:Times respectively, such that with high probability Template:Math, where Template:Mvar is a constant that depends on the parameters of the algorithm and Template:Math is the Template:Math-th singular value of the input matrix Template:Mvar.[5]
Theoretical complexity
If two matrices of order Template:Mvar can be multiplied in time Template:Math, where Template:Math for some Template:Math, then an LU-decomposition can be computed in time Template:Math.Template:Sfnp This means, for example, that an Template:Math algorithm exists based on the CoppersmithโWinograd algorithm. See also for fast matrix multiplication algorithms article for more details.
Sparse-matrix decomposition
Special algorithms have been developed for factorizing large sparse matrices. These algorithms attempt to find sparse factors Template:Mvar and Template:Mvar. Ideally, the cost of computation is determined by the number of nonzero entries, rather than by the size of the matrix.
These algorithms use the freedom to exchange rows and columns to minimize fill-in (entries that change from an initial zero to a nonzero value during the execution of an algorithm).
General treatment of orderings that minimize fill-in can be addressed using graph theory.
Applications
Solving linear equations
Given a system of linear equations in matrix form
we want to solve the equation for Template:Math, given Template:Mvar and Template:Math. Suppose we have already obtained the LUP decomposition of Template:Mvar such that Template:Math, so Template:Math.
In this case the solution is done in two logical steps:
- First, we solve the equation Template:Math for Template:Math.
- Second, we solve the equation Template:Math for Template:Math.
In both cases we are dealing with triangular matrices (Template:Mvar and Template:Mvar), which can be solved directly by forward and backward substitution without using the Gaussian elimination process (however we do need this process or equivalent to compute the LU decomposition itself).
The above procedure can be repeatedly applied to solve the equation multiple times for different Template:Math. In this case it is faster (and more convenient) to do an LU decomposition of the matrix Template:Mvar once and then solve the triangular matrices for the different Template:Math, rather than using Gaussian elimination each time. The matrices Template:Mvar and Template:Mvar could be thought to have "encoded" the Gaussian elimination process.
The cost of solving a system of linear equations is approximately Template:Math floating-point operations if the matrix Template:Mvar has size Template:Mvar. This makes it twice as fast as algorithms based on QR decomposition, which costs about Template:Math floating-point operations when Householder reflections are used. For this reason, LU decomposition is usually preferred.Template:Sfnp
Inverting a matrix
When solving systems of equations, Template:Math is usually treated as a vector with a length equal to the height of matrix Template:Mvar. In matrix inversion however, instead of vector Template:Math, we have matrix Template:Mvar, where Template:Mvar is an Template:Times matrix, so that we are trying to find a matrix Template:Mvar (also a Template:Times matrix):
We can use the same algorithm presented earlier to solve for each column of matrix Template:Mvar. Now suppose that Template:Mvar is the identity matrix of size Template:Mvar, Template:Mvar. It follows that the result Template:Mvar must be the inverse of Template:Mvar.Template:Sfnp
Computing the determinant
Given the LUP decomposition Template:Math of a square matrix Template:Mvar, the determinant of Template:Mvar can be computed straightforwardly as
The second equation follows from the fact that the determinant of a triangular matrix is simply the product of its diagonal entries, and that the determinant of a permutation matrix is equal to Template:Math where Template:Mvar is the number of row exchanges in the decomposition.
In the case of LU decomposition with full pivoting, Template:Math also equals the right-hand side of the above equation, if we let Template:Mvar be the total number of row and column exchanges.
The same method readily applies to LU decomposition by setting Template:Mvar equal to the identity matrix.
History

The LU decomposition is related to elimination of linear systems of equations, as e.g. described by Ralston.Template:Sfnp The solution of Template:Mvar linear equations in Template:Mvar unknowns by elimination was already known to ancient Chinese.Template:Sfnp Before Gauss many mathematicians in Eurasia were performing and perfecting it yet as the method became relegated to school grade, few of them left any detailed descriptions. Thus the name Gaussian elimination is only a convenient abbreviation of a complex history.
The Polish astronomer Tadeusz Banachiewicz introduced the LU decomposition in 1938.Template:Sfnp About Banachiewicz, Paul Dwyer stated:Template:SfnpTemplate:Page needed Template:Blockquote
BanachiewiczTemplate:Sfnp was the first to consider elimination in terms of matrices and in this way formulated LU decomposition, as demonstrated by his graphic illustration. His calculations follow ordinary matrix ones, yet notation deviates in that he preferred to write one factor transposed, to be able to multiply them mechanically column by column, by sliding ruler down consecutive rows of both (using arithmometer). Combined with swapped order of indices his formulae in modern notation read
where Template:Math; Template:Math; Template:Math refers to Template:Mvar extended with the last column; and the last component of Template:Math is Template:Math. Matrix formulae to calculate rows and columns of LU factors by recursion are given in the remaining part of Banachiewicz's paper as Eq. (2.3) and (2.4) Template:See below. This paper by Banachiewicz contains both derivation of Template:Mvar and Template:Math factors of respectively non-symmetric and symmetric matrices. They are sometimes confused as later publications tend to tie his name solely with the rediscovery of Cholesky decomposition. Banachiewicz himself can be excused of inaction as already next year he suffered from persecution by occupiers, spending three month in the Sachsenhausen Concentration Camp, on release from which he carried himself from a train his collaborator and co-prisoner Antoni Wilk, who died of exhaustion a week later.
Code examples
Fortran90 code example
Module mlu
Implicit None
Integer, Parameter :: SP = Kind(1d0) ! set I/O real precision
Private
Public luban, lusolve
Contains
Subroutine luban (a, tol, g, h, ip, condinv, detnth)
! By Banachiewicz (1938, hereafter B38) LU decomposition method calculates such
! triangles L=G^T, and U=H that square B=A^T=G^TH=LU. Partial pivoting
! by column permutation IP(:) is modern addition.
! Within the code a, g correspond to B38 A^T and G^T, so that a=gh holds.
!
! Normal use is for square A, however for RHS l already known
! input of (A|l)^T yields (L|y^T)^T where x in L^Tx=y is solution of Ax=l.
Real (SP), Intent (In) :: a (:, :)! input matrix A(m,n), n<=m
Real (SP), Intent (In) :: tol ! tolerance for near zero pivot
Real (SP), Intent (Out) :: g (size(a,dim=1), size(a,dim=2)) ! L(m,n)
Real (SP), Intent (Out) :: h (size(a,dim=2), size(a,dim=2)) ! U(n,n)
! note U columns are permuted
Real (SP), Intent (Out) :: condinv ! 1/cond(A), 0 for singular A
Real (SP), Intent (Out) :: detnth ! sign*Abs(det(A))**(1/n)
Integer, Intent (Out) :: ip (size(a, dim=2)) ! columns permutation
!
Integer :: k, n, j, l, isig
Real (SP) :: tol0, pivmax, pivmin, piv
!
n = size (a, dim=2)
tol0 = Max (tol, 3._SP*epsilon(tol0))! use default for tol=0
!
! Rectangular A and G are permitted under condition:
If (n > size(a, dim=1) .Or. n < 1) Stop 91
Forall (k=1:n) ip (k) = k
h = 0._SP
g = 0._SP
isig = 1
detnth = 0._SP
pivmax = Maxval (Abs (a(1, :)))
pivmin = pivmax
!
Do k = 1, n
! Banachiewicz (1938) Eq. (2.3)
h(k, ip(k:)) = a(k, ip(k:)) - Matmul(g(k, :k-1), h(:k-1, ip(k:)))
!
! Find row pivot
j = (Maxloc(Abs(h(k, ip(k:))), dim=1) + k-1)
If (j /= k) Then ! Swap columns j and k
isig = - isig ! Change Det(A) sign because of permutation
l = ip (k)
ip (k) = ip (j)
ip (j) = l
End If
piv = Abs (h(k, ip(k)))
pivmax = Max (piv, pivmax) ! Adjust condinv
pivmin = Min (piv, pivmin)
If (piv < tol0) Then ! singular matrix
isig = 0
pivmax = 1._SP
Exit
Else ! Account for pivot contribution to Det(A) sign and value
If (h(k, ip(k)) < 0._SP) isig = - isig
detnth = detnth + Log (piv)
End If
!
! Transposed Banachiewicz (1938) Eq. (2.4)
g (k+1:, k) = (a(k+1:, ip(k)) - &
Matmul(g(k+1:, :k-1), h(:k-1, ip(k)))) / h (k, ip(k))
g (k, k) = 1._SP
End Do
!
detnth = isig * Exp (detnth/n)
condinv = Abs (isig) * pivmin / pivmax
! Test for square A(n,n) by uncommenting below
! Print *, '|AQ-LU| ',Maxval (Abs(a(:,ip(:))-Matmul(g, h(:,ip(:)))))
End Subroutine luban
Subroutine lusolve(l,u,ip,x)
! Solves Ax=b system using triangle factors LU=A
Real (SP), Intent (In) :: l (:, :) ! lower triangle matrix L(n,n)
Real (SP), Intent (In) :: u (:, :) ! upper triangle matrix U(n,n)
Integer, Intent (In) :: ip (:) ! columns permutation IP(n)
Real (SP), Intent (InOut) :: x (:, :) ! Input: m sets of RHSs B(n,m),
! Output: the corresponding sets of unknowns X(n,m)
Integer :: n, m, i, j
n = size(ip)
m = size(x, dim=2)
If (n<1.Or.m<1.Or.Any([n,n]/=shape(l)).Or.Any(shape(l)/=shape(u)).Or. &
n/=size(x,dim=1)) Stop 91
Do i = 1, m
Do j = 1, n
x(j,i) = x(j,i)-dot_product(x(:j-1,i),l(j,:j-1))
End Do
Do j = n, 1, -1
x(j,i) = (x(j,i)-dot_product(x(j+1:,i),u(j,ip(j+1:)))) / &
u(j,ip(j))
End Do
End Do
End Subroutine lusolve
End Module mlu
C code example
/* INPUT: A - array of pointers to rows of a square matrix having dimension N
* Tol - small tolerance number to detect failure when the matrix is near degenerate
* OUTPUT: Matrix A is changed, it contains a copy of both matrices L-E and U as A=(L-E)+U such that P*A=L*U.
* The permutation matrix is not stored as a matrix, but in an integer vector P of size N+1
* containing column indexes where the permutation matrix has "1". The last element P[N]=S+N,
* where S is the number of row exchanges needed for determinant computation, det(P)=(-1)^S
*/
int LUPDecompose(double **A, int N, double Tol, int *P) {
int i, j, k, imax;
double maxA, *ptr, absA;
for (i = 0; i <= N; i++)
P[i] = i; //Unit permutation matrix, P[N] initialized with N
for (i = 0; i < N; i++) {
maxA = 0.0;
imax = i;
for (k = i; k < N; k++)
if ((absA = fabs(A[k][i])) > maxA) {
maxA = absA;
imax = k;
}
if (maxA < Tol) return 0; //failure, matrix is degenerate
if (imax != i) {
//pivoting P
j = P[i];
P[i] = P[imax];
P[imax] = j;
//pivoting rows of A
ptr = A[i];
A[i] = A[imax];
A[imax] = ptr;
//counting pivots starting from N (for determinant)
P[N]++;
}
for (j = i + 1; j < N; j++) {
A[j][i] /= A[i][i];
for (k = i + 1; k < N; k++)
A[j][k] -= A[j][i] * A[i][k];
}
}
return 1; //decomposition done
}
/* INPUT: A,P filled in LUPDecompose; b - rhs vector; N - dimension
* OUTPUT: x - solution vector of A*x=b
*/
void LUPSolve(double **A, int *P, double *b, int N, double *x) {
for (int i = 0; i < N; i++) {
x[i] = b[P[i]];
for (int k = 0; k < i; k++)
x[i] -= A[i][k] * x[k];
}
for (int i = N - 1; i >= 0; i--) {
for (int k = i + 1; k < N; k++)
x[i] -= A[i][k] * x[k];
x[i] /= A[i][i];
}
}
/* INPUT: A,P filled in LUPDecompose; N - dimension
* OUTPUT: IA is the inverse of the initial matrix
*/
void LUPInvert(double **A, int *P, int N, double **IA) {
for (int j = 0; j < N; j++) {
for (int i = 0; i < N; i++) {
IA[i][j] = P[i] == j ? 1.0 : 0.0;
for (int k = 0; k < i; k++)
IA[i][j] -= A[i][k] * IA[k][j];
}
for (int i = N - 1; i >= 0; i--) {
for (int k = i + 1; k < N; k++)
IA[i][j] -= A[i][k] * IA[k][j];
IA[i][j] /= A[i][i];
}
}
}
/* INPUT: A,P filled in LUPDecompose; N - dimension.
* OUTPUT: Function returns the determinant of the initial matrix
*/
double LUPDeterminant(double **A, int *P, int N) {
double det = A[0][0];
for (int i = 1; i < N; i++)
det *= A[i][i];
return (P[N] - N) % 2 == 0 ? det : -det;
}
C# code example
public class SystemOfLinearEquations
{
public double[] SolveUsingLU(double[,] matrix, double[] rightPart, int n)
{
// decomposition of matrix
double[,] lu = new double[n, n];
double sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
sum = 0;
for (int k = 0; k < i; k++)
sum += lu[i, k] * lu[k, j];
lu[i, j] = matrix[i, j] - sum;
}
for (int j = i + 1; j < n; j++)
{
sum = 0;
for (int k = 0; k < i; k++)
sum += lu[j, k] * lu[k, i];
lu[j, i] = (1 / lu[i, i]) * (matrix[j, i] - sum);
}
}
// lu = L+U-I
// find solution of Ly = b
double[] y = new double[n];
for (int i = 0; i < n; i++)
{
sum = 0;
for (int k = 0; k < i; k++)
sum += lu[i, k] * y[k];
y[i] = rightPart[i] - sum;
}
// find solution of Ux = y
double[] x = new double[n];
for (int i = n - 1; i >= 0; i--)
{
sum = 0;
for (int k = i + 1; k < n; k++)
sum += lu[i, k] * x[k];
x[i] = (1 / lu[i, i]) * (y[i] - sum);
}
return x;
}
}
MATLAB code example
function LU = LUDecompDoolittle(A)
n = length(A);
LU = A;
for k = 2:n
for i = 1 : k-1
lamda = LU(k,i) / LU (i, i);
LU(k,i) = lamda;
LU(k,i+1:n) = LU(k,i+1:n) - LU(i,i+1:n) * lamda;
end
end
end
function x = SolveLinearSystem(LU, B)
n = length(LU);
y = zeros(size(B));
% find solution of Ly = B
for i = 1:n
y(i,:) = B(i,:) - LU(i,1:i)*y(1:i,:);
end
% find solution of Ux = y
x = zeros(size(B));
for i = n:(-1):1
x(i,:) = (y(i,:) - LU(i,(i + 1):n)*x((i + 1):n,:))/LU(i, i);
end
end
A = [ 4 3 3; 6 3 3; 3 4 3 ]
LU = LUDecompDoolittle(A)
B = [ 1 2 3; 4 5 6; 7 8 9; 10 11 12 ]'
x = SolveLinearSystem(LU, B)
A * x
See also
- Block LU decomposition
- Bruhat decomposition
- Cholesky decomposition
- Crout matrix decomposition
- Incomplete LU factorization
- LU Reduction
- Matrix decomposition
- QR decomposition
Notes
References
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation. See Section 3.5. N โ 1
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation.
- Template:Citation
External links
References
- LU decomposition on MathWorld.
- LU decomposition on Math-Linux.
- LU decomposition at Holistic Numerical Methods Institute
- LU matrix factorization. MATLAB reference.
Computer code
- LAPACK is a collection of FORTRAN subroutines for solving dense linear algebra problems
- ALGLIB includes a partial port of the LAPACK to C++, C#, Delphi, etc.
- C++ code, Prof. J. Loomis, University of Dayton
- C code, Mathematics Source Library
- Rust code
- LU in X10
Online resources
- Template:Deprecated archive
- Matrix Calculator with steps, including LU decomposition,
- LU Decomposition Tool, uni-bonn.de
- LU Decomposition by Ed Pegg, Jr., The Wolfram Demonstrations Project, 2007.