- Added problem size constructor to decompositions that did not have one. It preallocates member data structures.

- Updated unit tests to check above constructor.
- In the compute() method of decompositions: Made temporary matrices/vectors class members to avoid heap allocations during compute() (when dynamic matrices are used, of course).

These  changes can speed up decomposition computation time when a solver instance is used to solve multiple same-sized problems. An added benefit is that the compute() method can now be invoked in contexts were heap allocations are forbidden, such as in real-time control loops.

CAVEAT: Not all of the decompositions in the Eigenvalues module have a heap-allocation-free compute() method. A future patch may address this issue, but some required API changes need to be incorporated first.
This commit is contained in:
Adolfo Rodriguez Tsouroukdissian 2010-04-21 17:15:57 +02:00
parent faf8f7732d
commit 28dde19e40
29 changed files with 396 additions and 121 deletions

View File

@ -66,6 +66,7 @@ template<typename _MatrixType> class LDLT
typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
typedef typename ei_plain_col_type<MatrixType, int>::type IntColVectorType; typedef typename ei_plain_col_type<MatrixType, int>::type IntColVectorType;
typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> TmpMatrixType;
/** \brief Default Constructor. /** \brief Default Constructor.
* *
@ -80,12 +81,17 @@ template<typename _MatrixType> class LDLT
* according to the specified problem \a size. * according to the specified problem \a size.
* \sa LDLT() * \sa LDLT()
*/ */
LDLT(int size) : m_matrix(size,size), m_p(size), m_transpositions(size), m_isInitialized(false) {} LDLT(int size) : m_matrix(size, size),
m_p(size),
m_transpositions(size),
m_temporary(size),
m_isInitialized(false) {}
LDLT(const MatrixType& matrix) LDLT(const MatrixType& matrix)
: m_matrix(matrix.rows(), matrix.cols()), : m_matrix(matrix.rows(), matrix.cols()),
m_p(matrix.rows()), m_p(matrix.rows()),
m_transpositions(matrix.rows()), m_transpositions(matrix.rows()),
m_temporary(matrix.rows()),
m_isInitialized(false) m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
@ -175,6 +181,7 @@ template<typename _MatrixType> class LDLT
MatrixType m_matrix; MatrixType m_matrix;
IntColVectorType m_p; IntColVectorType m_p;
IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions? IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions?
TmpMatrixType m_temporary;
int m_sign; int m_sign;
bool m_isInitialized; bool m_isInitialized;
}; };
@ -206,7 +213,7 @@ LDLT<MatrixType>& LDLT<MatrixType>::compute(const MatrixType& a)
// By using a temorary, packet-aligned products are guarenteed. In the LLT // By using a temorary, packet-aligned products are guarenteed. In the LLT
// case this is unnecessary because the diagonal is included and will always // case this is unnecessary because the diagonal is included and will always
// have optimal alignment. // have optimal alignment.
Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> _temporary(size); m_temporary.resize(size);
for (int j = 0; j < size; ++j) for (int j = 0; j < size; ++j)
{ {
@ -251,11 +258,11 @@ LDLT<MatrixType>& LDLT<MatrixType>::compute(const MatrixType& a)
int endSize = size - j - 1; int endSize = size - j - 1;
if (endSize > 0) { if (endSize > 0) {
_temporary.tail(endSize).noalias() = m_matrix.block(j+1,0, endSize, j) m_temporary.tail(endSize).noalias() = m_matrix.block(j+1,0, endSize, j)
* m_matrix.col(j).head(j).conjugate(); * m_matrix.col(j).head(j).conjugate();
m_matrix.row(j).tail(endSize) = m_matrix.row(j).tail(endSize).conjugate() m_matrix.row(j).tail(endSize) = m_matrix.row(j).tail(endSize).conjugate()
- _temporary.tail(endSize).transpose(); - m_temporary.tail(endSize).transpose();
if(ei_abs(Djj) > cutoff) if(ei_abs(Djj) > cutoff)
{ {

View File

@ -82,6 +82,15 @@ template<typename _MatrixType, int _UpLo> class LLT
*/ */
LLT() : m_matrix(), m_isInitialized(false) {} LLT() : m_matrix(), m_isInitialized(false) {}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa LLT()
*/
LLT(int size) : m_matrix(size, size),
m_isInitialized(false) {}
LLT(const MatrixType& matrix) LLT(const MatrixType& matrix)
: m_matrix(matrix.rows(), matrix.cols()), : m_matrix(matrix.rows(), matrix.cols()),
m_isInitialized(false) m_isInitialized(false)

View File

@ -95,7 +95,24 @@ template<typename _MatrixType> class ComplexEigenSolver
* The default constructor is useful in cases in which the user intends to * The default constructor is useful in cases in which the user intends to
* perform decompositions via compute(). * perform decompositions via compute().
*/ */
ComplexEigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) ComplexEigenSolver()
: m_eivec(),
m_eivalues(),
m_schur(),
m_isInitialized(false)
{}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa ComplexEigenSolver()
*/
ComplexEigenSolver(int size)
: m_eivec(size, size),
m_eivalues(size),
m_schur(size),
m_isInitialized(false)
{} {}
/** \brief Constructor; computes eigendecomposition of given matrix. /** \brief Constructor; computes eigendecomposition of given matrix.
@ -107,6 +124,7 @@ template<typename _MatrixType> class ComplexEigenSolver
ComplexEigenSolver(const MatrixType& matrix) ComplexEigenSolver(const MatrixType& matrix)
: m_eivec(matrix.rows(),matrix.cols()), : m_eivec(matrix.rows(),matrix.cols()),
m_eivalues(matrix.cols()), m_eivalues(matrix.cols()),
m_schur(matrix.rows()),
m_isInitialized(false) m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
@ -179,6 +197,7 @@ template<typename _MatrixType> class ComplexEigenSolver
protected: protected:
EigenvectorType m_eivec; EigenvectorType m_eivec;
EigenvalueType m_eivalues; EigenvalueType m_eivalues;
ComplexSchur<MatrixType> m_schur;
bool m_isInitialized; bool m_isInitialized;
}; };
@ -193,8 +212,8 @@ void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix)
// Step 1: Do a complex Schur decomposition, A = U T U^* // Step 1: Do a complex Schur decomposition, A = U T U^*
// The eigenvalues are on the diagonal of T. // The eigenvalues are on the diagonal of T.
ComplexSchur<MatrixType> schur(matrix); m_schur.compute(matrix);
m_eivalues = schur.matrixT().diagonal(); m_eivalues = m_schur.matrixT().diagonal();
// Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T. // Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T.
// The matrix X is unit triangular. // The matrix X is unit triangular.
@ -205,10 +224,10 @@ void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix)
// Compute X(i,k) using the (i,k) entry of the equation X T = D X // Compute X(i,k) using the (i,k) entry of the equation X T = D X
for(int i=k-1 ; i>=0 ; i--) for(int i=k-1 ; i>=0 ; i--)
{ {
X.coeffRef(i,k) = -schur.matrixT().coeff(i,k); X.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k);
if(k-i-1>0) if(k-i-1>0)
X.coeffRef(i,k) -= (schur.matrixT().row(i).segment(i+1,k-i-1) * X.col(k).segment(i+1,k-i-1)).value(); X.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * X.col(k).segment(i+1,k-i-1)).value();
ComplexScalar z = schur.matrixT().coeff(i,i) - schur.matrixT().coeff(k,k); ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k);
if(z==ComplexScalar(0)) if(z==ComplexScalar(0))
{ {
// If the i-th and k-th eigenvalue are equal, then z equals 0. // If the i-th and k-th eigenvalue are equal, then z equals 0.
@ -220,7 +239,7 @@ void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix)
} }
// Step 3: Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1) // Step 3: Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1)
m_eivec = schur.matrixU() * X; m_eivec = m_schur.matrixU() * X;
// .. and normalize the eigenvectors // .. and normalize the eigenvectors
for(int k=0 ; k<n ; k++) for(int k=0 ; k<n ; k++)
{ {

View File

@ -96,7 +96,11 @@ template<typename _MatrixType> class ComplexSchur
* \sa compute() for an example. * \sa compute() for an example.
*/ */
ComplexSchur(int size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) ComplexSchur(int size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
: m_matT(size,size), m_matU(size,size), m_isInitialized(false), m_matUisUptodate(false) : m_matT(size,size),
m_matU(size,size),
m_hess(size),
m_isInitialized(false),
m_matUisUptodate(false)
{} {}
/** \brief Constructor; computes Schur decomposition of given matrix. /** \brief Constructor; computes Schur decomposition of given matrix.
@ -111,6 +115,7 @@ template<typename _MatrixType> class ComplexSchur
ComplexSchur(const MatrixType& matrix, bool skipU = false) ComplexSchur(const MatrixType& matrix, bool skipU = false)
: m_matT(matrix.rows(),matrix.cols()), : m_matT(matrix.rows(),matrix.cols()),
m_matU(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()),
m_hess(matrix.rows()),
m_isInitialized(false), m_isInitialized(false),
m_matUisUptodate(false) m_matUisUptodate(false)
{ {
@ -182,6 +187,7 @@ template<typename _MatrixType> class ComplexSchur
protected: protected:
ComplexMatrixType m_matT, m_matU; ComplexMatrixType m_matT, m_matU;
HessenbergDecomposition<MatrixType> m_hess;
bool m_isInitialized; bool m_isInitialized;
bool m_matUisUptodate; bool m_matUisUptodate;
@ -300,10 +306,10 @@ void ComplexSchur<MatrixType>::compute(const MatrixType& matrix, bool skipU)
// Reduce to Hessenberg form // Reduce to Hessenberg form
// TODO skip Q if skipU = true // TODO skip Q if skipU = true
HessenbergDecomposition<MatrixType> hess(matrix); m_hess.compute(matrix);
m_matT = hess.matrixH().template cast<ComplexScalar>(); m_matT = m_hess.matrixH().template cast<ComplexScalar>();
if(!skipU) m_matU = hess.matrixQ().template cast<ComplexScalar>(); if(!skipU) m_matU = m_hess.matrixQ().template cast<ComplexScalar>();
// Reduce the Hessenberg matrix m_matT to triangular form by QR iteration. // Reduce the Hessenberg matrix m_matT to triangular form by QR iteration.

View File

@ -122,6 +122,17 @@ template<typename _MatrixType> class EigenSolver
*/ */
EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) {} EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) {}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa EigenSolver()
*/
EigenSolver(int size)
: m_eivec(size, size),
m_eivalues(size),
m_isInitialized(false) {}
/** \brief Constructor; computes eigendecomposition of given matrix. /** \brief Constructor; computes eigendecomposition of given matrix.
* *
* \param[in] matrix Square matrix whose eigendecomposition is to be computed. * \param[in] matrix Square matrix whose eigendecomposition is to be computed.

View File

@ -91,7 +91,8 @@ template<typename _MatrixType> class HessenbergDecomposition
* \sa compute() for an example. * \sa compute() for an example.
*/ */
HessenbergDecomposition(int size = Size==Dynamic ? 2 : Size) HessenbergDecomposition(int size = Size==Dynamic ? 2 : Size)
: m_matrix(size,size) : m_matrix(size,size),
m_temp(size)
{ {
if(size>1) if(size>1)
m_hCoeffs.resize(size-1); m_hCoeffs.resize(size-1);
@ -107,12 +108,13 @@ template<typename _MatrixType> class HessenbergDecomposition
* \sa matrixH() for an example. * \sa matrixH() for an example.
*/ */
HessenbergDecomposition(const MatrixType& matrix) HessenbergDecomposition(const MatrixType& matrix)
: m_matrix(matrix) : m_matrix(matrix),
m_temp(matrix.rows())
{ {
if(matrix.rows()<2) if(matrix.rows()<2)
return; return;
m_hCoeffs.resize(matrix.rows()-1,1); m_hCoeffs.resize(matrix.rows()-1,1);
_compute(m_matrix, m_hCoeffs); _compute(m_matrix, m_hCoeffs, m_temp);
} }
/** \brief Computes Hessenberg decomposition of given matrix. /** \brief Computes Hessenberg decomposition of given matrix.
@ -137,7 +139,7 @@ template<typename _MatrixType> class HessenbergDecomposition
if(matrix.rows()<2) if(matrix.rows()<2)
return; return;
m_hCoeffs.resize(matrix.rows()-1,1); m_hCoeffs.resize(matrix.rows()-1,1);
_compute(m_matrix, m_hCoeffs); _compute(m_matrix, m_hCoeffs, m_temp);
} }
/** \brief Returns the Householder coefficients. /** \brief Returns the Householder coefficients.
@ -226,13 +228,14 @@ template<typename _MatrixType> class HessenbergDecomposition
private: private:
static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs);
typedef Matrix<Scalar, 1, Size, Options | RowMajor, 1, MaxSize> VectorType; typedef Matrix<Scalar, 1, Size, Options | RowMajor, 1, MaxSize> VectorType;
typedef typename NumTraits<Scalar>::Real RealScalar; typedef typename NumTraits<Scalar>::Real RealScalar;
static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp);
protected: protected:
MatrixType m_matrix; MatrixType m_matrix;
CoeffVectorType m_hCoeffs; CoeffVectorType m_hCoeffs;
VectorType m_temp;
}; };
#ifndef EIGEN_HIDE_HEAVY_CODE #ifndef EIGEN_HIDE_HEAVY_CODE
@ -250,11 +253,11 @@ template<typename _MatrixType> class HessenbergDecomposition
* \sa packedMatrix() * \sa packedMatrix()
*/ */
template<typename MatrixType> template<typename MatrixType>
void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs) void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp)
{ {
assert(matA.rows()==matA.cols()); assert(matA.rows()==matA.cols());
int n = matA.rows(); int n = matA.rows();
VectorType temp(n); temp.resize(n);
for (int i = 0; i<n-1; ++i) for (int i = 0; i<n-1; ++i)
{ {
// let's consider the vector v = i-th column starting at position i+1 // let's consider the vector v = i-th column starting at position i+1

View File

@ -78,6 +78,7 @@ template<typename _MatrixType> class RealSchur
typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Scalar Scalar;
typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar; typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType; typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
/** \brief Default constructor. /** \brief Default constructor.
* *
@ -92,7 +93,9 @@ template<typename _MatrixType> class RealSchur
*/ */
RealSchur(int size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) RealSchur(int size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
: m_matT(size, size), : m_matT(size, size),
m_matU(size, size), m_matU(size, size),
m_workspaceVector(size),
m_hess(size),
m_isInitialized(false) m_isInitialized(false)
{ } { }
@ -108,6 +111,8 @@ template<typename _MatrixType> class RealSchur
RealSchur(const MatrixType& matrix) RealSchur(const MatrixType& matrix)
: m_matT(matrix.rows(),matrix.cols()), : m_matT(matrix.rows(),matrix.cols()),
m_matU(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()),
m_workspaceVector(matrix.rows()),
m_hess(matrix.rows()),
m_isInitialized(false) m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
@ -165,6 +170,8 @@ template<typename _MatrixType> class RealSchur
MatrixType m_matT; MatrixType m_matT;
MatrixType m_matU; MatrixType m_matU;
ColumnVectorType m_workspaceVector;
HessenbergDecomposition<MatrixType> m_hess;
bool m_isInitialized; bool m_isInitialized;
typedef Matrix<Scalar,3,1> Vector3s; typedef Matrix<Scalar,3,1> Vector3s;
@ -185,14 +192,13 @@ void RealSchur<MatrixType>::compute(const MatrixType& matrix)
// Step 1. Reduce to Hessenberg form // Step 1. Reduce to Hessenberg form
// TODO skip Q if skipU = true // TODO skip Q if skipU = true
HessenbergDecomposition<MatrixType> hess(matrix); m_hess.compute(matrix);
m_matT = hess.matrixH(); m_matT = m_hess.matrixH();
m_matU = hess.matrixQ(); m_matU = m_hess.matrixQ();
// Step 2. Reduce to real Schur form // Step 2. Reduce to real Schur form
typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType; m_workspaceVector.resize(m_matU.cols());
ColumnVectorType workspaceVector(m_matU.cols()); Scalar* workspace = &m_workspaceVector.coeffRef(0);
Scalar* workspace = &workspaceVector.coeffRef(0);
// The matrix m_matT is divided in three parts. // The matrix m_matT is divided in three parts.
// Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero. // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero.

View File

@ -58,14 +58,16 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
SelfAdjointEigenSolver() SelfAdjointEigenSolver()
: m_eivec(int(Size), int(Size)), : m_eivec(int(Size), int(Size)),
m_eivalues(int(Size)) m_eivalues(int(Size)),
m_subdiag(int(TridiagonalizationType::SizeMinusOne))
{ {
ei_assert(Size!=Dynamic); ei_assert(Size!=Dynamic);
} }
SelfAdjointEigenSolver(int size) SelfAdjointEigenSolver(int size)
: m_eivec(size, size), : m_eivec(size, size),
m_eivalues(size) m_eivalues(size),
m_subdiag(TridiagonalizationType::SizeMinusOne)
{} {}
/** Constructors computing the eigenvalues of the selfadjoint matrix \a matrix, /** Constructors computing the eigenvalues of the selfadjoint matrix \a matrix,
@ -75,8 +77,10 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
*/ */
SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true)
: m_eivec(matrix.rows(), matrix.cols()), : m_eivec(matrix.rows(), matrix.cols()),
m_eivalues(matrix.cols()) m_eivalues(matrix.cols()),
m_subdiag()
{ {
if (matrix.rows() > 1) m_subdiag.resize(matrix.rows() - 1);
compute(matrix, computeEigenvectors); compute(matrix, computeEigenvectors);
} }
@ -89,8 +93,10 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
*/ */
SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true) SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true)
: m_eivec(matA.rows(), matA.cols()), : m_eivec(matA.rows(), matA.cols()),
m_eivalues(matA.cols()) m_eivalues(matA.cols()),
m_subdiag()
{ {
if (matA.rows() > 1) m_subdiag.resize(matA.rows() - 1);
compute(matA, matB, computeEigenvectors); compute(matA, matB, computeEigenvectors);
} }
@ -132,6 +138,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
protected: protected:
MatrixType m_eivec; MatrixType m_eivec;
RealVectorType m_eivalues; RealVectorType m_eivalues;
typename TridiagonalizationType::SubDiagonalType m_subdiag;
#ifndef NDEBUG #ifndef NDEBUG
bool m_eigenvectorsOk; bool m_eigenvectorsOk;
#endif #endif
@ -187,27 +194,27 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute(
// the latter avoids multiple memory allocation when the same SelfAdjointEigenSolver is used multiple times... // the latter avoids multiple memory allocation when the same SelfAdjointEigenSolver is used multiple times...
// (same for diag and subdiag) // (same for diag and subdiag)
RealVectorType& diag = m_eivalues; RealVectorType& diag = m_eivalues;
typename TridiagonalizationType::SubDiagonalType subdiag(n-1); m_subdiag.resize(n-1);
TridiagonalizationType::decomposeInPlace(m_eivec, diag, subdiag, computeEigenvectors); TridiagonalizationType::decomposeInPlace(m_eivec, diag, m_subdiag, computeEigenvectors);
int end = n-1; int end = n-1;
int start = 0; int start = 0;
while (end>0) while (end>0)
{ {
for (int i = start; i<end; ++i) for (int i = start; i<end; ++i)
if (ei_isMuchSmallerThan(ei_abs(subdiag[i]),(ei_abs(diag[i])+ei_abs(diag[i+1])))) if (ei_isMuchSmallerThan(ei_abs(m_subdiag[i]),(ei_abs(diag[i])+ei_abs(diag[i+1]))))
subdiag[i] = 0; m_subdiag[i] = 0;
// find the largest unreduced block // find the largest unreduced block
while (end>0 && subdiag[end-1]==0) while (end>0 && m_subdiag[end-1]==0)
end--; end--;
if (end<=0) if (end<=0)
break; break;
start = end - 1; start = end - 1;
while (start>0 && subdiag[start-1]!=0) while (start>0 && m_subdiag[start-1]!=0)
start--; start--;
ei_tridiagonal_qr_step(diag.data(), subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); ei_tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n);
} }
// Sort eigenvalues and corresponding vectors. // Sort eigenvalues and corresponding vectors.

View File

@ -210,8 +210,8 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
// i.e., A = H A H' where H = I - h v v' and v = matA.col(i).tail(n-i-1) // i.e., A = H A H' where H = I - h v v' and v = matA.col(i).tail(n-i-1)
matA.col(i).coeffRef(i+1) = 1; matA.col(i).coeffRef(i+1) = 1;
hCoeffs.tail(n-i-1) = (matA.corner(BottomRight,remainingSize,remainingSize).template selfadjointView<Lower>() hCoeffs.tail(n-i-1).noalias() = (matA.corner(BottomRight,remainingSize,remainingSize).template selfadjointView<Lower>()
* (ei_conj(h) * matA.col(i).tail(remainingSize))); * (ei_conj(h) * matA.col(i).tail(remainingSize)));
hCoeffs.tail(n-i-1) += (ei_conj(h)*Scalar(-0.5)*(hCoeffs.tail(remainingSize).dot(matA.col(i).tail(remainingSize)))) * matA.col(i).tail(n-i-1); hCoeffs.tail(n-i-1) += (ei_conj(h)*Scalar(-0.5)*(hCoeffs.tail(remainingSize).dot(matA.col(i).tail(remainingSize)))) * matA.col(i).tail(n-i-1);

View File

@ -81,6 +81,14 @@ template<typename _MatrixType> class FullPivLU
*/ */
FullPivLU(); FullPivLU();
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa FullPivLU()
*/
FullPivLU(int rows, int cols);
/** Constructor. /** Constructor.
* *
* \param matrix the matrix of which to compute the LU decomposition. * \param matrix the matrix of which to compute the LU decomposition.
@ -377,6 +385,8 @@ template<typename _MatrixType> class FullPivLU
MatrixType m_lu; MatrixType m_lu;
PermutationPType m_p; PermutationPType m_p;
PermutationQType m_q; PermutationQType m_q;
IntColVectorType m_rowsTranspositions;
IntRowVectorType m_colsTranspositions;
int m_det_pq, m_nonzero_pivots; int m_det_pq, m_nonzero_pivots;
RealScalar m_maxpivot, m_prescribedThreshold; RealScalar m_maxpivot, m_prescribedThreshold;
bool m_isInitialized, m_usePrescribedThreshold; bool m_isInitialized, m_usePrescribedThreshold;
@ -388,9 +398,27 @@ FullPivLU<MatrixType>::FullPivLU()
{ {
} }
template<typename MatrixType>
FullPivLU<MatrixType>::FullPivLU(int rows, int cols)
: m_lu(rows, cols),
m_p(rows),
m_q(cols),
m_rowsTranspositions(rows),
m_colsTranspositions(cols),
m_isInitialized(false),
m_usePrescribedThreshold(false)
{
}
template<typename MatrixType> template<typename MatrixType>
FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix) FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix)
: m_isInitialized(false), m_usePrescribedThreshold(false) : m_lu(matrix.rows(), matrix.cols()),
m_p(matrix.rows()),
m_q(matrix.cols()),
m_rowsTranspositions(matrix.rows()),
m_colsTranspositions(matrix.cols()),
m_isInitialized(false),
m_usePrescribedThreshold(false)
{ {
compute(matrix); compute(matrix);
} }
@ -407,9 +435,9 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
// will store the transpositions, before we accumulate them at the end. // will store the transpositions, before we accumulate them at the end.
// can't accumulate on-the-fly because that will be done in reverse order for the rows. // can't accumulate on-the-fly because that will be done in reverse order for the rows.
IntColVectorType rows_transpositions(matrix.rows()); m_rowsTranspositions.resize(matrix.rows());
IntRowVectorType cols_transpositions(matrix.cols()); m_colsTranspositions.resize(matrix.cols());
int number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. rows_transpositions[i]!=i int number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. m_rowsTranspositions[i]!=i
m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case) m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
m_maxpivot = RealScalar(0); m_maxpivot = RealScalar(0);
@ -442,8 +470,8 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
m_nonzero_pivots = k; m_nonzero_pivots = k;
for(int i = k; i < size; ++i) for(int i = k; i < size; ++i)
{ {
rows_transpositions.coeffRef(i) = i; m_rowsTranspositions.coeffRef(i) = i;
cols_transpositions.coeffRef(i) = i; m_colsTranspositions.coeffRef(i) = i;
} }
break; break;
} }
@ -453,8 +481,8 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
// Now that we've found the pivot, we need to apply the row/col swaps to // Now that we've found the pivot, we need to apply the row/col swaps to
// bring it to the location (k,k). // bring it to the location (k,k).
rows_transpositions.coeffRef(k) = row_of_biggest_in_corner; m_rowsTranspositions.coeffRef(k) = row_of_biggest_in_corner;
cols_transpositions.coeffRef(k) = col_of_biggest_in_corner; m_colsTranspositions.coeffRef(k) = col_of_biggest_in_corner;
if(k != row_of_biggest_in_corner) { if(k != row_of_biggest_in_corner) {
m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner)); m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner));
++number_of_transpositions; ++number_of_transpositions;
@ -478,11 +506,11 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
m_p.setIdentity(rows); m_p.setIdentity(rows);
for(int k = size-1; k >= 0; --k) for(int k = size-1; k >= 0; --k)
m_p.applyTranspositionOnTheRight(k, rows_transpositions.coeff(k)); m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k));
m_q.setIdentity(cols); m_q.setIdentity(cols);
for(int k = 0; k < size; ++k) for(int k = 0; k < size; ++k)
m_q.applyTranspositionOnTheRight(k, cols_transpositions.coeff(k)); m_q.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_det_pq = (number_of_transpositions%2) ? -1 : 1;
return *this; return *this;

View File

@ -83,6 +83,14 @@ template<typename _MatrixType> class PartialPivLU
*/ */
PartialPivLU(); PartialPivLU();
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa PartialPivLU()
*/
PartialPivLU(int size);
/** Constructor. /** Constructor.
* *
* \param matrix the matrix of which to compute the LU decomposition. * \param matrix the matrix of which to compute the LU decomposition.
@ -176,6 +184,7 @@ template<typename _MatrixType> class PartialPivLU
protected: protected:
MatrixType m_lu; MatrixType m_lu;
PermutationType m_p; PermutationType m_p;
PermutationVectorType m_rowsTranspositions;
int m_det_p; int m_det_p;
bool m_isInitialized; bool m_isInitialized;
}; };
@ -184,6 +193,17 @@ template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU() PartialPivLU<MatrixType>::PartialPivLU()
: m_lu(), : m_lu(),
m_p(), m_p(),
m_rowsTranspositions(),
m_det_p(0),
m_isInitialized(false)
{
}
template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU(int size)
: m_lu(size, size),
m_p(size),
m_rowsTranspositions(size),
m_det_p(0), m_det_p(0),
m_isInitialized(false) m_isInitialized(false)
{ {
@ -191,8 +211,9 @@ PartialPivLU<MatrixType>::PartialPivLU()
template<typename MatrixType> template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix) PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix)
: m_lu(), : m_lu(matrix.rows(), matrix.rows()),
m_p(), m_p(matrix.rows()),
m_rowsTranspositions(matrix.rows()),
m_det_p(0), m_det_p(0),
m_isInitialized(false) m_isInitialized(false)
{ {
@ -384,15 +405,15 @@ PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& ma
ei_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices"); ei_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
const int size = matrix.rows(); const int size = matrix.rows();
PermutationVectorType rows_transpositions(size); m_rowsTranspositions.resize(size);
int nb_transpositions; int nb_transpositions;
ei_partial_lu_inplace(m_lu, rows_transpositions, nb_transpositions); ei_partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions);
m_det_p = (nb_transpositions%2) ? -1 : 1; m_det_p = (nb_transpositions%2) ? -1 : 1;
m_p.setIdentity(size); m_p.setIdentity(size);
for(int k = size-1; k >= 0; --k) for(int k = size-1; k >= 0; --k)
m_p.applyTranspositionOnTheRight(k, rows_transpositions.coeff(k)); m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k));
m_isInitialized = true; m_isInitialized = true;
return *this; return *this;

View File

@ -70,11 +70,38 @@ template<typename _MatrixType> class ColPivHouseholderQR
* The default constructor is useful in cases in which the user intends to * The default constructor is useful in cases in which the user intends to
* perform decompositions via ColPivHouseholderQR::compute(const MatrixType&). * perform decompositions via ColPivHouseholderQR::compute(const MatrixType&).
*/ */
ColPivHouseholderQR() : m_qr(), m_hCoeffs(), m_isInitialized(false) {} ColPivHouseholderQR()
: m_qr(),
m_hCoeffs(),
m_colsPermutation(),
m_colsTranspositions(),
m_temp(),
m_colSqNorms(),
m_isInitialized(false) {}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa ColPivHouseholderQR()
*/
ColPivHouseholderQR(int rows, int cols)
: m_qr(rows, cols),
m_hCoeffs(std::min(rows,cols)),
m_colsPermutation(cols),
m_colsTranspositions(cols),
m_temp(cols),
m_colSqNorms(cols),
m_isInitialized(false),
m_usePrescribedThreshold(false) {}
ColPivHouseholderQR(const MatrixType& matrix) ColPivHouseholderQR(const MatrixType& matrix)
: m_qr(matrix.rows(), matrix.cols()), : m_qr(matrix.rows(), matrix.cols()),
m_hCoeffs(std::min(matrix.rows(),matrix.cols())), m_hCoeffs(std::min(matrix.rows(),matrix.cols())),
m_colsPermutation(matrix.cols()),
m_colsTranspositions(matrix.cols()),
m_temp(matrix.cols()),
m_colSqNorms(matrix.cols()),
m_isInitialized(false), m_isInitialized(false),
m_usePrescribedThreshold(false) m_usePrescribedThreshold(false)
{ {
@ -121,7 +148,7 @@ template<typename _MatrixType> class ColPivHouseholderQR
const PermutationType& colsPermutation() const const PermutationType& colsPermutation() const
{ {
ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
return m_cols_permutation; return m_colsPermutation;
} }
/** \returns the absolute value of the determinant of the matrix of which /** \returns the absolute value of the determinant of the matrix of which
@ -307,7 +334,10 @@ template<typename _MatrixType> class ColPivHouseholderQR
protected: protected:
MatrixType m_qr; MatrixType m_qr;
HCoeffsType m_hCoeffs; HCoeffsType m_hCoeffs;
PermutationType m_cols_permutation; PermutationType m_colsPermutation;
IntRowVectorType m_colsTranspositions;
RowVectorType m_temp;
RealRowVectorType m_colSqNorms;
bool m_isInitialized, m_usePrescribedThreshold; bool m_isInitialized, m_usePrescribedThreshold;
RealScalar m_prescribedThreshold, m_maxpivot; RealScalar m_prescribedThreshold, m_maxpivot;
int m_nonzero_pivots; int m_nonzero_pivots;
@ -342,35 +372,35 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const
m_qr = matrix; m_qr = matrix;
m_hCoeffs.resize(size); m_hCoeffs.resize(size);
RowVectorType temp(cols); m_temp.resize(cols);
IntRowVectorType cols_transpositions(matrix.cols()); m_colsTranspositions.resize(matrix.cols());
int number_of_transpositions = 0; int number_of_transpositions = 0;
RealRowVectorType colSqNorms(cols); m_colSqNorms.resize(cols);
for(int k = 0; k < cols; ++k) for(int k = 0; k < cols; ++k)
colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm(); m_colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm();
RealScalar threshold_helper = colSqNorms.maxCoeff() * ei_abs2(NumTraits<Scalar>::epsilon()) / rows; RealScalar threshold_helper = m_colSqNorms.maxCoeff() * ei_abs2(NumTraits<Scalar>::epsilon()) / rows;
m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case) m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
m_maxpivot = RealScalar(0); m_maxpivot = RealScalar(0);
for(int k = 0; k < size; ++k) for(int k = 0; k < size; ++k)
{ {
// first, we look up in our table colSqNorms which column has the biggest squared norm // first, we look up in our table m_colSqNorms which column has the biggest squared norm
int biggest_col_index; int biggest_col_index;
RealScalar biggest_col_sq_norm = colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index); RealScalar biggest_col_sq_norm = m_colSqNorms.tail(cols-k).maxCoeff(&biggest_col_index);
biggest_col_index += k; biggest_col_index += k;
// since our table colSqNorms accumulates imprecision at every step, we must now recompute // since our table m_colSqNorms accumulates imprecision at every step, we must now recompute
// the actual squared norm of the selected column. // the actual squared norm of the selected column.
// Note that not doing so does result in solve() sometimes returning inf/nan values // Note that not doing so does result in solve() sometimes returning inf/nan values
// when running the unit test with 1000 repetitions. // when running the unit test with 1000 repetitions.
biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm(); biggest_col_sq_norm = m_qr.col(biggest_col_index).tail(rows-k).squaredNorm();
// we store that back into our table: it can't hurt to correct our table. // we store that back into our table: it can't hurt to correct our table.
colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm; m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
// if the current biggest column is smaller than epsilon times the initial biggest column, // if the current biggest column is smaller than epsilon times the initial biggest column,
// terminate to avoid generating nan/inf values. // terminate to avoid generating nan/inf values.
@ -388,10 +418,10 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const
} }
// apply the transposition to the columns // apply the transposition to the columns
cols_transpositions.coeffRef(k) = biggest_col_index; m_colsTranspositions.coeffRef(k) = biggest_col_index;
if(k != biggest_col_index) { if(k != biggest_col_index) {
m_qr.col(k).swap(m_qr.col(biggest_col_index)); m_qr.col(k).swap(m_qr.col(biggest_col_index));
std::swap(colSqNorms.coeffRef(k), colSqNorms.coeffRef(biggest_col_index)); std::swap(m_colSqNorms.coeffRef(k), m_colSqNorms.coeffRef(biggest_col_index));
++number_of_transpositions; ++number_of_transpositions;
} }
@ -407,15 +437,15 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const
// apply the householder transformation // apply the householder transformation
m_qr.corner(BottomRight, rows-k, cols-k-1) m_qr.corner(BottomRight, rows-k, cols-k-1)
.applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &temp.coeffRef(k+1)); .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
// update our table of squared norms of the columns // update our table of squared norms of the columns
colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2(); m_colSqNorms.tail(cols-k-1) -= m_qr.row(k).tail(cols-k-1).cwiseAbs2();
} }
m_cols_permutation.setIdentity(cols); m_colsPermutation.setIdentity(cols);
for(int k = 0; k < m_nonzero_pivots; ++k) for(int k = 0; k < m_nonzero_pivots; ++k)
m_cols_permutation.applyTranspositionOnTheRight(k, cols_transpositions.coeff(k)); m_colsPermutation.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_det_pq = (number_of_transpositions%2) ? -1 : 1;
m_isInitialized = true; m_isInitialized = true;

View File

@ -69,10 +69,38 @@ template<typename _MatrixType> class FullPivHouseholderQR
* The default constructor is useful in cases in which the user intends to * The default constructor is useful in cases in which the user intends to
* perform decompositions via FullPivHouseholderQR::compute(const MatrixType&). * perform decompositions via FullPivHouseholderQR::compute(const MatrixType&).
*/ */
FullPivHouseholderQR() : m_isInitialized(false) {} FullPivHouseholderQR()
: m_qr(),
m_hCoeffs(),
m_rows_transpositions(),
m_cols_transpositions(),
m_cols_permutation(),
m_temp(),
m_isInitialized(false) {}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa FullPivHouseholderQR()
*/
FullPivHouseholderQR(int rows, int cols)
: m_qr(rows, cols),
m_hCoeffs(std::min(rows,cols)),
m_rows_transpositions(rows),
m_cols_transpositions(cols),
m_cols_permutation(cols),
m_temp(std::min(rows,cols)),
m_isInitialized(false) {}
FullPivHouseholderQR(const MatrixType& matrix) FullPivHouseholderQR(const MatrixType& matrix)
: m_isInitialized(false) : m_qr(matrix.rows(), matrix.cols()),
m_hCoeffs(std::min(matrix.rows(), matrix.cols())),
m_rows_transpositions(matrix.rows()),
m_cols_transpositions(matrix.cols()),
m_cols_permutation(matrix.cols()),
m_temp(std::min(matrix.rows(), matrix.cols())),
m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
} }
@ -233,7 +261,9 @@ template<typename _MatrixType> class FullPivHouseholderQR
MatrixType m_qr; MatrixType m_qr;
HCoeffsType m_hCoeffs; HCoeffsType m_hCoeffs;
IntColVectorType m_rows_transpositions; IntColVectorType m_rows_transpositions;
IntRowVectorType m_cols_transpositions;
PermutationType m_cols_permutation; PermutationType m_cols_permutation;
RowVectorType m_temp;
bool m_isInitialized; bool m_isInitialized;
RealScalar m_precision; RealScalar m_precision;
int m_rank; int m_rank;
@ -269,12 +299,12 @@ FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(cons
m_qr = matrix; m_qr = matrix;
m_hCoeffs.resize(size); m_hCoeffs.resize(size);
RowVectorType temp(cols); m_temp.resize(cols);
m_precision = NumTraits<Scalar>::epsilon() * size; m_precision = NumTraits<Scalar>::epsilon() * size;
m_rows_transpositions.resize(matrix.rows()); m_rows_transpositions.resize(matrix.rows());
IntRowVectorType cols_transpositions(matrix.cols()); m_cols_transpositions.resize(matrix.cols());
int number_of_transpositions = 0; int number_of_transpositions = 0;
RealScalar biggest(0); RealScalar biggest(0);
@ -298,14 +328,14 @@ FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(cons
for(int i = k; i < size; i++) for(int i = k; i < size; i++)
{ {
m_rows_transpositions.coeffRef(i) = i; m_rows_transpositions.coeffRef(i) = i;
cols_transpositions.coeffRef(i) = i; m_cols_transpositions.coeffRef(i) = i;
m_hCoeffs.coeffRef(i) = Scalar(0); m_hCoeffs.coeffRef(i) = Scalar(0);
} }
break; break;
} }
m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner; m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
cols_transpositions.coeffRef(k) = col_of_biggest_in_corner; m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
if(k != row_of_biggest_in_corner) { if(k != row_of_biggest_in_corner) {
m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k)); m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
++number_of_transpositions; ++number_of_transpositions;
@ -320,12 +350,12 @@ FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(cons
m_qr.coeffRef(k,k) = beta; m_qr.coeffRef(k,k) = beta;
m_qr.corner(BottomRight, rows-k, cols-k-1) m_qr.corner(BottomRight, rows-k, cols-k-1)
.applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &temp.coeffRef(k+1)); .applyHouseholderOnTheLeft(m_qr.col(k).tail(rows-k-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
} }
m_cols_permutation.setIdentity(cols); m_cols_permutation.setIdentity(cols);
for(int k = 0; k < size; ++k) for(int k = 0; k < size; ++k)
m_cols_permutation.applyTranspositionOnTheRight(k, cols_transpositions.coeff(k)); m_cols_permutation.applyTranspositionOnTheRight(k, m_cols_transpositions.coeff(k));
m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_det_pq = (number_of_transpositions%2) ? -1 : 1;
m_isInitialized = true; m_isInitialized = true;

View File

@ -71,11 +71,24 @@ template<typename _MatrixType> class HouseholderQR
* The default constructor is useful in cases in which the user intends to * The default constructor is useful in cases in which the user intends to
* perform decompositions via HouseholderQR::compute(const MatrixType&). * perform decompositions via HouseholderQR::compute(const MatrixType&).
*/ */
HouseholderQR() : m_qr(), m_hCoeffs(), m_isInitialized(false) {} HouseholderQR() : m_qr(), m_hCoeffs(), m_temp(), m_isInitialized(false) {}
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa HouseholderQR()
*/
HouseholderQR(int rows, int cols)
: m_qr(rows, cols),
m_hCoeffs(std::min(rows,cols)),
m_temp(cols),
m_isInitialized(false) {}
HouseholderQR(const MatrixType& matrix) HouseholderQR(const MatrixType& matrix)
: m_qr(matrix.rows(), matrix.cols()), : m_qr(matrix.rows(), matrix.cols()),
m_hCoeffs(std::min(matrix.rows(),matrix.cols())), m_hCoeffs(std::min(matrix.rows(),matrix.cols())),
m_temp(matrix.cols()),
m_isInitialized(false) m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
@ -159,6 +172,7 @@ template<typename _MatrixType> class HouseholderQR
protected: protected:
MatrixType m_qr; MatrixType m_qr;
HCoeffsType m_hCoeffs; HCoeffsType m_hCoeffs;
RowVectorType m_temp;
bool m_isInitialized; bool m_isInitialized;
}; };
@ -190,7 +204,7 @@ HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType&
m_qr = matrix; m_qr = matrix;
m_hCoeffs.resize(size); m_hCoeffs.resize(size);
RowVectorType temp(cols); m_temp.resize(cols);
for(int k = 0; k < size; ++k) for(int k = 0; k < size; ++k)
{ {
@ -203,7 +217,7 @@ HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType&
// apply H to remaining part of m_qr from the left // apply H to remaining part of m_qr from the left
m_qr.corner(BottomRight, remainingRows, remainingCols) m_qr.corner(BottomRight, remainingRows, remainingCols)
.applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingRows-1), m_hCoeffs.coeffRef(k), &temp.coeffRef(k+1)); .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingRows-1), m_hCoeffs.coeffRef(k), &m_temp.coeffRef(k+1));
} }
m_isInitialized = true; m_isInitialized = true;
return *this; return *this;

