mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-08 09:49:03 +08:00
Add partial pivoting runtime option to LU.
Note: in fact, inverse() always uses partial pivoting because the algo currently used doesn't make sense with complete pivoting. No num stability issue so far even with size 200x200. If there is any problem we can of course reimplement inverse on top of LU.
This commit is contained in:
parent
e741b7beca
commit
09ef7db9d9
@ -526,7 +526,7 @@ template<typename Derived> class MatrixBase
|
|||||||
|
|
||||||
/////////// LU module ///////////
|
/////////// LU module ///////////
|
||||||
|
|
||||||
const LU<EvalType> lu() const;
|
const LU<EvalType> lu(int pivoting) const;
|
||||||
const EvalType inverse() const;
|
const EvalType inverse() const;
|
||||||
void computeInverse(EvalType *result) const;
|
void computeInverse(EvalType *result) const;
|
||||||
Scalar determinant() const;
|
Scalar determinant() const;
|
||||||
|
@ -209,6 +209,11 @@ enum {
|
|||||||
HasDirectAccess = DirectAccessBit
|
HasDirectAccess = DirectAccessBit
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PartialPivoting,
|
||||||
|
CompletePivoting
|
||||||
|
};
|
||||||
|
|
||||||
const int FullyCoherentAccessPattern = 0x1;
|
const int FullyCoherentAccessPattern = 0x1;
|
||||||
const int InnerCoherentAccessPattern = 0x2 | FullyCoherentAccessPattern;
|
const int InnerCoherentAccessPattern = 0x2 | FullyCoherentAccessPattern;
|
||||||
const int OuterCoherentAccessPattern = 0x4 | InnerCoherentAccessPattern;
|
const int OuterCoherentAccessPattern = 0x4 | InnerCoherentAccessPattern;
|
||||||
|
@ -54,29 +54,29 @@ template<typename MatrixType> class LU
|
|||||||
typedef Matrix<int, MatrixType::ColsAtCompileTime, 1> IntRowVectorType;
|
typedef Matrix<int, MatrixType::ColsAtCompileTime, 1> IntRowVectorType;
|
||||||
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
|
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
|
||||||
|
|
||||||
LU(const MatrixType& matrix);
|
LU(const MatrixType& matrix, int pivoting = CompletePivoting);
|
||||||
|
|
||||||
const MatrixType& matrixLU() const
|
inline const MatrixType& matrixLU() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Part<MatrixType, UnitLower> matrixL() const
|
inline const Part<MatrixType, UnitLower> matrixL() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Part<MatrixType, Upper> matrixU() const
|
inline const Part<MatrixType, Upper> matrixU() const
|
||||||
{
|
{
|
||||||
return m_lu;
|
return m_lu;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IntColVectorType& permutationP() const
|
inline const IntColVectorType& permutationP() const
|
||||||
{
|
{
|
||||||
return m_p;
|
return m_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IntRowVectorType& permutationQ() const
|
inline const IntRowVectorType& permutationQ() const
|
||||||
{
|
{
|
||||||
return m_q;
|
return m_q;
|
||||||
}
|
}
|
||||||
@ -92,29 +92,47 @@ template<typename MatrixType> class LU
|
|||||||
* 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
|
* Warning: a determinant can be very big or small, so for matrices
|
||||||
* of large dimension (like a 50-by-50 matrix) there can be a risk of
|
* of large enough dimension (like a 50-by-50 matrix) there is a risk of
|
||||||
* overflow/underflow.
|
* overflow/underflow.
|
||||||
*/
|
*/
|
||||||
typename ei_traits<MatrixType>::Scalar determinant() const;
|
typename ei_traits<MatrixType>::Scalar determinant() const;
|
||||||
|
|
||||||
|
inline int rank() const
|
||||||
|
{
|
||||||
|
return m_rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int dimensionOfKernel() const
|
||||||
|
{
|
||||||
|
return m_lu.cols() - m_rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInvertible() const
|
||||||
|
{
|
||||||
|
return m_rank == m_lu.cols();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatrixType m_lu;
|
MatrixType m_lu;
|
||||||
IntColVectorType m_p;
|
IntColVectorType m_p;
|
||||||
IntRowVectorType m_q;
|
IntRowVectorType m_q;
|
||||||
int m_det_pq;
|
int m_det_pq;
|
||||||
Scalar m_biggest_eigenvalue_of_u;
|
Scalar m_biggest_eigenvalue_of_u;
|
||||||
int m_dimension_of_kernel;
|
int m_rank;
|
||||||
|
int m_pivoting;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
LU<MatrixType>::LU(const MatrixType& matrix)
|
LU<MatrixType>::LU(const MatrixType& matrix, int pivoting)
|
||||||
: m_lu(matrix),
|
: m_lu(matrix),
|
||||||
m_p(matrix.rows()),
|
m_p(matrix.rows()),
|
||||||
m_q(matrix.cols())
|
m_q(matrix.cols()),
|
||||||
|
m_pivoting(pivoting)
|
||||||
{
|
{
|
||||||
const int size = matrix.diagonal().size();
|
const int size = matrix.diagonal().size();
|
||||||
const int rows = matrix.rows();
|
const int rows = matrix.rows();
|
||||||
const int cols = matrix.cols();
|
const int cols = matrix.cols();
|
||||||
|
ei_assert(pivoting == PartialPivoting || pivoting == CompletePivoting);
|
||||||
|
|
||||||
IntColVectorType rows_transpositions(matrix.rows());
|
IntColVectorType rows_transpositions(matrix.rows());
|
||||||
IntRowVectorType cols_transpositions(matrix.cols());
|
IntRowVectorType cols_transpositions(matrix.cols());
|
||||||
@ -123,20 +141,36 @@ LU<MatrixType>::LU(const MatrixType& matrix)
|
|||||||
for(int k = 0; k < size; k++)
|
for(int k = 0; k < size; k++)
|
||||||
{
|
{
|
||||||
int row_of_biggest, col_of_biggest;
|
int row_of_biggest, col_of_biggest;
|
||||||
const Scalar biggest = m_lu.corner(Eigen::BottomRight, rows-k, cols-k)
|
Scalar biggest;
|
||||||
.cwise().abs()
|
if(m_pivoting == CompletePivoting)
|
||||||
.maxCoeff(&row_of_biggest, &col_of_biggest);
|
{
|
||||||
row_of_biggest += k;
|
biggest = m_lu.corner(Eigen::BottomRight, rows-k, cols-k)
|
||||||
col_of_biggest += k;
|
.cwise().abs()
|
||||||
rows_transpositions.coeffRef(k) = row_of_biggest;
|
.maxCoeff(&row_of_biggest, &col_of_biggest);
|
||||||
cols_transpositions.coeffRef(k) = col_of_biggest;
|
row_of_biggest += k;
|
||||||
if(k != row_of_biggest) {
|
col_of_biggest += k;
|
||||||
m_lu.row(k).swap(m_lu.row(row_of_biggest));
|
rows_transpositions.coeffRef(k) = row_of_biggest;
|
||||||
number_of_transpositions++;
|
cols_transpositions.coeffRef(k) = col_of_biggest;
|
||||||
|
if(k != row_of_biggest) {
|
||||||
|
m_lu.row(k).swap(m_lu.row(row_of_biggest));
|
||||||
|
number_of_transpositions++;
|
||||||
|
}
|
||||||
|
if(k != col_of_biggest) {
|
||||||
|
m_lu.col(k).swap(m_lu.col(col_of_biggest));
|
||||||
|
number_of_transpositions++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(k != col_of_biggest) {
|
else // partial pivoting
|
||||||
m_lu.col(k).swap(m_lu.col(col_of_biggest));
|
{
|
||||||
number_of_transpositions++;
|
biggest = m_lu.col(k).end(rows-k)
|
||||||
|
.cwise().abs()
|
||||||
|
.maxCoeff(&row_of_biggest);
|
||||||
|
row_of_biggest += k;
|
||||||
|
rows_transpositions.coeffRef(k) = row_of_biggest;
|
||||||
|
if(k != row_of_biggest) {
|
||||||
|
m_lu.row(k).swap(m_lu.row(row_of_biggest));
|
||||||
|
number_of_transpositions++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const Scalar lu_k_k = m_lu.coeff(k,k);
|
const Scalar lu_k_k = m_lu.coeff(k,k);
|
||||||
if(ei_isMuchSmallerThan(lu_k_k, biggest)) continue;
|
if(ei_isMuchSmallerThan(lu_k_k, biggest)) continue;
|
||||||
@ -151,9 +185,12 @@ LU<MatrixType>::LU(const MatrixType& matrix)
|
|||||||
for(int k = size-1; k >= 0; k--)
|
for(int k = size-1; k >= 0; k--)
|
||||||
std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k)));
|
std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k)));
|
||||||
|
|
||||||
for(int k = 0; k < matrix.cols(); k++) m_q.coeffRef(k) = k;
|
if(pivoting == CompletePivoting)
|
||||||
for(int k = 0; k < size; k++)
|
{
|
||||||
std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k)));
|
for(int k = 0; k < matrix.cols(); k++) m_q.coeffRef(k) = k;
|
||||||
|
for(int k = 0; k < size; k++)
|
||||||
|
std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k)));
|
||||||
|
}
|
||||||
|
|
||||||
m_det_pq = (number_of_transpositions%2) ? -1 : 1;
|
m_det_pq = (number_of_transpositions%2) ? -1 : 1;
|
||||||
|
|
||||||
@ -161,14 +198,15 @@ LU<MatrixType>::LU(const MatrixType& matrix)
|
|||||||
m_lu.diagonal().cwise().abs().maxCoeff(&index_of_biggest);
|
m_lu.diagonal().cwise().abs().maxCoeff(&index_of_biggest);
|
||||||
m_biggest_eigenvalue_of_u = m_lu.diagonal().coeff(index_of_biggest);
|
m_biggest_eigenvalue_of_u = m_lu.diagonal().coeff(index_of_biggest);
|
||||||
|
|
||||||
m_dimension_of_kernel = 0;
|
m_rank = 0;
|
||||||
for(int k = 0; k < size; k++)
|
for(int k = 0; k < size; k++)
|
||||||
m_dimension_of_kernel += ei_isMuchSmallerThan(m_lu.diagonal().coeff(k), m_biggest_eigenvalue_of_u);
|
m_rank += !ei_isMuchSmallerThan(m_lu.diagonal().coeff(k), m_biggest_eigenvalue_of_u);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
typename ei_traits<MatrixType>::Scalar LU<MatrixType>::determinant() const
|
typename ei_traits<MatrixType>::Scalar LU<MatrixType>::determinant() const
|
||||||
{
|
{
|
||||||
|
if(!isInvertible()) return Scalar(0);
|
||||||
Scalar res = m_det_pq;
|
Scalar res = m_det_pq;
|
||||||
for(int k = 0; k < m_lu.diagonal().size(); k++) res *= m_lu.diagonal().coeff(k);
|
for(int k = 0; k < m_lu.diagonal().size(); k++) res *= m_lu.diagonal().coeff(k);
|
||||||
return res;
|
return res;
|
||||||
@ -180,9 +218,9 @@ typename ei_traits<MatrixType>::Scalar LU<MatrixType>::determinant() const
|
|||||||
*/
|
*/
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
const LU<typename MatrixBase<Derived>::EvalType>
|
const LU<typename MatrixBase<Derived>::EvalType>
|
||||||
MatrixBase<Derived>::lu() const
|
MatrixBase<Derived>::lu(int pivoting = CompletePivoting) const
|
||||||
{
|
{
|
||||||
return eval();
|
return LU<typename MatrixBase<Derived>::EvalType>(eval(), pivoting);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // EIGEN_LU_H
|
#endif // EIGEN_LU_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user