LU: remove partial-pivoting path (moderately useful since it's does

not allow to easily get the rank), fix a bug (which could have been
triggered by matrices having coefficients of very different
magnitudes).
Part: add an assert to prevent hard to find bugs
Swap: update comments
This commit is contained in:
Benoit Jacob 2008-08-07 04:31:05 +00:00
parent 88bb2087c1
commit 58ba9ca72f
5 changed files with 73 additions and 68 deletions

View File

@ -535,7 +535,7 @@ template<typename Derived> class MatrixBase
/////////// LU module ///////////
const LU<EvalType> lu(int pivoting) const;
const LU<EvalType> lu() const;
const EvalType inverse() const;
void computeInverse(EvalType *result) const;
Scalar determinant() const;

View File

@ -179,6 +179,7 @@ struct ei_part_assignment_impl
}
else
{
ei_assert(Mode == Upper || Mode == Lower || Mode == StrictlyUpper || Mode == StrictlyLower);
if((Mode == Upper && row <= col)
|| (Mode == Lower && row >= col)
|| (Mode == StrictlyUpper && row < col)

View File

@ -27,14 +27,9 @@
/** \class SwapWrapper
*
* \brief Expression which must be nested by value
* \internal
*
* \param ExpressionType the type of the object of which we are requiring nesting-by-value
*
* This class is the return type of MatrixBase::nestByValue()
* and most of the time this is the only way it is used.
*
* \sa MatrixBase::nestByValue()
* \brief Internal helper class for swapping two expressions
*/
template<typename ExpressionType>
struct ei_traits<SwapWrapper<ExpressionType> >
@ -116,12 +111,10 @@ template<typename ExpressionType> class SwapWrapper
/** swaps *this with the expression \a other.
*
* \note \a other is only marked const because I couln't find another way
* to get g++ (4.2 and 4.3) to accept that template parameter resolution.
* The problem seems to be that when swapping expressions as in
* m.row(i).swap(m.row(j)); the Row object returned by row(j) is a temporary
* and g++ doesn't dare to pass it by non-constant reference.
* It gets const_cast'd of course. TODO: get rid of const here.
* \note \a other is only marked for internal reasons, but of course
* it gets const-casted. One reason is that one will often call swap
* on temporary objects (hence non-const references are forbidden).
* Another reason is that lazyAssign takes a const argument anyway.
*/
template<typename Derived>
template<typename OtherDerived>
@ -131,3 +124,9 @@ void MatrixBase<Derived>::swap(const MatrixBase<OtherDerived>& other)
}
#endif // EIGEN_SWAP_H

View File

@ -209,11 +209,6 @@ enum {
HasDirectAccess = DirectAccessBit
};
enum {
PartialPivoting,
CompletePivoting
};
const int FullyCoherentAccessPattern = 0x1;
const int InnerCoherentAccessPattern = 0x2 | FullyCoherentAccessPattern;
const int OuterCoherentAccessPattern = 0x4 | InnerCoherentAccessPattern;

View File

@ -54,7 +54,7 @@ template<typename MatrixType> class LU
typedef Matrix<int, MatrixType::ColsAtCompileTime, 1> IntRowVectorType;
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
LU(const MatrixType& matrix, int pivoting = CompletePivoting);
LU(const MatrixType& matrix);
inline const MatrixType& matrixLU() const
{
@ -81,6 +81,10 @@ template<typename MatrixType> class LU
return m_q;
}
inline const Matrix<Scalar, MatrixType::RowsAtCompileTime, Dynamic,
MatrixType::MaxRowsAtCompileTime,
MatrixType::MaxColsAtCompileTime> kernel() const;
template<typename OtherDerived>
typename ProductReturnType<Transpose<MatrixType>, OtherDerived>::Type::Eval
solve(const MatrixBase<MatrixType> &b) const;
@ -107,11 +111,21 @@ template<typename MatrixType> class LU
return m_lu.cols() - m_rank;
}
inline bool isInvertible() const
inline bool isInjective() const
{
return m_rank == m_lu.cols();
}
inline bool isSurjective() const
{
return m_rank == m_lu.rows();
}
inline bool isInvertible() const
{
return isInjective() && isSurjective();
}
protected:
MatrixType m_lu;
IntColVectorType m_p;
@ -119,61 +133,48 @@ template<typename MatrixType> class LU
int m_det_pq;
Scalar m_biggest_eigenvalue_of_u;
int m_rank;
int m_pivoting;
};
template<typename MatrixType>
LU<MatrixType>::LU(const MatrixType& matrix, int pivoting)
LU<MatrixType>::LU(const MatrixType& matrix)
: m_lu(matrix),
m_p(matrix.rows()),
m_q(matrix.cols()),
m_pivoting(pivoting)
m_q(matrix.cols())
{
const int size = matrix.diagonal().size();
const int rows = matrix.rows();
const int cols = matrix.cols();
ei_assert(pivoting == PartialPivoting || pivoting == CompletePivoting);
IntColVectorType rows_transpositions(matrix.rows());
IntRowVectorType cols_transpositions(matrix.cols());
int number_of_transpositions = 0;
RealScalar biggest;
for(int k = 0; k < size; k++)
{
int row_of_biggest, col_of_biggest;
Scalar biggest;
if(m_pivoting == CompletePivoting)
{
biggest = m_lu.corner(Eigen::BottomRight, rows-k, cols-k)
.cwise().abs()
.maxCoeff(&row_of_biggest, &col_of_biggest);
row_of_biggest += k;
col_of_biggest += k;
rows_transpositions.coeffRef(k) = row_of_biggest;
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++;
}
int row_of_biggest_in_corner, col_of_biggest_in_corner;
RealScalar biggest_in_corner;
biggest_in_corner = m_lu.corner(Eigen::BottomRight, rows-k, cols-k)
.cwise().abs()
.maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner);
row_of_biggest_in_corner += k;
col_of_biggest_in_corner += k;
rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
if(k != row_of_biggest_in_corner) {
m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner));
number_of_transpositions++;
}
else // partial pivoting
{
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++;
}
if(k != col_of_biggest_in_corner) {
m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner));
number_of_transpositions++;
}
if(k==0) biggest = biggest_in_corner;
const Scalar lu_k_k = m_lu.coeff(k,k);
if(ei_isMuchSmallerThan(lu_k_k, biggest)) continue;
std::cout << lu_k_k << " " << biggest << std::endl;
if(ei_isMuchSmallerThan(lu_k_k, biggest)) { std::cout << "hello" << std::endl; continue; }
if(k<rows-1)
m_lu.col(k).end(rows-k-1) /= lu_k_k;
if(k<size-1)
@ -185,18 +186,15 @@ LU<MatrixType>::LU(const MatrixType& matrix, int pivoting)
for(int k = size-1; k >= 0; k--)
std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k)));
if(pivoting == CompletePivoting)
{
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)));
}
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;
int index_of_biggest;
m_lu.diagonal().cwise().abs().maxCoeff(&index_of_biggest);
m_biggest_eigenvalue_of_u = m_lu.diagonal().coeff(index_of_biggest);
int index_of_biggest_in_diagonal;
m_lu.diagonal().cwise().abs().maxCoeff(&index_of_biggest_in_diagonal);
m_biggest_eigenvalue_of_u = m_lu.diagonal().coeff(index_of_biggest_in_diagonal);
m_rank = 0;
for(int k = 0; k < size; k++)
@ -212,15 +210,27 @@ typename ei_traits<MatrixType>::Scalar LU<MatrixType>::determinant() const
return res;
}
#if 0
template<typename MatrixType>
inline const Matrix<Scalar, RowsAtCompileTime, Dynamic,
MaxRowsAtCompileTime, MaxColsAtCompileTime> kernel() const
{
Matrix<Scalar, RowsAtCompileTime, Dynamic,
MaxRowsAtCompileTime, MaxColsAtCompileTime>
result(m_lu.rows(), dimensionOfKernel());
}
#endif
/** \return the LU decomposition of \c *this.
*
* \sa class LU
*/
template<typename Derived>
const LU<typename MatrixBase<Derived>::EvalType>
MatrixBase<Derived>::lu(int pivoting = CompletePivoting) const
MatrixBase<Derived>::lu() const
{
return LU<typename MatrixBase<Derived>::EvalType>(eval(), pivoting);
return eval();
}
#endif // EIGEN_LU_H