View File

@ -93,10 +93,35 @@ template<typename MatrixType, unsigned int Options> class JacobiSVD
public: public:
/** \brief Default Constructor.
*
* The default constructor is useful in cases in which the user intends to
* perform decompositions via JacobiSVD::compute(const MatrixType&).
*/
JacobiSVD() : m_isInitialized(false) {} JacobiSVD() : m_isInitialized(false) {}
JacobiSVD(const MatrixType& matrix) : m_isInitialized(false)
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa JacobiSVD()
*/
JacobiSVD(int rows, int cols) : m_matrixU(rows, rows),
m_matrixV(cols, cols),
m_singularValues(std::min(rows, cols)),
m_workMatrix(rows, cols),
m_isInitialized(false) {}
JacobiSVD(const MatrixType& matrix) : m_matrixU(matrix.rows(), matrix.rows()),
m_matrixV(matrix.cols(), matrix.cols()),
m_singularValues(),
m_workMatrix(),
m_isInitialized(false)
{ {
const int minSize = std::min(matrix.rows(), matrix.cols());
m_singularValues.resize(minSize);
m_workMatrix.resize(minSize, minSize);
compute(matrix); compute(matrix);
} }
@ -124,6 +149,7 @@ template<typename MatrixType, unsigned int Options> class JacobiSVD
MatrixUType m_matrixU; MatrixUType m_matrixU;
MatrixVType m_matrixV; MatrixVType m_matrixV;
SingularValuesType m_singularValues; SingularValuesType m_singularValues;
WorkMatrixType m_workMatrix;
bool m_isInitialized; bool m_isInitialized;
template<typename _MatrixType, unsigned int _Options, bool _IsComplex> template<typename _MatrixType, unsigned int _Options, bool _IsComplex>
@ -289,17 +315,16 @@ struct ei_svd_precondition_if_more_cols_than_rows<MatrixType, Options, true>
template<typename MatrixType, unsigned int Options> template<typename MatrixType, unsigned int Options>
JacobiSVD<MatrixType, Options>& JacobiSVD<MatrixType, Options>::compute(const MatrixType& matrix) JacobiSVD<MatrixType, Options>& JacobiSVD<MatrixType, Options>::compute(const MatrixType& matrix)
{ {
WorkMatrixType work_matrix;
int rows = matrix.rows(); int rows = matrix.rows();
int cols = matrix.cols(); int cols = matrix.cols();
int diagSize = std::min(rows, cols); int diagSize = std::min(rows, cols);
m_singularValues.resize(diagSize); m_singularValues.resize(diagSize);
const RealScalar precision = 2 * NumTraits<Scalar>::epsilon(); const RealScalar precision = 2 * NumTraits<Scalar>::epsilon();
if(!ei_svd_precondition_if_more_rows_than_cols<MatrixType, Options>::run(matrix, work_matrix, *this) if(!ei_svd_precondition_if_more_rows_than_cols<MatrixType, Options>::run(matrix, m_workMatrix, *this)
&& !ei_svd_precondition_if_more_cols_than_rows<MatrixType, Options>::run(matrix, work_matrix, *this)) && !ei_svd_precondition_if_more_cols_than_rows<MatrixType, Options>::run(matrix, m_workMatrix, *this))
{ {
work_matrix = matrix.block(0,0,diagSize,diagSize); m_workMatrix = matrix.block(0,0,diagSize,diagSize);
if(ComputeU) m_matrixU.setIdentity(rows,rows); if(ComputeU) m_matrixU.setIdentity(rows,rows);
if(ComputeV) m_matrixV.setIdentity(cols,cols); if(ComputeV) m_matrixV.setIdentity(cols,cols);
} }
@ -312,19 +337,19 @@ JacobiSVD<MatrixType, Options>& JacobiSVD<MatrixType, Options>::compute(const Ma
{ {
for(int q = 0; q < p; ++q) for(int q = 0; q < p; ++q)
{ {
if(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p))) if(std::max(ei_abs(m_workMatrix.coeff(p,q)),ei_abs(m_workMatrix.coeff(q,p)))
> std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision) > std::max(ei_abs(m_workMatrix.coeff(p,p)),ei_abs(m_workMatrix.coeff(q,q)))*precision)
{ {
finished = false; finished = false;
ei_svd_precondition_2x2_block_to_be_real<MatrixType, Options>::run(work_matrix, *this, p, q); ei_svd_precondition_2x2_block_to_be_real<MatrixType, Options>::run(m_workMatrix, *this, p, q);
PlanarRotation<RealScalar> j_left, j_right; PlanarRotation<RealScalar> j_left, j_right;
ei_real_2x2_jacobi_svd(work_matrix, p, q, &j_left, &j_right); ei_real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
work_matrix.applyOnTheLeft(p,q,j_left); m_workMatrix.applyOnTheLeft(p,q,j_left);
if(ComputeU) m_matrixU.applyOnTheRight(p,q,j_left.transpose()); if(ComputeU) m_matrixU.applyOnTheRight(p,q,j_left.transpose());
work_matrix.applyOnTheRight(p,q,j_right); m_workMatrix.applyOnTheRight(p,q,j_right);
if(ComputeV) m_matrixV.applyOnTheRight(p,q,j_right); if(ComputeV) m_matrixV.applyOnTheRight(p,q,j_right);
} }
} }
@ -333,9 +358,9 @@ JacobiSVD<MatrixType, Options>& JacobiSVD<MatrixType, Options>::compute(const Ma
for(int i = 0; i < diagSize; ++i) for(int i = 0; i < diagSize; ++i)
{ {
RealScalar a = ei_abs(work_matrix.coeff(i,i)); RealScalar a = ei_abs(m_workMatrix.coeff(i,i));
m_singularValues.coeffRef(i) = a; m_singularValues.coeffRef(i) = a;
if(ComputeU && (a!=RealScalar(0))) m_matrixU.col(i) *= work_matrix.coeff(i,i)/a; if(ComputeU && (a!=RealScalar(0))) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a;
} }
for(int i = 0; i < diagSize; i++) for(int i = 0; i < diagSize; i++)

View File

@ -73,11 +73,25 @@ template<typename _MatrixType> class SVD
*/ */
SVD() : m_matU(), m_matV(), m_sigma(), m_isInitialized(false) {} SVD() : m_matU(), m_matV(), m_sigma(), m_isInitialized(false) {}
SVD(const MatrixType& matrix) /** \brief Default Constructor with memory preallocation
: m_matU(matrix.rows(), matrix.rows()), *
m_matV(matrix.cols(),matrix.cols()), * Like the default constructor but with preallocation of the internal data
m_sigma(matrix.cols()), * according to the specified problem \a size.
m_isInitialized(false) * \sa JacobiSVD()
*/
SVD(int rows, int cols) : m_matU(rows, rows),
m_matV(cols,cols),
m_sigma(std::min(rows, cols)),
m_workMatrix(rows, cols),
m_rv1(cols),
m_isInitialized(false) {}
SVD(const MatrixType& matrix) : m_matU(matrix.rows(), matrix.rows()),
m_matV(matrix.cols(),matrix.cols()),
m_sigma(std::min(matrix.rows(), matrix.cols())),
m_workMatrix(matrix.rows(), matrix.cols()),
m_rv1(matrix.cols()),
m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
} }
@ -165,6 +179,8 @@ template<typename _MatrixType> class SVD
MatrixVType m_matV; MatrixVType m_matV;
/** \internal */ /** \internal */
SingularValuesType m_sigma; SingularValuesType m_sigma;
MatrixType m_workMatrix;
RowVector m_rv1;
bool m_isInitialized; bool m_isInitialized;
int m_rows, m_cols; int m_rows, m_cols;
}; };
@ -185,11 +201,12 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
m_matU.setZero(); m_matU.setZero();
m_sigma.resize(n); m_sigma.resize(n);
m_matV.resize(n,n); m_matV.resize(n,n);
m_workMatrix = matrix;
int max_iters = 30; int max_iters = 30;
MatrixVType& V = m_matV; MatrixVType& V = m_matV;
MatrixType A = matrix; MatrixType& A = m_workMatrix;
SingularValuesType& W = m_sigma; SingularValuesType& W = m_sigma;
bool flag; bool flag;
@ -198,14 +215,14 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
bool convergence = true; bool convergence = true;
Scalar eps = NumTraits<Scalar>::dummy_precision(); Scalar eps = NumTraits<Scalar>::dummy_precision();
RowVector rv1(n); m_rv1.resize(n);
g = scale = anorm = 0; g = scale = anorm = 0;
// Householder reduction to bidiagonal form. // Householder reduction to bidiagonal form.
for (i=0; i<n; i++) for (i=0; i<n; i++)
{ {
l = i+2; l = i+2;
rv1[i] = scale*g; m_rv1[i] = scale*g;
g = s = scale = 0.0; g = s = scale = 0.0;
if (i < m) if (i < m)
{ {
@ -246,16 +263,16 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
g = -sign(ei_sqrt(s),f); g = -sign(ei_sqrt(s),f);
h = f*g - s; h = f*g - s;
A(i,l-1) = f-g; A(i,l-1) = f-g;
rv1.tail(n-l+1) = A.row(i).tail(n-l+1)/h; m_rv1.tail(n-l+1) = A.row(i).tail(n-l+1)/h;
for (j=l-1; j<m; j++) for (j=l-1; j<m; j++)
{ {
s = A.row(i).tail(n-l+1).dot(A.row(j).tail(n-l+1)); s = A.row(i).tail(n-l+1).dot(A.row(j).tail(n-l+1));
A.row(j).tail(n-l+1) += s*rv1.tail(n-l+1).transpose(); A.row(j).tail(n-l+1) += s*m_rv1.tail(n-l+1).transpose();
} }
A.row(i).tail(n-l+1) *= scale; A.row(i).tail(n-l+1) *= scale;
} }
} }
anorm = std::max( anorm, (ei_abs(W[i])+ei_abs(rv1[i])) ); anorm = std::max( anorm, (ei_abs(W[i])+ei_abs(m_rv1[i])) );
} }
// Accumulation of right-hand transformations. // Accumulation of right-hand transformations.
for (i=n-1; i>=0; i--) for (i=n-1; i>=0; i--)
@ -277,7 +294,7 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
V.col(i).tail(n-l).setZero(); V.col(i).tail(n-l).setZero();
} }
V(i, i) = 1.0; V(i, i) = 1.0;
g = rv1[i]; g = m_rv1[i];
l = i; l = i;
} }
// Accumulation of left-hand transformations. // Accumulation of left-hand transformations.
@ -318,7 +335,7 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
nm = l-1; nm = l-1;
// Note that rv1[1] is always zero. // Note that rv1[1] is always zero.
//if ((double)(ei_abs(rv1[l])+anorm) == anorm) //if ((double)(ei_abs(rv1[l])+anorm) == anorm)
if (l==0 || ei_abs(rv1[l]) <= eps*anorm) if (l==0 || ei_abs(m_rv1[l]) <= eps*anorm)
{ {
flag = false; flag = false;
break; break;
@ -333,8 +350,8 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
s = 1.0; s = 1.0;
for (i=l ;i<k+1; i++) for (i=l ;i<k+1; i++)
{ {
f = s*rv1[i]; f = s*m_rv1[i];
rv1[i] = c*rv1[i]; m_rv1[i] = c*m_rv1[i];
//if ((double)(ei_abs(f)+anorm) == anorm) //if ((double)(ei_abs(f)+anorm) == anorm)
if (ei_abs(f) <= eps*anorm) if (ei_abs(f) <= eps*anorm)
break; break;
@ -363,8 +380,8 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
x = W[l]; // Shift from bottom 2-by-2 minor. x = W[l]; // Shift from bottom 2-by-2 minor.
nm = k-1; nm = k-1;
y = W[nm]; y = W[nm];
g = rv1[nm]; g = m_rv1[nm];
h = rv1[k]; h = m_rv1[k];
f = ((y-z)*(y+z) + (g-h)*(g+h))/(Scalar(2.0)*h*y); f = ((y-z)*(y+z) + (g-h)*(g+h))/(Scalar(2.0)*h*y);
g = pythag(f,1.0); g = pythag(f,1.0);
f = ((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x; f = ((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x;
@ -373,13 +390,13 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
for (j=l; j<=nm; j++) for (j=l; j<=nm; j++)
{ {
i = j+1; i = j+1;
g = rv1[i]; g = m_rv1[i];
y = W[i]; y = W[i];
h = s*g; h = s*g;
g = c*g; g = c*g;
z = pythag(f,h); z = pythag(f,h);
rv1[j] = z; m_rv1[j] = z;
c = f/z; c = f/z;
s = h/z; s = h/z;
f = x*c + g*s; f = x*c + g*s;
@ -401,8 +418,8 @@ SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
x = c*y - s*g; x = c*y - s*g;
A.applyOnTheRight(i,j,PlanarRotation<Scalar>(c,s)); A.applyOnTheRight(i,j,PlanarRotation<Scalar>(c,s));
} }
rv1[l] = 0.0; m_rv1[l] = 0.0;
rv1[k] = f; m_rv1[k] = f;
W[k] = x; W[k] = x;
} }
} }

View File

@ -163,4 +163,8 @@ void test_cholesky()
CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() ); CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() );
CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() ); CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() );
CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() ); CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() );
// Test problem size constructors
CALL_SUBTEST_9( LLT<MatrixXf>(10) );
CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
} }

