mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-13 04:09:10 +08:00
Complete LU documentation
This commit is contained in:
parent
17ec407ccd
commit
f04c1cb774
2
Eigen/LU
2
Eigen/LU
@ -6,7 +6,7 @@
|
|||||||
namespace Eigen {
|
namespace Eigen {
|
||||||
|
|
||||||
/** \defgroup LU_Module LU module
|
/** \defgroup LU_Module LU module
|
||||||
* This module includes LU decomposition and related notions such as matrix inversion and determinant.
|
* This module includes %LU decomposition and related notions such as matrix inversion and determinant.
|
||||||
* This module defines the following MatrixBase methods:
|
* This module defines the following MatrixBase methods:
|
||||||
* - MatrixBase::inverse()
|
* - MatrixBase::inverse()
|
||||||
* - MatrixBase::determinant()
|
* - MatrixBase::determinant()
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
// License and a copy of the GNU General Public License along with
|
// License and a copy of the GNU General Public License along with
|
||||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef EIGEN_INVERSEPRODUCT_H
|
#ifndef EIGEN_SOLVETRIANGULAR_H
|
||||||
#define EIGEN_INVERSEPRODUCT_H
|
#define EIGEN_SOLVETRIANGULAR_H
|
||||||
|
|
||||||
template<typename XprType> struct ei_is_part { enum {value=false}; };
|
template<typename XprType> struct ei_is_part { enum {value=false}; };
|
||||||
template<typename XprType, unsigned int Mode> struct ei_is_part<Part<XprType,Mode> > { enum {value=true}; };
|
template<typename XprType, unsigned int Mode> struct ei_is_part<Part<XprType,Mode> > { enum {value=true}; };
|
||||||
@ -251,4 +251,4 @@ typename OtherDerived::Eval MatrixBase<Derived>::solveTriangular(const MatrixBas
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // EIGEN_INVERSEPRODUCT_H
|
#endif // EIGEN_SOLVETRIANGULAR_H
|
||||||
|
@ -29,17 +29,30 @@
|
|||||||
*
|
*
|
||||||
* \class LU
|
* \class LU
|
||||||
*
|
*
|
||||||
* \brief LU decomposition of a matrix with complete pivoting, and associated features
|
* \brief LU decomposition of a matrix with complete pivoting, and related features
|
||||||
*
|
*
|
||||||
* \param MatrixType the type of the matrix of which we are computing the LU decomposition
|
* \param MatrixType the type of the matrix of which we are computing the LU decomposition
|
||||||
*
|
*
|
||||||
* This class performs a LU decomposition of any matrix, with complete pivoting: the matrix A
|
* This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A
|
||||||
* is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q
|
* is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q
|
||||||
* are permutation matrices.
|
* are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues of U are
|
||||||
|
* in non-increasing order.
|
||||||
*
|
*
|
||||||
* This decomposition provides the generic approach to solving systems of linear equations, computing
|
* This decomposition provides the generic approach to solving systems of linear equations, computing
|
||||||
* the rank, invertibility, inverse, kernel, and determinant.
|
* the rank, invertibility, inverse, kernel, and determinant.
|
||||||
*
|
*
|
||||||
|
* The data of the LU decomposition can be directly accessed through the methods matrixLU(),
|
||||||
|
* permutationP(), permutationQ(). Convenience methods matrixL(), matrixU() are also provided.
|
||||||
|
*
|
||||||
|
* As an exemple, here is how the original matrix can be retrieved, in the square case:
|
||||||
|
* \include class_LU_1.cpp
|
||||||
|
* Output: \verbinclude class_LU_1.out
|
||||||
|
*
|
||||||
|
* When the matrix is not square, matrixL() is no longer very useful: if one needs it, one has
|
||||||
|
* to construct the L matrix by hand, as shown in this example:
|
||||||
|
* \include class_LU_2.cpp
|
||||||
|
* Output: \verbinclude class_LU_2.out
|
||||||
|
*
|
||||||
* \sa MatrixBase::lu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse()
|
* \sa MatrixBase::lu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse()
|
||||||
*/
|
*/
|
||||||
template<typename MatrixType> class LU
|
template<typename MatrixType> class LU
|
||||||
@ -58,91 +71,220 @@ template<typename MatrixType> class LU
|
|||||||
MatrixType::MaxRowsAtCompileTime)
|
MatrixType::MaxRowsAtCompileTime)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Constructor.
|
||||||
|
*
|
||||||
|
* \param matrix the matrix of which to compute the LU decomposition.
|
||||||
|
*/
|
||||||
LU(const MatrixType& matrix);
|
LU(const MatrixType& matrix);
|
||||||
|
|
||||||
|
/** \returns the LU decomposition matrix: the upper-triangular part is U, the
|
||||||
|
* unit-lower-triangular part is L (at least for square matrices; in the non-square
|
||||||
|
* case, special care is needed, see the documentation of class LU).
|
||||||
|
*
|
||||||
|
* \sa matrixL(), matrixU()
|
||||||
|
*/
|
||||||
inline const MatrixType& matrixLU() const
|
inline const MatrixType& matrixLU() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns an expression of the unit-lower-triangular part of the LU matrix. In the square case,
|
||||||
|
* this is the L matrix. In the non-square, actually obtaining the L matrix takes some
|
||||||
|
* more care, see the documentation of class LU.
|
||||||
|
*
|
||||||
|
* \sa matrixLU(), matrixU()
|
||||||
|
*/
|
||||||
inline const Part<MatrixType, UnitLower> matrixL() const
|
inline const Part<MatrixType, UnitLower> matrixL() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns an expression of the U matrix, i.e. the upper-triangular part of the LU matrix.
|
||||||
|
*
|
||||||
|
* \note The eigenvalues of U are sorted in non-increasing order.
|
||||||
|
*
|
||||||
|
* \sa matrixLU(), matrixL()
|
||||||
|
*/
|
||||||
inline const Part<MatrixType, Upper> matrixU() const
|
inline const Part<MatrixType, Upper> matrixU() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed,
|
||||||
|
* representing the P permutation i.e. the permutation of the rows. For its precise meaning,
|
||||||
|
* see the examples given in the documentation of class LU.
|
||||||
|
*
|
||||||
|
* \sa permutationQ()
|
||||||
|
*/
|
||||||
inline const IntColVectorType& permutationP() const
|
inline const IntColVectorType& permutationP() const
|
||||||
{
|
{
|
||||||
return m_p;
|
return m_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns a vector of integers, whose size is the number of columns of the matrix being
|
||||||
|
* decomposed, representing the Q permutation i.e. the permutation of the columns.
|
||||||
|
* For its precise meaning, see the examples given in the documentation of class LU.
|
||||||
|
*
|
||||||
|
* \sa permutationP()
|
||||||
|
*/
|
||||||
inline const IntRowVectorType& permutationQ() const
|
inline const IntRowVectorType& permutationQ() const
|
||||||
{
|
{
|
||||||
return m_q;
|
return m_q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Computes the kernel of the matrix.
|
||||||
|
*
|
||||||
|
* \note: this method is only allowed on non-invertible matrices, as determined by
|
||||||
|
* isInvertible(). Calling it on an invertible matrice will make an assertion fail.
|
||||||
|
*
|
||||||
|
* \param result a pointer to the matrix in which to store the kernel. The columns of this
|
||||||
|
* matrix will be set to form a basis of the kernel (it will be resized
|
||||||
|
* if necessary).
|
||||||
|
*
|
||||||
|
* Example: \include LU_computeKernel.cpp
|
||||||
|
* Output: \verbinclude LU_computeKernel.out
|
||||||
|
*
|
||||||
|
* \sa kernel()
|
||||||
|
*/
|
||||||
void computeKernel(Matrix<typename MatrixType::Scalar,
|
void computeKernel(Matrix<typename MatrixType::Scalar,
|
||||||
MatrixType::ColsAtCompileTime, Dynamic,
|
MatrixType::ColsAtCompileTime, Dynamic,
|
||||||
MatrixType::MaxColsAtCompileTime,
|
MatrixType::MaxColsAtCompileTime,
|
||||||
LU<MatrixType>::MaxSmallDimAtCompileTime
|
LU<MatrixType>::MaxSmallDimAtCompileTime
|
||||||
> *result) const;
|
> *result) const;
|
||||||
|
|
||||||
const Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, Dynamic,
|
/** \returns the kernel of the matrix. The columns of the returned matrix
|
||||||
|
* will form a basis of the kernel.
|
||||||
|
*
|
||||||
|
* \note: this method is only allowed on non-invertible matrices, as determined by
|
||||||
|
* isInvertible(). Calling it on an invertible matrice will make an assertion fail.
|
||||||
|
*
|
||||||
|
* \note: this method returns a matrix by value, which induces some inefficiency.
|
||||||
|
* If you prefer to avoid this overhead, use computeKernel() instead.
|
||||||
|
*
|
||||||
|
* Example: \include LU_kernel.cpp
|
||||||
|
* Output: \verbinclude LU_kernel.out
|
||||||
|
*
|
||||||
|
* \sa computeKernel()
|
||||||
|
*/ const Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, Dynamic,
|
||||||
MatrixType::MaxColsAtCompileTime,
|
MatrixType::MaxColsAtCompileTime,
|
||||||
LU<MatrixType>::MaxSmallDimAtCompileTime> kernel() const;
|
LU<MatrixType>::MaxSmallDimAtCompileTime> kernel() const;
|
||||||
|
|
||||||
|
/** This method finds a solution x to the equation Ax=b, where A is the matrix of which
|
||||||
|
* *this is the LU decomposition, if any exists.
|
||||||
|
*
|
||||||
|
* \param b the right-hand-side of the equation to solve. Can be a vector or a matrix,
|
||||||
|
* the only requirement in order for the equation to make sense is that
|
||||||
|
* b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition.
|
||||||
|
* \param result a pointer to the vector or matrix in which to store the solution, if any exists.
|
||||||
|
* Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols().
|
||||||
|
* If no solution exists, *result is left with undefined coefficients.
|
||||||
|
*
|
||||||
|
* \returns true if any solution exists, false if no solution exists.
|
||||||
|
*
|
||||||
|
* \note If there exist more than one solution, this method will arbitrarily choose one.
|
||||||
|
* If you need a complete analysis of the space of solutions, take the one solution obtained * by this method and add to it elements of the kernel, as determined by kernel().
|
||||||
|
*
|
||||||
|
* Example: \include LU_solve.cpp
|
||||||
|
* Output: \verbinclude LU_solve.out
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::solveTriangular(), kernel(), computeKernel(), inverse(), computeInverse()
|
||||||
|
*/
|
||||||
template<typename OtherDerived, typename ResultType>
|
template<typename OtherDerived, typename ResultType>
|
||||||
bool solve(
|
bool solve(
|
||||||
const MatrixBase<OtherDerived>& b,
|
const MatrixBase<OtherDerived>& b,
|
||||||
ResultType *result
|
ResultType *result
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/** \returns the determinant of the matrix of which
|
||||||
* This method returns the determinant of the matrix of which
|
|
||||||
* *this is the LU decomposition. It has only linear complexity
|
* *this is the LU decomposition. It has only linear complexity
|
||||||
* (that is, O(n) where n is the dimension of the square matrix)
|
* (that is, O(n) where n is the dimension of the square matrix)
|
||||||
* as the LU decomposition has already been computed.
|
* as the LU decomposition has already been computed.
|
||||||
*
|
*
|
||||||
* Warning: a determinant can be very big or small, so for matrices
|
* \note This is only for square matrices.
|
||||||
* of large enough dimension (like a 50-by-50 matrix) there is a risk of
|
*
|
||||||
* overflow/underflow.
|
* \note For fixed-size matrices of size up to 4, MatrixBase::determinant() offers
|
||||||
|
* optimized paths.
|
||||||
|
*
|
||||||
|
* \warning a determinant can be very big or small, so for matrices
|
||||||
|
* of large enough dimension, there is a risk of overflow/underflow.
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::determinant()
|
||||||
*/
|
*/
|
||||||
typename ei_traits<MatrixType>::Scalar determinant() const;
|
typename ei_traits<MatrixType>::Scalar determinant() const;
|
||||||
|
|
||||||
|
/** \returns the rank of the matrix of which *this is the LU decomposition.
|
||||||
|
*
|
||||||
|
* \note This is computed at the time of the construction of the LU decomposition. This
|
||||||
|
* method does not perform any further computation.
|
||||||
|
*/
|
||||||
inline int rank() const
|
inline int rank() const
|
||||||
{
|
{
|
||||||
return m_rank;
|
return m_rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns the dimension of the kernel of the matrix of which *this is the LU decomposition.
|
||||||
|
*
|
||||||
|
* \note Since the rank is computed at the time of the construction of the LU decomposition, this
|
||||||
|
* method almost does not perform any further computation.
|
||||||
|
*/
|
||||||
inline int dimensionOfKernel() const
|
inline int dimensionOfKernel() const
|
||||||
{
|
{
|
||||||
return m_lu.cols() - m_rank;
|
return m_lu.cols() - m_rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns true if the matrix of which *this is the LU decomposition represents an injective
|
||||||
|
* linear map, i.e. has trivial kernel; false otherwise.
|
||||||
|
*
|
||||||
|
* \note Since the rank is computed at the time of the construction of the LU decomposition, this
|
||||||
|
* method almost does not perform any further computation.
|
||||||
|
*/
|
||||||
inline bool isInjective() const
|
inline bool isInjective() const
|
||||||
{
|
{
|
||||||
return m_rank == m_lu.cols();
|
return m_rank == m_lu.cols();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns true if the matrix of which *this is the LU decomposition represents a surjective
|
||||||
|
* linear map; false otherwise.
|
||||||
|
*
|
||||||
|
* \note Since the rank is computed at the time of the construction of the LU decomposition, this
|
||||||
|
* method almost does not perform any further computation.
|
||||||
|
*/
|
||||||
inline bool isSurjective() const
|
inline bool isSurjective() const
|
||||||
{
|
{
|
||||||
return m_rank == m_lu.rows();
|
return m_rank == m_lu.rows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns true if the matrix of which *this is the LU decomposition is invertible.
|
||||||
|
*
|
||||||
|
* \note Since the rank is computed at the time of the construction of the LU decomposition, this
|
||||||
|
* method almost does not perform any further computation.
|
||||||
|
*/
|
||||||
inline bool isInvertible() const
|
inline bool isInvertible() const
|
||||||
{
|
{
|
||||||
return isInjective() && isSurjective();
|
return isInjective() && isSurjective();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Computes the inverse of the matrix of which *this is the LU decomposition.
|
||||||
|
*
|
||||||
|
* \param result a pointer to the matrix into which to store the inverse. Resized if needed.
|
||||||
|
*
|
||||||
|
* \note If this matrix is not invertible, *result is left with undefined coefficients.
|
||||||
|
* Use isInvertible() to first determine whether this matrix is invertible.
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::computeInverse(), inverse()
|
||||||
|
*/
|
||||||
inline void computeInverse(MatrixType *result) const
|
inline void computeInverse(MatrixType *result) const
|
||||||
{
|
{
|
||||||
solve(MatrixType::Identity(m_lu.rows(), m_lu.cols()), result);
|
solve(MatrixType::Identity(m_lu.rows(), m_lu.cols()), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns the inverse of the matrix of which *this is the LU decomposition.
|
||||||
|
*
|
||||||
|
* \note If this matrix is not invertible, the returned matrix has undefined coefficients.
|
||||||
|
* Use isInvertible() to first determine whether this matrix is invertible.
|
||||||
|
*
|
||||||
|
* \sa computeInverse(), MatrixBase::inverse()
|
||||||
|
*/
|
||||||
inline MatrixType inverse() const
|
inline MatrixType inverse() const
|
||||||
{
|
{
|
||||||
MatrixType result;
|
MatrixType result;
|
||||||
|
10
doc/snippets/LU_computeKernel.cpp
Normal file
10
doc/snippets/LU_computeKernel.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
MatrixXf m = MatrixXf::Random(3,5);
|
||||||
|
cout << "Here is the matrix m:" << endl << m << endl;
|
||||||
|
LU<MatrixXf> lu(m);
|
||||||
|
// allocate the matrix ker with the correct size to avoid reallocation
|
||||||
|
MatrixXf ker(m.rows(), lu.dimensionOfKernel());
|
||||||
|
lu.computeKernel(&ker);
|
||||||
|
cout << "Here is a matrix whose columns form a basis of the kernel of m:"
|
||||||
|
<< endl << ker << endl;
|
||||||
|
cout << "By definition of the kernel, m*ker is zero:"
|
||||||
|
<< endl << m*ker << endl;
|
7
doc/snippets/LU_kernel.cpp
Normal file
7
doc/snippets/LU_kernel.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
MatrixXf m = MatrixXf::Random(3,5);
|
||||||
|
cout << "Here is the matrix m:" << endl << m << endl;
|
||||||
|
MatrixXf ker = m.lu().kernel();
|
||||||
|
cout << "Here is a matrix whose columns form a basis of the kernel of m:"
|
||||||
|
<< endl << ker << endl;
|
||||||
|
cout << "By definition of the kernel, m*ker is zero:"
|
||||||
|
<< endl << m*ker << endl;
|
15
doc/snippets/LU_solve.cpp
Normal file
15
doc/snippets/LU_solve.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
typedef Matrix<float,2,3> Matrix2x3;
|
||||||
|
typedef Matrix<float,3,2> Matrix3x2;
|
||||||
|
Matrix2x3 m = Matrix2x3::Random();
|
||||||
|
Matrix2f y = Matrix2f::Random();
|
||||||
|
cout << "Here is the matrix m:" << endl << m << endl;
|
||||||
|
cout << "Here is the matrix y:" << endl << y << endl;
|
||||||
|
Matrix3x2 x;
|
||||||
|
if(m.lu().solve(y, &x))
|
||||||
|
{
|
||||||
|
assert(y.isApprox(m*x));
|
||||||
|
cout << "Here is a solution x to the equation mx=y:" << endl << x << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cout << "The equation mx=y does not have any solution." << endl;
|
||||||
|
|
12
doc/snippets/class_LU_1.cpp
Normal file
12
doc/snippets/class_LU_1.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Matrix3d m = Matrix3d::Random();
|
||||||
|
cout << "Here is the matrix m:" << endl << m << endl;
|
||||||
|
Eigen::LU<Matrix3d> lu(m);
|
||||||
|
cout << "Here is, up to permutations, its LU decomposition matrix:"
|
||||||
|
<< endl << lu.matrixLU() << endl;
|
||||||
|
cout << "Let us now reconstruct the original matrix m from it:" << endl;
|
||||||
|
Matrix3d x = lu.matrixL() * lu.matrixU();
|
||||||
|
Matrix3d y;
|
||||||
|
for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++)
|
||||||
|
y(i, lu.permutationQ()[j]) = x(lu.permutationP()[i], j);
|
||||||
|
cout << y << endl;
|
||||||
|
assert(y.isApprox(m));
|
18
doc/snippets/class_LU_2.cpp
Normal file
18
doc/snippets/class_LU_2.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
typedef Matrix<double, 5, 3> Matrix5x3;
|
||||||
|
typedef Matrix<double, 5, 5> Matrix5x5;
|
||||||
|
Matrix5x3 m = Matrix5x3::Random();
|
||||||
|
cout << "Here is the matrix m:" << endl << m << endl;
|
||||||
|
Eigen::LU<Matrix5x3> lu(m);
|
||||||
|
cout << "Here is, up to permutations, its LU decomposition matrix:"
|
||||||
|
<< endl << lu.matrixLU() << endl;
|
||||||
|
cout << "Here is the actual L matrix in this decomposition:" << endl;
|
||||||
|
Matrix5x5 l = Matrix5x5::Identity();
|
||||||
|
l.block<5,3>(0,0).part<StrictlyLower>() = lu.matrixLU();
|
||||||
|
cout << l << endl;
|
||||||
|
cout << "Let us now reconstruct the original matrix m:" << endl;
|
||||||
|
Matrix5x3 x = l * lu.matrixU();
|
||||||
|
Matrix5x3 y;
|
||||||
|
for(int i = 0; i < 5; i++) for(int j = 0; j < 3; j++)
|
||||||
|
y(i, lu.permutationQ()[j]) = x(lu.permutationP()[i], j);
|
||||||
|
cout << y << endl;
|
||||||
|
assert(y.isApprox(m));
|
Loading…
x
Reference in New Issue
Block a user