mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
* Fix some complex alignment issues in the cache friendly matrix-vector products.
* Minor update of the cores of the Cholesky algorithms to make them more friendly wrt to matrix-vector products => speedup x5 !
This commit is contained in:
@@ -48,24 +48,28 @@
|
||||
*/
|
||||
template<typename MatrixType> class Cholesky
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
|
||||
|
||||
enum {
|
||||
PacketSize = ei_packet_traits<Scalar>::size,
|
||||
AlignmentMask = int(PacketSize)-1
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Cholesky(const MatrixType& matrix)
|
||||
: m_matrix(matrix.rows(), matrix.cols())
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
Part<MatrixType, Lower> matrixL(void) const
|
||||
{
|
||||
return m_matrix;
|
||||
}
|
||||
inline Part<MatrixType, Lower> matrixL(void) const { return m_matrix; }
|
||||
|
||||
bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
/** \returns true if the matrix is positive definite */
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename Derived>
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const;
|
||||
@@ -92,20 +96,30 @@ void Cholesky<MatrixType>::compute(const MatrixType& a)
|
||||
|
||||
RealScalar x;
|
||||
x = ei_real(a.coeff(0,0));
|
||||
m_isPositiveDefinite = x > RealScalar(0) && ei_isMuchSmallerThan(ei_imag(m_matrix.coeff(0,0)), RealScalar(1));
|
||||
m_isPositiveDefinite = x > precision<Scalar>() && ei_isMuchSmallerThan(ei_imag(m_matrix.coeff(0,0)), RealScalar(1));
|
||||
m_matrix.coeffRef(0,0) = ei_sqrt(x);
|
||||
m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / m_matrix.coeff(0,0);
|
||||
m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / ei_real(m_matrix.coeff(0,0));
|
||||
for (int j = 1; j < size; ++j)
|
||||
{
|
||||
Scalar tmp = ei_real(a.coeff(j,j)) - m_matrix.row(j).start(j).norm2();
|
||||
x = ei_real(tmp);
|
||||
m_isPositiveDefinite = m_isPositiveDefinite && x > RealScalar(0) && ei_isMuchSmallerThan(ei_imag(tmp), RealScalar(1));
|
||||
if (x < precision<Scalar>() || (!ei_isMuchSmallerThan(ei_imag(tmp), RealScalar(1))))
|
||||
{
|
||||
m_isPositiveDefinite = m_isPositiveDefinite;
|
||||
return;
|
||||
}
|
||||
m_matrix.coeffRef(j,j) = x = ei_sqrt(x);
|
||||
|
||||
int endSize = size-j-1;
|
||||
if (endSize>0)
|
||||
if (endSize>0) {
|
||||
// Note that when all matrix columns have good alignment, then the following
|
||||
// product is guaranteed to be optimal with respect to alignment.
|
||||
m_matrix.col(j).end(endSize) =
|
||||
(m_matrix.block(j+1, 0, endSize, j) * m_matrix.row(j).start(j).adjoint()).lazy();
|
||||
|
||||
m_matrix.col(j).end(endSize) = (a.row(j).end(endSize).adjoint()
|
||||
- m_matrix.block(j+1, 0, endSize, j) * m_matrix.row(j).start(j).adjoint()) / x;
|
||||
- m_matrix.col(j).end(endSize) ) / x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,23 +60,13 @@ template<typename MatrixType> class CholeskyWithoutSquareRoot
|
||||
}
|
||||
|
||||
/** \returns the lower triangular matrix L */
|
||||
Part<MatrixType, UnitLower> matrixL(void) const
|
||||
{
|
||||
return m_matrix;
|
||||
}
|
||||
inline Part<MatrixType, UnitLower> matrixL(void) const { return m_matrix; }
|
||||
|
||||
/** \returns the coefficients of the diagonal matrix D */
|
||||
DiagonalCoeffs<MatrixType> vectorD(void) const
|
||||
{
|
||||
return m_matrix.diagonal();
|
||||
}
|
||||
inline DiagonalCoeffs<MatrixType> vectorD(void) const { return m_matrix.diagonal(); }
|
||||
|
||||
/** \returns whether the matrix is positive definite */
|
||||
bool isPositiveDefinite(void) const
|
||||
{
|
||||
// FIXME is it really correct ?
|
||||
return m_matrix.diagonal().real().minCoeff() > RealScalar(0);
|
||||
}
|
||||
/** \returns true if the matrix is positive definite */
|
||||
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
|
||||
|
||||
template<typename Derived>
|
||||
typename Derived::Eval solve(const MatrixBase<Derived> &b) const;
|
||||
@@ -91,6 +81,8 @@ template<typename MatrixType> class CholeskyWithoutSquareRoot
|
||||
* is not stored), and the diagonal entries correspond to D.
|
||||
*/
|
||||
MatrixType m_matrix;
|
||||
|
||||
bool m_isPositiveDefinite;
|
||||
};
|
||||
|
||||
/** Compute / recompute the Cholesky decomposition A = L D L^* = U^* D U of \a matrix
|
||||
@@ -101,6 +93,13 @@ void CholeskyWithoutSquareRoot<MatrixType>::compute(const MatrixType& a)
|
||||
assert(a.rows()==a.cols());
|
||||
const int size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
m_isPositiveDefinite = true;
|
||||
|
||||
// Let's preallocate a temporay vector to evaluate the matrix-vector product into it.
|
||||
// Unlike the standard Cholesky decomposition, here we cannot evaluate it to the destination
|
||||
// matrix because it a sub-row which is not compatible suitable for efficient packet evaluation.
|
||||
// (at least if we assume the matrix is col-major)
|
||||
Matrix<Scalar,MatrixType::RowsAtCompileTime,1> _temporary(size);
|
||||
|
||||
// Note that, in this algorithm the rows of the strict upper part of m_matrix is used to store
|
||||
// column vector, thus the strange .conjugate() and .transpose()...
|
||||
@@ -112,11 +111,21 @@ void CholeskyWithoutSquareRoot<MatrixType>::compute(const MatrixType& a)
|
||||
RealScalar tmp = ei_real(a.coeff(j,j) - (m_matrix.row(j).start(j) * m_matrix.col(j).start(j).conjugate()).coeff(0,0));
|
||||
m_matrix.coeffRef(j,j) = tmp;
|
||||
|
||||
if (ei_isMuchSmallerThan(tmp,RealScalar(1)))
|
||||
{
|
||||
m_isPositiveDefinite = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int endSize = size-j-1;
|
||||
if (endSize>0)
|
||||
{
|
||||
_temporary.end(endSize) = ( m_matrix.block(j+1,0, endSize, j)
|
||||
* m_matrix.col(j).start(j).conjugate() ).lazy();
|
||||
|
||||
m_matrix.row(j).end(endSize) = a.row(j).end(endSize).conjugate()
|
||||
- (m_matrix.block(j+1,0, endSize, j) * m_matrix.col(j).start(j).conjugate()).transpose();
|
||||
- _temporary.end(endSize).transpose();
|
||||
|
||||
m_matrix.col(j).end(endSize) = m_matrix.row(j).end(endSize) / tmp;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user