View File

@ -63,4 +63,7 @@ void test_eigensolver_complex()
CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) ); CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
CALL_SUBTEST_4( eigensolver(Matrix3f()) ); CALL_SUBTEST_4( eigensolver(Matrix3f()) );
} }
// Test problem size constructors
CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(10));
} }

View File

@ -89,4 +89,7 @@ void test_eigensolver_generic()
CALL_SUBTEST_2( eigensolver_verify_assert<MatrixXd>() ); CALL_SUBTEST_2( eigensolver_verify_assert<MatrixXd>() );
CALL_SUBTEST_4( eigensolver_verify_assert<Matrix2d>() ); CALL_SUBTEST_4( eigensolver_verify_assert<Matrix2d>() );
CALL_SUBTEST_5( eigensolver_verify_assert<MatrixXf>() ); CALL_SUBTEST_5( eigensolver_verify_assert<MatrixXf>() );
// Test problem size constructors
CALL_SUBTEST_6(EigenSolver<MatrixXf>(10));
} }

View File

@ -129,5 +129,9 @@ void test_eigensolver_selfadjoint()
CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) ); CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) );
CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) ); CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) );
} }
// Test problem size constructors
CALL_SUBTEST_8(SelfAdjointEigenSolver<MatrixXf>(10));
CALL_SUBTEST_8(Tridiagonalization<MatrixXf>(10));
} }

View File

@ -61,4 +61,7 @@ void test_hessenberg()
CALL_SUBTEST_3(( hessenberg<std::complex<float>,4>() )); CALL_SUBTEST_3(( hessenberg<std::complex<float>,4>() ));
CALL_SUBTEST_4(( hessenberg<float,Dynamic>(ei_random<int>(1,320)) )); CALL_SUBTEST_4(( hessenberg<float,Dynamic>(ei_random<int>(1,320)) ));
CALL_SUBTEST_5(( hessenberg<std::complex<double>,Dynamic>(ei_random<int>(1,320)) )); CALL_SUBTEST_5(( hessenberg<std::complex<double>,Dynamic>(ei_random<int>(1,320)) ));
// Test problem size constructors
CALL_SUBTEST_6(HessenbergDecomposition<MatrixXf>(10));
} }

View File

@ -106,4 +106,7 @@ void test_jacobisvd()
CALL_SUBTEST_3(( svd_verify_assert<Matrix3d>() )); CALL_SUBTEST_3(( svd_verify_assert<Matrix3d>() ));
CALL_SUBTEST_9(( svd_verify_assert<MatrixXf>() )); CALL_SUBTEST_9(( svd_verify_assert<MatrixXf>() ));
CALL_SUBTEST_11(( svd_verify_assert<MatrixXd>() )); CALL_SUBTEST_11(( svd_verify_assert<MatrixXd>() ));
// Test problem size constructors
CALL_SUBTEST_12( JacobiSVD<MatrixXf>(10, 20) );
} }

View File

@ -212,5 +212,9 @@ void test_lu()
CALL_SUBTEST_6( lu_verify_assert<MatrixXcd>() ); CALL_SUBTEST_6( lu_verify_assert<MatrixXcd>() );
CALL_SUBTEST_7(( lu_non_invertible<Matrix<float,Dynamic,16> >() )); CALL_SUBTEST_7(( lu_non_invertible<Matrix<float,Dynamic,16> >() ));
// Test problem size constructors
CALL_SUBTEST_9( PartialPivLU<MatrixXf>(10) );
CALL_SUBTEST_9( FullPivLU<MatrixXf>(10, 20); );
} }
} }

View File

@ -133,4 +133,7 @@ void test_qr()
CALL_SUBTEST_6(qr_verify_assert<MatrixXd>()); CALL_SUBTEST_6(qr_verify_assert<MatrixXd>());
CALL_SUBTEST_7(qr_verify_assert<MatrixXcf>()); CALL_SUBTEST_7(qr_verify_assert<MatrixXcf>());
CALL_SUBTEST_8(qr_verify_assert<MatrixXcd>()); CALL_SUBTEST_8(qr_verify_assert<MatrixXcd>());
// Test problem size constructors
CALL_SUBTEST_12(HouseholderQR<MatrixXf>(10, 20));
} }

View File

@ -157,4 +157,7 @@ void test_qr_colpivoting()
CALL_SUBTEST_2(qr_verify_assert<MatrixXd>()); CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>()); CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>());
CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>()); CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
// Test problem size constructors
CALL_SUBTEST_9(ColPivHouseholderQR<MatrixXf>(10, 20));
} }

View File

@ -139,4 +139,7 @@ void test_qr_fullpivoting()
CALL_SUBTEST_2(qr_verify_assert<MatrixXd>()); CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
CALL_SUBTEST_4(qr_verify_assert<MatrixXcf>()); CALL_SUBTEST_4(qr_verify_assert<MatrixXcf>());
CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>()); CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
// Test problem size constructors
CALL_SUBTEST_7(FullPivHouseholderQR<MatrixXf>(10, 20));
} }

View File

@ -64,4 +64,7 @@ void test_schur_complex()
CALL_SUBTEST_2(( schur<MatrixXcf>(ei_random<int>(1,50)) )); CALL_SUBTEST_2(( schur<MatrixXcf>(ei_random<int>(1,50)) ));
CALL_SUBTEST_3(( schur<Matrix<std::complex<float>, 1, 1> >() )); CALL_SUBTEST_3(( schur<Matrix<std::complex<float>, 1, 1> >() ));
CALL_SUBTEST_4(( schur<Matrix<float, 3, 3, Eigen::RowMajor> >() )); CALL_SUBTEST_4(( schur<Matrix<float, 3, 3, Eigen::RowMajor> >() ));
// Test problem size constructors
CALL_SUBTEST_5(ComplexSchur<MatrixXf>(10));
} }

View File

@ -82,4 +82,7 @@ void test_schur_real()
CALL_SUBTEST_2(( schur<MatrixXd>(ei_random<int>(1,50)) )); CALL_SUBTEST_2(( schur<MatrixXd>(ei_random<int>(1,50)) ));
CALL_SUBTEST_3(( schur<Matrix<float, 1, 1> >() )); CALL_SUBTEST_3(( schur<Matrix<float, 1, 1> >() ));
CALL_SUBTEST_4(( schur<Matrix<double, 3, 3, Eigen::RowMajor> >() )); CALL_SUBTEST_4(( schur<Matrix<double, 3, 3, Eigen::RowMajor> >() ));
// Test problem size constructors
CALL_SUBTEST_5(RealSchur<MatrixXf>(10));
} }

View File

@ -113,4 +113,7 @@ void test_svd()
CALL_SUBTEST_2( svd_verify_assert<Matrix4d>() ); CALL_SUBTEST_2( svd_verify_assert<Matrix4d>() );
CALL_SUBTEST_3( svd_verify_assert<MatrixXf>() ); CALL_SUBTEST_3( svd_verify_assert<MatrixXf>() );
CALL_SUBTEST_4( svd_verify_assert<MatrixXd>() ); CALL_SUBTEST_4( svd_verify_assert<MatrixXd>() );
// Test problem size constructors
CALL_SUBTEST_9( SVD<MatrixXf>(10, 20) );
} }