From db8631b66a4f5cb9957a58cc629be5ef438e3059 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sun, 30 May 2010 21:49:35 +0100 Subject: [PATCH 01/67] Guard with assert against using decomposition objects uninitialized. --- .../src/Eigenvalues/HessenbergDecomposition.h | 29 +++++++++-- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 51 ++++++++++++------- Eigen/src/Eigenvalues/Tridiagonalization.h | 27 ++++++++-- test/eigensolver_complex.cpp | 12 +++++ test/eigensolver_selfadjoint.cpp | 14 +++++ test/hessenberg.cpp | 7 +++ 6 files changed, 113 insertions(+), 27 deletions(-) diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index 1111ffb12..220531bf5 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -107,7 +107,8 @@ template class HessenbergDecomposition */ HessenbergDecomposition(Index size = Size==Dynamic ? 2 : Size) : m_matrix(size,size), - m_temp(size) + m_temp(size), + m_isInitialized(false) { if(size>1) m_hCoeffs.resize(size-1); @@ -124,12 +125,17 @@ template class HessenbergDecomposition */ HessenbergDecomposition(const MatrixType& matrix) : m_matrix(matrix), - m_temp(matrix.rows()) + m_temp(matrix.rows()), + m_isInitialized(false) { if(matrix.rows()<2) + { + m_isInitialized = true; return; + } m_hCoeffs.resize(matrix.rows()-1,1); _compute(m_matrix, m_hCoeffs, m_temp); + m_isInitialized = true; } /** \brief Computes Hessenberg decomposition of given matrix. @@ -152,9 +158,13 @@ template class HessenbergDecomposition { m_matrix = matrix; if(matrix.rows()<2) + { + m_isInitialized = true; return; + } m_hCoeffs.resize(matrix.rows()-1,1); _compute(m_matrix, m_hCoeffs, m_temp); + m_isInitialized = true; } /** \brief Returns the Householder coefficients. @@ -170,7 +180,11 @@ template class HessenbergDecomposition * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - const CoeffVectorType& householderCoefficients() const { return m_hCoeffs; } + const CoeffVectorType& householderCoefficients() const + { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); + return m_hCoeffs; + } /** \brief Returns the internal representation of the decomposition * @@ -201,7 +215,11 @@ template class HessenbergDecomposition * * \sa householderCoefficients() */ - const MatrixType& packedMatrix() const { return m_matrix; } + const MatrixType& packedMatrix() const + { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); + return m_matrix; + } /** \brief Reconstructs the orthogonal matrix Q in the decomposition * @@ -219,6 +237,7 @@ template class HessenbergDecomposition */ HouseholderSequenceType matrixQ() const { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate(), false, m_matrix.rows() - 1, 1); } @@ -244,6 +263,7 @@ template class HessenbergDecomposition */ HessenbergDecompositionMatrixHReturnType matrixH() const { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); return HessenbergDecompositionMatrixHReturnType(*this); } @@ -257,6 +277,7 @@ template class HessenbergDecomposition MatrixType m_matrix; CoeffVectorType m_hCoeffs; VectorType m_temp; + bool m_isInitialized; }; #ifndef EIGEN_HIDE_HEAVY_CODE diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 2c53655d1..20773a549 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -115,10 +115,9 @@ template class SelfAdjointEigenSolver : m_eivec(), m_eivalues(), m_tridiag(), - m_subdiag() - { - ei_assert(Size!=Dynamic); - } + m_subdiag(), + m_isInitialized(false) + { } /** \brief Constructor, pre-allocates memory for dynamic-size matrices. * @@ -137,7 +136,8 @@ template class SelfAdjointEigenSolver : m_eivec(size, size), m_eivalues(size), m_tridiag(size), - m_subdiag(size > 1 ? size - 1 : 1) + m_subdiag(size > 1 ? size - 1 : 1), + m_isInitialized(false) {} /** \brief Constructor; computes eigendecomposition of given matrix. @@ -162,7 +162,8 @@ template class SelfAdjointEigenSolver : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), m_tridiag(matrix.rows()), - m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1) + m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1), + m_isInitialized(false) { compute(matrix, computeEigenvectors); } @@ -192,7 +193,8 @@ template class SelfAdjointEigenSolver : m_eivec(matA.rows(), matA.cols()), m_eivalues(matA.cols()), m_tridiag(matA.rows()), - m_subdiag(matA.rows() > 1 ? matA.rows() - 1 : 1) + m_subdiag(matA.rows() > 1 ? matA.rows() - 1 : 1), + m_isInitialized(false) { compute(matA, matB, computeEigenvectors); } @@ -283,9 +285,8 @@ template class SelfAdjointEigenSolver */ const MatrixType& eigenvectors() const { - #ifndef NDEBUG - ei_assert(m_eigenvectorsOk); - #endif + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } @@ -303,7 +304,11 @@ template class SelfAdjointEigenSolver * * \sa eigenvectors(), MatrixBase::eigenvalues() */ - const RealVectorType& eigenvalues() const { return m_eivalues; } + const RealVectorType& eigenvalues() const + { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + return m_eivalues; + } /** \brief Computes the positive-definite square root of the matrix. * @@ -325,6 +330,8 @@ template class SelfAdjointEigenSolver */ MatrixType operatorSqrt() const { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } @@ -348,6 +355,8 @@ template class SelfAdjointEigenSolver */ MatrixType operatorInverseSqrt() const { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } @@ -357,9 +366,8 @@ template class SelfAdjointEigenSolver RealVectorType m_eivalues; TridiagonalizationType m_tridiag; typename TridiagonalizationType::SubDiagonalType m_subdiag; - #ifndef NDEBUG + bool m_isInitialized; bool m_eigenvectorsOk; - #endif }; #ifndef EIGEN_HIDE_HEAVY_CODE @@ -386,18 +394,19 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index template SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { - #ifndef NDEBUG - m_eigenvectorsOk = computeEigenvectors; - #endif assert(matrix.cols() == matrix.rows()); Index n = matrix.cols(); m_eivalues.resize(n,1); - m_eivec.resize(n,n); + if(computeEigenvectors) + m_eivec.resize(n,n); if(n==1) { m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0)); - m_eivec.setOnes(); + if(computeEigenvectors) + m_eivec.setOnes(); + m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; return *this; } @@ -438,9 +447,13 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( if (k > 0) { std::swap(m_eivalues[i], m_eivalues[k+i]); - m_eivec.col(i).swap(m_eivec.col(k+i)); + if(computeEigenvectors) + m_eivec.col(i).swap(m_eivec.col(k+i)); } } + + m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; return *this; } diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index 02917f2e6..e204c30ea 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -109,7 +109,9 @@ template class Tridiagonalization * \sa compute() for an example. */ Tridiagonalization(Index size = Size==Dynamic ? 2 : Size) - : m_matrix(size,size), m_hCoeffs(size > 1 ? size-1 : 1) + : m_matrix(size,size), + m_hCoeffs(size > 1 ? size-1 : 1), + m_isInitialized(false) {} /** \brief Constructor; computes tridiagonal decomposition of given matrix. @@ -123,9 +125,12 @@ template class Tridiagonalization * Output: \verbinclude Tridiagonalization_Tridiagonalization_MatrixType.out */ Tridiagonalization(const MatrixType& matrix) - : m_matrix(matrix), m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1) + : m_matrix(matrix), + m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1), + m_isInitialized(false) { _compute(m_matrix, m_hCoeffs); + m_isInitialized = true; } /** \brief Computes tridiagonal decomposition of given matrix. @@ -149,6 +154,7 @@ template class Tridiagonalization m_matrix = matrix; m_hCoeffs.resize(matrix.rows()-1, 1); _compute(m_matrix, m_hCoeffs); + m_isInitialized = true; } /** \brief Returns the Householder coefficients. @@ -167,7 +173,11 @@ template class Tridiagonalization * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - inline CoeffVectorType householderCoefficients() const { return m_hCoeffs; } + inline CoeffVectorType householderCoefficients() const + { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); + return m_hCoeffs; + } /** \brief Returns the internal representation of the decomposition * @@ -200,7 +210,11 @@ template class Tridiagonalization * * \sa householderCoefficients() */ - inline const MatrixType& packedMatrix() const { return m_matrix; } + inline const MatrixType& packedMatrix() const + { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); + return m_matrix; + } /** \brief Returns the unitary matrix Q in the decomposition * @@ -219,6 +233,7 @@ template class Tridiagonalization */ HouseholderSequenceType matrixQ() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate(), false, m_matrix.rows() - 1, 1); } @@ -312,12 +327,14 @@ template class Tridiagonalization MatrixType m_matrix; CoeffVectorType m_hCoeffs; + bool m_isInitialized; }; template const typename Tridiagonalization::DiagonalReturnType Tridiagonalization::diagonal() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); return m_matrix.diagonal(); } @@ -325,6 +342,7 @@ template const typename Tridiagonalization::SubDiagonalReturnType Tridiagonalization::subDiagonal() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); Index n = m_matrix.rows(); return Block(m_matrix, 1, 0, n-1,n-1).diagonal(); } @@ -335,6 +353,7 @@ Tridiagonalization::matrixT() const { // FIXME should this function (and other similar ones) rather take a matrix as argument // and fill it ? (to avoid temporaries) + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); Index n = m_matrix.rows(); MatrixType matT = m_matrix; matT.topRightCorner(n-1, n-1).diagonal() = subDiagonal().template cast().conjugate(); diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 5c5d7b38f..4437d9811 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -76,6 +76,13 @@ template void eigensolver(const MatrixType& m) VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); } +template void eigensolver_verify_assert() +{ + ComplexEigenSolver eig; + VERIFY_RAISES_ASSERT(eig.eigenvectors()) + VERIFY_RAISES_ASSERT(eig.eigenvalues()) +} + void test_eigensolver_complex() { for(int i = 0; i < g_repeat; i++) { @@ -85,6 +92,11 @@ void test_eigensolver_complex() CALL_SUBTEST_4( eigensolver(Matrix3f()) ); } + CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) ); + CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(14,14)) ); + CALL_SUBTEST_3( eigensolver_verify_assert(Matrix, 1, 1>()) ); + CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) ); + // Test problem size constructors CALL_SUBTEST_5(ComplexEigenSolver(10)); } diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 25ef280a1..3ff84c4e0 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -105,6 +105,9 @@ template void selfadjointeigensolver(const MatrixType& m) eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); VERIFY_IS_APPROX(symmA.template selfadjointView().eigenvalues(), eiSymm.eigenvalues()); + SelfAdjointEigenSolver eiSymmNoEivecs(symmA, false); + VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues()); + // generalized eigen problem Ax = lBx VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); @@ -115,6 +118,17 @@ template void selfadjointeigensolver(const MatrixType& m) MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.template selfadjointView().operatorNorm(), RealScalar(1)); + + SelfAdjointEigenSolver eiSymmUninitialized; + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt()); + + eiSymmUninitialized.compute(symmA, false); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt()); } void test_eigensolver_selfadjoint() diff --git a/test/hessenberg.cpp b/test/hessenberg.cpp index 16aa564ae..b4cfe288d 100644 --- a/test/hessenberg.cpp +++ b/test/hessenberg.cpp @@ -54,6 +54,13 @@ template void hessenberg(int size = Size) MatrixType cs2Q = cs2.matrixQ(); VERIFY_IS_EQUAL(cs1Q, cs2Q); + // Test assertions for when used uninitialized + HessenbergDecomposition hessUninitialized; + VERIFY_RAISES_ASSERT( hessUninitialized.matrixH() ); + VERIFY_RAISES_ASSERT( hessUninitialized.matrixQ() ); + VERIFY_RAISES_ASSERT( hessUninitialized.householderCoefficients() ); + VERIFY_RAISES_ASSERT( hessUninitialized.packedMatrix() ); + // TODO: Add tests for packedMatrix() and householderCoefficients() } From 07a65dd02b2e454de83f5b78ea290b2e90593c11 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Mon, 31 May 2010 11:48:47 +0100 Subject: [PATCH 02/67] Fix stupid compilation error in test. --- test/eigensolver_complex.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 4437d9811..1440cd700 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -92,10 +92,10 @@ void test_eigensolver_complex() CALL_SUBTEST_4( eigensolver(Matrix3f()) ); } - CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) ); - CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(14,14)) ); - CALL_SUBTEST_3( eigensolver_verify_assert(Matrix, 1, 1>()) ); - CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) ); + CALL_SUBTEST_1( eigensolver_verify_assert() ); + CALL_SUBTEST_2( eigensolver_verify_assert() ); + CALL_SUBTEST_3(( eigensolver_verify_assert, 1, 1> >() )); + CALL_SUBTEST_4( eigensolver_verify_assert() ); // Test problem size constructors CALL_SUBTEST_5(ComplexEigenSolver(10)); From c21390a6113e7d9759217dffef9361576decbaa0 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Mon, 31 May 2010 14:42:04 +0100 Subject: [PATCH 03/67] Define non-const operator() in Reverse; enable test for this. Introduction of DenseCoeffBase (revision bfdc1c49730c79e6058ba1506628341559670c25 ) meant that non-const operator() is only defined if DirectAccess is set. This caused the line "m.reverse()(1,0) = 4;" in MatrixBase_reverse.cpp to fail at compile-time. Not sure this is correct solution; perhaps we should disallow this? Or make Reverse DirectAccess with a negative stride - would that break something? --- Eigen/src/Array/Reverse.h | 16 +++++++++++++ Eigen/src/Array/VectorwiseOp.h | 4 ++-- test/array_reverse.cpp | 42 +--------------------------------- 3 files changed, 19 insertions(+), 43 deletions(-) diff --git a/Eigen/src/Array/Reverse.h b/Eigen/src/Array/Reverse.h index cca425142..2d7510902 100644 --- a/Eigen/src/Array/Reverse.h +++ b/Eigen/src/Array/Reverse.h @@ -84,6 +84,10 @@ template class Reverse EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) using Base::IsRowMajor; + // next line is necessary because otherwise const version of operator() + // is hidden by non-const version defined in this file + using Base::operator(); + protected: enum { PacketSize = ei_packet_traits::size, @@ -106,6 +110,12 @@ template class Reverse inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } + inline Scalar& operator()(Index row, Index col) + { + ei_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return coeffRef(row, col); + } + inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, @@ -128,6 +138,12 @@ template class Reverse return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); } + inline Scalar& operator()(Index index) + { + ei_assert(index >= 0 && index < m_matrix.size()); + return coeffRef(index); + } + template inline const PacketScalar packet(Index row, Index col) const { diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index e338a9193..2aa382df2 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -380,8 +380,8 @@ template class VectorwiseOp /** \returns a matrix expression * where each column (or row) are reversed. * - * Example: \include PartialRedux_reverse.cpp - * Output: \verbinclude PartialRedux_reverse.out + * Example: \include VectorWise_reverse.cpp + * Output: \verbinclude VectorWise_reverse.out * * \sa DenseBase::reverse() */ const Reverse reverse() const diff --git a/test/array_reverse.cpp b/test/array_reverse.cpp index ccf8dcc87..3933ff523 100644 --- a/test/array_reverse.cpp +++ b/test/array_reverse.cpp @@ -103,47 +103,6 @@ template void reverse(const MatrixType& m) } } - /* - cout << "m1:" << endl << m1 << endl; - cout << "m1c_reversed:" << endl << m1c_reversed << endl; - - cout << "----------------" << endl; - - for ( int i=0; i< rows*cols; i++){ - cout << m1c_reversed.coeff(i) << endl; - } - - cout << "----------------" << endl; - - for ( int i=0; i< rows*cols; i++){ - cout << m1c_reversed.colwise().reverse().coeff(i) << endl; - } - - cout << "================" << endl; - - cout << "m1.coeff( ind ): " << m1.coeff( ind ) << endl; - cout << "m1c_reversed.colwise().reverse().coeff( ind ): " << m1c_reversed.colwise().reverse().coeff( ind ) << endl; - */ - - //MatrixType m1r_reversed = m1.rowwise().reverse(); - //VERIFY_IS_APPROX( m1r_reversed.rowwise().reverse().coeff( ind ), m1.coeff( ind ) ); - - /* - cout << "m1" << endl << m1 << endl; - cout << "m1 using coeff(int index)" << endl; - for ( int i = 0; i < rows*cols; i++) { - cout << m1.coeff(i) << " "; - } - cout << endl; - - cout << "m1.transpose()" << endl << m1.transpose() << endl; - cout << "m1.transpose() using coeff(int index)" << endl; - for ( int i = 0; i < rows*cols; i++) { - cout << m1.transpose().coeff(i) << " "; - } - cout << endl; - */ - /* Scalar x = ei_random(); int r = ei_random(0, rows-1), @@ -152,6 +111,7 @@ template void reverse(const MatrixType& m) m1.reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c)); + /* m1.colwise().reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, c)); From 609941380aad2883ab0facc44aaaee4736f15ef3 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Mon, 31 May 2010 16:48:41 +0100 Subject: [PATCH 04/67] Change skipU argument to computeU - this reverses the meaning. See "skipXxx / computeXxx parameters in Eigenvalues module" on mailing list. --- Eigen/src/Array/VectorwiseOp.h | 4 +- Eigen/src/Eigenvalues/ComplexSchur.h | 57 ++++++++++++++-------------- test/schur_complex.cpp | 5 +++ 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index 2aa382df2..b809283a7 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -380,8 +380,8 @@ template class VectorwiseOp /** \returns a matrix expression * where each column (or row) are reversed. * - * Example: \include VectorWise_reverse.cpp - * Output: \verbinclude VectorWise_reverse.out + * Example: \include Vectorwise_reverse.cpp + * Output: \verbinclude Vectorwise_reverse.out * * \sa DenseBase::reverse() */ const Reverse reverse() const diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 673cb46f9..84da40f22 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -110,21 +110,21 @@ template class ComplexSchur /** \brief Constructor; computes Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. - * \param[in] skipU If true, then the unitary matrix U in the decomposition is not computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * This constructor calls compute() to compute the Schur decomposition. * * \sa matrixT() and matrixU() for examples. */ - ComplexSchur(const MatrixType& matrix, bool skipU = false) + ComplexSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_hess(matrix.rows()), m_isInitialized(false), m_matUisUptodate(false) { - compute(matrix, skipU); + compute(matrix, computeU); } /** \brief Returns the unitary matrix in the Schur decomposition. @@ -132,10 +132,10 @@ template class ComplexSchur * \returns A const reference to the matrix U. * * It is assumed that either the constructor - * ComplexSchur(const MatrixType& matrix, bool skipU) or the - * member function compute(const MatrixType& matrix, bool skipU) + * ComplexSchur(const MatrixType& matrix, bool computeU) or the + * member function compute(const MatrixType& matrix, bool computeU) * has been called before to compute the Schur decomposition of a - * matrix, and that \p skipU was set to false (the default + * matrix, and that \p computeU was set to true (the default * value). * * Example: \include ComplexSchur_matrixU.cpp @@ -153,8 +153,8 @@ template class ComplexSchur * \returns A const reference to the matrix T. * * It is assumed that either the constructor - * ComplexSchur(const MatrixType& matrix, bool skipU) or the - * member function compute(const MatrixType& matrix, bool skipU) + * ComplexSchur(const MatrixType& matrix, bool computeU) or the + * member function compute(const MatrixType& matrix, bool computeU) * has been called before to compute the Schur decomposition of a * matrix. * @@ -174,7 +174,7 @@ template class ComplexSchur /** \brief Computes Schur decomposition of given matrix. * * \param[in] matrix Square matrix whose Schur decomposition is to be computed. - * \param[in] skipU If true, then the unitary matrix U in the decomposition is not computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * The Schur decomposition is computed by first reducing the * matrix to Hessenberg form using the class @@ -182,13 +182,14 @@ template class ComplexSchur * to triangular form by performing QR iterations with a single * shift. The cost of computing the Schur decomposition depends * on the number of iterations; as a rough guide, it may be taken + * on the number of iterations; as a rough guide, it may be taken * to be \f$25n^3\f$ complex flops, or \f$10n^3\f$ complex flops - * if \a skipU is true. + * if \a computeU is false. * * Example: \include ComplexSchur_compute.cpp * Output: \verbinclude ComplexSchur_compute.out */ - void compute(const MatrixType& matrix, bool skipU = false); + void compute(const MatrixType& matrix, bool computeU = true); protected: ComplexMatrixType m_matT, m_matU; @@ -199,7 +200,7 @@ template class ComplexSchur private: bool subdiagonalEntryIsNeglegible(Index i); ComplexScalar computeShift(Index iu, Index iter); - void reduceToTriangularForm(bool skipU); + void reduceToTriangularForm(bool computeU); friend struct ei_complex_schur_reduce_to_hessenberg::IsComplex>; }; @@ -295,22 +296,22 @@ typename ComplexSchur::ComplexScalar ComplexSchur::compu template -void ComplexSchur::compute(const MatrixType& matrix, bool skipU) +void ComplexSchur::compute(const MatrixType& matrix, bool computeU) { m_matUisUptodate = false; ei_assert(matrix.cols() == matrix.rows()); if(matrix.cols() == 1) { - m_matU = ComplexMatrixType::Identity(1,1); - if(!skipU) m_matT = matrix.template cast(); + m_matT = matrix.template cast(); + if(computeU) m_matU = ComplexMatrixType::Identity(1,1); m_isInitialized = true; - m_matUisUptodate = !skipU; + m_matUisUptodate = computeU; return; } - ei_complex_schur_reduce_to_hessenberg::IsComplex>::run(*this, matrix, skipU); - reduceToTriangularForm(skipU); + ei_complex_schur_reduce_to_hessenberg::IsComplex>::run(*this, matrix, computeU); + reduceToTriangularForm(computeU); } /* Reduce given matrix to Hessenberg form */ @@ -318,28 +319,26 @@ template struct ei_complex_schur_reduce_to_hessenberg { // this is the implementation for the case IsComplex = true - static void run(ComplexSchur& _this, const MatrixType& matrix, bool skipU) + static void run(ComplexSchur& _this, const MatrixType& matrix, bool computeU) { - // TODO skip Q if skipU = true _this.m_hess.compute(matrix); _this.m_matT = _this.m_hess.matrixH(); - if(!skipU) _this.m_matU = _this.m_hess.matrixQ(); + if(computeU) _this.m_matU = _this.m_hess.matrixQ(); } }; template struct ei_complex_schur_reduce_to_hessenberg { - static void run(ComplexSchur& _this, const MatrixType& matrix, bool skipU) + static void run(ComplexSchur& _this, const MatrixType& matrix, bool computeU) { typedef typename ComplexSchur::ComplexScalar ComplexScalar; typedef typename ComplexSchur::ComplexMatrixType ComplexMatrixType; // Note: m_hess is over RealScalar; m_matT and m_matU is over ComplexScalar - // TODO skip Q if skipU = true _this.m_hess.compute(matrix); _this.m_matT = _this.m_hess.matrixH().template cast(); - if(!skipU) + if(computeU) { // This may cause an allocation which seems to be avoidable MatrixType Q = _this.m_hess.matrixQ(); @@ -350,7 +349,7 @@ struct ei_complex_schur_reduce_to_hessenberg // Reduce the Hessenberg matrix m_matT to triangular form by QR iteration. template -void ComplexSchur::reduceToTriangularForm(bool skipU) +void ComplexSchur::reduceToTriangularForm(bool computeU) { // 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. @@ -393,7 +392,7 @@ void ComplexSchur::reduceToTriangularForm(bool skipU) rot.makeGivens(m_matT.coeff(il,il) - shift, m_matT.coeff(il+1,il)); m_matT.rightCols(m_matT.cols()-il).applyOnTheLeft(il, il+1, rot.adjoint()); m_matT.topRows(std::min(il+2,iu)+1).applyOnTheRight(il, il+1, rot); - if(!skipU) m_matU.applyOnTheRight(il, il+1, rot); + if(computeU) m_matU.applyOnTheRight(il, il+1, rot); for(Index i=il+1 ; i::reduceToTriangularForm(bool skipU) m_matT.coeffRef(i+1,i-1) = ComplexScalar(0); m_matT.rightCols(m_matT.cols()-i).applyOnTheLeft(i, i+1, rot.adjoint()); m_matT.topRows(std::min(i+2,iu)+1).applyOnTheRight(i, i+1, rot); - if(!skipU) m_matU.applyOnTheRight(i, i+1, rot); + if(computeU) m_matU.applyOnTheRight(i, i+1, rot); } } @@ -413,7 +412,7 @@ void ComplexSchur::reduceToTriangularForm(bool skipU) } m_isInitialized = true; - m_matUisUptodate = !skipU; + m_matUisUptodate = computeU; } #endif // EIGEN_COMPLEX_SCHUR_H diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp index b33411cf2..cc8174d00 100644 --- a/test/schur_complex.cpp +++ b/test/schur_complex.cpp @@ -56,6 +56,11 @@ template void schur(int size = MatrixType::ColsAtCompileTim ComplexSchur cs2(A); VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT()); VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU()); + + // Test computation of only T, not U + ComplexSchur csOnlyT(A, false); + VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); + VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); } void test_schur_complex() From 8dc947821b3b64f754cdce1b7d8141885ed5ecd0 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Mon, 31 May 2010 18:17:47 +0100 Subject: [PATCH 05/67] Allow user to compute only the eigenvalues and not the eigenvectors. --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 127 +++++++++++------- Eigen/src/Eigenvalues/EigenSolver.h | 100 ++++++++------ Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h | 6 +- Eigen/src/Eigenvalues/RealSchur.h | 84 +++++++----- .../ComplexEigenSolver_eigenvalues.cpp | 2 +- doc/snippets/EigenSolver_compute.cpp | 4 +- doc/snippets/EigenSolver_eigenvalues.cpp | 2 +- doc/snippets/RealSchur_compute.cpp | 4 +- test/eigensolver_complex.cpp | 24 ++-- test/eigensolver_generic.cpp | 32 +++-- test/schur_real.cpp | 5 + 11 files changed, 235 insertions(+), 155 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index f56815c15..a3a4a4eba 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -56,7 +56,10 @@ template class ComplexEigenSolver { public: + + /** \brief Synonym for the template parameter \p _MatrixType. */ typedef _MatrixType MatrixType; + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, @@ -65,12 +68,12 @@ template class ComplexEigenSolver MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; - /** \brief Scalar type for matrices of type \p _MatrixType. */ + /** \brief Scalar type for matrices of type #MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; - /** \brief Complex scalar type for \p _MatrixType. + /** \brief Complex scalar type for #MatrixType. * * This is \c std::complex if #Scalar is real (e.g., * \c float or \c double) and just \c Scalar if #Scalar is @@ -81,14 +84,14 @@ template class ComplexEigenSolver /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #ComplexScalar. - * The length of the vector is the size of \p _MatrixType. + * The length of the vector is the size of #MatrixType. */ typedef Matrix EigenvalueType; /** \brief Type for matrix of eigenvectors as returned by eigenvectors(). * * This is a square matrix with entries of type #ComplexScalar. - * The size is the same as the size of \p _MatrixType. + * The size is the same as the size of #MatrixType. */ typedef Matrix EigenvectorType; @@ -102,6 +105,7 @@ template class ComplexEigenSolver m_eivalues(), m_schur(), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX() {} @@ -116,40 +120,46 @@ template class ComplexEigenSolver m_eivalues(size), m_schur(size), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX(size, size) {} /** \brief Constructor; computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * * This constructor calls compute() to compute the eigendecomposition. */ - ComplexEigenSolver(const MatrixType& matrix) + ComplexEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(),matrix.cols()), m_eivalues(matrix.cols()), m_schur(matrix.rows()), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX(matrix.rows(),matrix.cols()) { - compute(matrix); + compute(matrix, computeEigenvectors); } /** \brief Returns the eigenvectors of given matrix. * * \returns A const reference to the matrix whose columns are the eigenvectors. * - * It is assumed that either the constructor - * ComplexEigenSolver(const MatrixType& matrix) or the member - * function compute(const MatrixType& matrix) has been called - * before to compute the eigendecomposition of a matrix. This - * function returns a matrix whose columns are the - * eigenvectors. Column \f$ k \f$ is an eigenvector - * corresponding to eigenvalue number \f$ k \f$ as returned by - * eigenvalues(). The eigenvectors are normalized to have - * (Euclidean) norm equal to one. The matrix returned by this - * function is the matrix \f$ V \f$ in the eigendecomposition \f$ - * A = V D V^{-1} \f$, if it exists. + * \pre Either the constructor + * ComplexEigenSolver(const MatrixType& matrix, bool) or the member + * function compute(const MatrixType& matrix, bool) has been called before + * to compute the eigendecomposition of a matrix, and + * \p computeEigenvectors was set to true (the default). + * + * This function returns a matrix whose columns are the eigenvectors. Column + * \f$ k \f$ is an eigenvector corresponding to eigenvalue number \f$ k + * \f$ as returned by eigenvalues(). The eigenvectors are normalized to + * have (Euclidean) norm equal to one. The matrix returned by this + * function is the matrix \f$ V \f$ in the eigendecomposition \f$ A = V D + * V^{-1} \f$, if it exists. * * Example: \include ComplexEigenSolver_eigenvectors.cpp * Output: \verbinclude ComplexEigenSolver_eigenvectors.out @@ -157,6 +167,7 @@ template class ComplexEigenSolver const EigenvectorType& eigenvectors() const { ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } @@ -164,11 +175,12 @@ template class ComplexEigenSolver * * \returns A const reference to the column vector containing the eigenvalues. * - * It is assumed that either the constructor - * ComplexEigenSolver(const MatrixType& matrix) or the member - * function compute(const MatrixType& matrix) has been called - * before to compute the eigendecomposition of a matrix. This - * function returns a column vector containing the + * \pre Either the constructor + * ComplexEigenSolver(const MatrixType& matrix, bool) or the member + * function compute(const MatrixType& matrix, bool) has been called before + * to compute the eigendecomposition of a matrix. + * + * This function returns a column vector containing the * eigenvalues. Eigenvalues are repeated according to their * algebraic multiplicity, so there are as many eigenvalues as * rows in the matrix. @@ -185,10 +197,14 @@ template class ComplexEigenSolver /** \brief Computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * - * This function computes the eigenvalues and eigenvectors of \p - * matrix. The eigenvalues() and eigenvectors() functions can be - * used to retrieve the computed eigendecomposition. + * This function computes the eigenvalues of the complex matrix \p matrix. + * The eigenvalues() function can be used to retrieve them. If + * \p computeEigenvectors is true, then the eigenvectors are also computed + * and can be retrieved by calling eigenvectors(). * * The matrix is first reduced to Schur form using the * ComplexSchur class. The Schur decomposition is then used to @@ -201,19 +217,20 @@ template class ComplexEigenSolver * Example: \include ComplexEigenSolver_compute.cpp * Output: \verbinclude ComplexEigenSolver_compute.out */ - void compute(const MatrixType& matrix); + void compute(const MatrixType& matrix, bool computeEigenvectors = true); protected: EigenvectorType m_eivec; EigenvalueType m_eivalues; ComplexSchur m_schur; bool m_isInitialized; + bool m_eigenvectorsOk; EigenvectorType m_matX; }; template -void ComplexEigenSolver::compute(const MatrixType& matrix) +void ComplexEigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); @@ -222,40 +239,45 @@ void ComplexEigenSolver::compute(const MatrixType& matrix) // Step 1: Do a complex Schur decomposition, A = U T U^* // The eigenvalues are on the diagonal of T. - m_schur.compute(matrix); + m_schur.compute(matrix, computeEigenvectors); m_eivalues = m_schur.matrixT().diagonal(); - // Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T. - // The matrix X is unit triangular. - m_matX = EigenvectorType::Zero(n, n); - for(Index k=n-1 ; k>=0 ; k--) + if(computeEigenvectors) { - m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0); - // Compute X(i,k) using the (i,k) entry of the equation X T = D X - for(Index i=k-1 ; i>=0 ; i--) + // Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T. + // The matrix X is unit triangular. + m_matX = EigenvectorType::Zero(n, n); + for(Index k=n-1 ; k>=0 ; k--) { - m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k); - if(k-i-1>0) - m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value(); - ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k); - if(z==ComplexScalar(0)) + m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0); + // Compute X(i,k) using the (i,k) entry of the equation X T = D X + for(Index i=k-1 ; i>=0 ; i--) { - // If the i-th and k-th eigenvalue are equal, then z equals 0. - // Use a small value instead, to prevent division by zero. - ei_real_ref(z) = NumTraits::epsilon() * matrixnorm; + m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k); + if(k-i-1>0) + m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value(); + ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k); + if(z==ComplexScalar(0)) + { + // If the i-th and k-th eigenvalue are equal, then z equals 0. + // Use a small value instead, to prevent division by zero. + ei_real_ref(z) = NumTraits::epsilon() * matrixnorm; + } + m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z; } - m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z; + } + + // 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.noalias() = m_schur.matrixU() * m_matX; + // .. and normalize the eigenvectors + for(Index k=0 ; k::compute(const MatrixType& matrix) { k += i; std::swap(m_eivalues[k],m_eivalues[i]); - m_eivec.col(i).swap(m_eivec.col(k)); + if(computeEigenvectors) + m_eivec.col(i).swap(m_eivec.col(k)); } } } diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index 5400fdaf2..f745413a8 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -57,16 +57,16 @@ * this variant of the eigendecomposition the pseudo-eigendecomposition. * * Call the function compute() to compute the eigenvalues and eigenvectors of - * a given matrix. Alternatively, you can use the - * EigenSolver(const MatrixType&) constructor which computes the eigenvalues - * and eigenvectors at construction time. Once the eigenvalue and eigenvectors - * are computed, they can be retrieved with the eigenvalues() and + * a given matrix. Alternatively, you can use the + * EigenSolver(const MatrixType&, bool) constructor which computes the + * eigenvalues and eigenvectors at construction time. Once the eigenvalue and + * eigenvectors are computed, they can be retrieved with the eigenvalues() and * eigenvectors() functions. The pseudoEigenvalueMatrix() and * pseudoEigenvectors() methods allow the construction of the * pseudo-eigendecomposition. * - * The documentation for EigenSolver(const MatrixType&) contains an example of - * the typical use of this class. + * The documentation for EigenSolver(const MatrixType&, bool) contains an + * example of the typical use of this class. * * \note The implementation is adapted from * JAMA (public domain). @@ -78,7 +78,9 @@ template class EigenSolver { public: + /** \brief Synonym for the template parameter \p _MatrixType. */ typedef _MatrixType MatrixType; + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, @@ -87,12 +89,12 @@ template class EigenSolver MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; - /** \brief Scalar type for matrices of type \p _MatrixType. */ + /** \brief Scalar type for matrices of type #MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; - /** \brief Complex scalar type for \p _MatrixType. + /** \brief Complex scalar type for #MatrixType. * * This is \c std::complex if #Scalar is real (e.g., * \c float or \c double) and just \c Scalar if #Scalar is @@ -103,27 +105,27 @@ template class EigenSolver /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #ComplexScalar. - * The length of the vector is the size of \p _MatrixType. + * The length of the vector is the size of #MatrixType. */ typedef Matrix EigenvalueType; /** \brief Type for matrix of eigenvectors as returned by eigenvectors(). * * This is a square matrix with entries of type #ComplexScalar. - * The size is the same as the size of \p _MatrixType. + * The size is the same as the size of #MatrixType. */ typedef Matrix EigenvectorsType; /** \brief Default constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via EigenSolver::compute(const MatrixType&). + * perform decompositions via EigenSolver::compute(const MatrixType&, bool). * * \sa compute() for an example. */ EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false), m_realSchur(), m_matT(), m_tmp() {} - /** \brief Default Constructor with memory preallocation + /** \brief Default constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. @@ -133,6 +135,7 @@ template class EigenSolver : m_eivec(size, size), m_eivalues(size), m_isInitialized(false), + m_eigenvectorsOk(false), m_realSchur(size), m_matT(size, size), m_tmp(size) @@ -141,6 +144,9 @@ template class EigenSolver /** \brief Constructor; computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * * This constructor calls compute() to compute the eigenvalues * and eigenvectors. @@ -150,23 +156,26 @@ template class EigenSolver * * \sa compute() */ - EigenSolver(const MatrixType& matrix) + EigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), m_isInitialized(false), + m_eigenvectorsOk(false), m_realSchur(matrix.cols()), m_matT(matrix.rows(), matrix.cols()), m_tmp(matrix.cols()) { - compute(matrix); + compute(matrix, computeEigenvectors); } /** \brief Returns the eigenvectors of given matrix. * * \returns %Matrix whose columns are the (possibly complex) eigenvectors. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before, and + * \p computeEigenvectors was set to true (the default). * * Column \f$ k \f$ of the returned matrix is an eigenvector corresponding * to eigenvalue number \f$ k \f$ as returned by eigenvalues(). The @@ -185,9 +194,10 @@ template class EigenSolver * * \returns Const reference to matrix whose columns are the pseudo-eigenvectors. * - * \pre Either the constructor EigenSolver(const MatrixType&) or - * the member function compute(const MatrixType&) has been called - * before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before, and + * \p computeEigenvectors was set to true (the default). * * The real matrix \f$ V \f$ returned by this function and the * block-diagonal matrix \f$ D \f$ returned by pseudoEigenvalueMatrix() @@ -201,6 +211,7 @@ template class EigenSolver const MatrixType& pseudoEigenvectors() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } @@ -208,8 +219,9 @@ template class EigenSolver * * \returns A block-diagonal matrix. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before. * * The matrix \f$ D \f$ returned by this function is real and * block-diagonal. The blocks on the diagonal are either 1-by-1 or 2-by-2 @@ -226,8 +238,9 @@ template class EigenSolver * * \returns A const reference to the column vector containing the eigenvalues. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before. * * The eigenvalues are repeated according to their algebraic multiplicity, * so there are as many eigenvalues as rows in the matrix. @@ -247,34 +260,40 @@ template class EigenSolver /** \brief Computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * \returns Reference to \c *this * - * This function computes the eigenvalues and eigenvectors of \p matrix. - * The eigenvalues() and eigenvectors() functions can be used to retrieve - * the computed eigendecomposition. + * This function computes the eigenvalues of the real matrix \p matrix. + * The eigenvalues() function can be used to retrieve them. If + * \p computeEigenvectors is true, then the eigenvectors are also computed + * and can be retrieved by calling eigenvectors(). * * The matrix is first reduced to real Schur form using the RealSchur * class. The Schur decomposition is then used to compute the eigenvalues * and eigenvectors. * - * The cost of the computation is dominated by the cost of the Schur - * decomposition, which is very approximately \f$ 25n^3 \f$ where - * \f$ n \f$ is the size of the matrix. + * The cost of the computation is dominated by the cost of the + * Schur decomposition, which is very approximately \f$ 25n^3 \f$ + * (where \f$ n \f$ is the size of the matrix) if \p computeEigenvectors + * is true, and \f$ 10n^3 \f$ if \p computeEigenvectors is false. * * This method reuses of the allocated data in the EigenSolver object. * * Example: \include EigenSolver_compute.cpp * Output: \verbinclude EigenSolver_compute.out */ - EigenSolver& compute(const MatrixType& matrix); + EigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); private: - void computeEigenvectors(); + void doComputeEigenvectors(); protected: MatrixType m_eivec; EigenvalueType m_eivalues; bool m_isInitialized; + bool m_eigenvectorsOk; RealSchur m_realSchur; MatrixType m_matT; @@ -286,7 +305,7 @@ template MatrixType EigenSolver::pseudoEigenvalueMatrix() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); - Index n = m_eivec.cols(); + Index n = m_eivalues.rows(); MatrixType matD = MatrixType::Zero(n,n); for (Index i=0; i typename EigenSolver::EigenvectorsType EigenSolver::eigenvectors() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); Index n = m_eivec.cols(); EigenvectorsType matV(n,n); for (Index j=0; j::EigenvectorsType EigenSolver::eige } template -EigenSolver& EigenSolver::compute(const MatrixType& matrix) +EigenSolver& EigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { assert(matrix.cols() == matrix.rows()); // Reduce to real Schur form. - m_realSchur.compute(matrix); + m_realSchur.compute(matrix, computeEigenvectors); m_matT = m_realSchur.matrixT(); - m_eivec = m_realSchur.matrixU(); + if (computeEigenvectors) + m_eivec = m_realSchur.matrixU(); // Compute eigenvalues from matT m_eivalues.resize(matrix.cols()); @@ -362,9 +383,12 @@ EigenSolver& EigenSolver::compute(const MatrixType& matr } // Compute eigenvectors. - computeEigenvectors(); + if (computeEigenvectors) + doComputeEigenvectors(); m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; + return *this; } @@ -389,7 +413,7 @@ std::complex cdiv(Scalar xr, Scalar xi, Scalar yr, Scalar yi) template -void EigenSolver::computeEigenvectors() +void EigenSolver::doComputeEigenvectors() { const Index size = m_eivec.cols(); const Scalar eps = NumTraits::epsilon(); @@ -404,7 +428,7 @@ void EigenSolver::computeEigenvectors() // Backsubstitute to find vectors of upper triangular form if (norm == 0.0) { - return; + return; } for (Index n = size-1; n >= 0; n--) diff --git a/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h index 7b04e6ba7..f27481fe1 100644 --- a/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +++ b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h @@ -37,7 +37,7 @@ struct ei_eigenvalues_selector { typedef typename Derived::PlainObject PlainObject; PlainObject m_eval(m); - return ComplexEigenSolver(m_eval).eigenvalues(); + return ComplexEigenSolver(m_eval, false).eigenvalues(); } }; @@ -49,7 +49,7 @@ struct ei_eigenvalues_selector { typedef typename Derived::PlainObject PlainObject; PlainObject m_eval(m); - return EigenSolver(m_eval).eigenvalues(); + return EigenSolver(m_eval, false).eigenvalues(); } }; @@ -101,7 +101,7 @@ SelfAdjointView::eigenvalues() const { typedef typename SelfAdjointView::PlainObject PlainObject; PlainObject thisAsMatrix(*this); - return SelfAdjointEigenSolver(thisAsMatrix).eigenvalues(); + return SelfAdjointEigenSolver(thisAsMatrix, false).eigenvalues(); } diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index 92ff448ed..c92b72a94 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -50,13 +50,13 @@ * the eigendecomposition of a matrix. * * Call the function compute() to compute the real Schur decomposition of a - * given matrix. Alternatively, you can use the RealSchur(const MatrixType&) + * given matrix. Alternatively, you can use the RealSchur(const MatrixType&, bool) * constructor which computes the real Schur decomposition at construction * time. Once the decomposition is computed, you can use the matrixU() and * matrixT() functions to retrieve the matrices U and T in the decomposition. * - * The documentation of RealSchur(const MatrixType&) contains an example of - * the typical use of this class. + * The documentation of RealSchur(const MatrixType&, bool) contains an example + * of the typical use of this class. * * \note The implementation is adapted from * JAMA (public domain). @@ -98,41 +98,46 @@ template class RealSchur m_matU(size, size), m_workspaceVector(size), m_hess(size), - m_isInitialized(false) + m_isInitialized(false), + m_matUisUptodate(false) { } /** \brief Constructor; computes real Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * This constructor calls compute() to compute the Schur decomposition. * * Example: \include RealSchur_RealSchur_MatrixType.cpp * Output: \verbinclude RealSchur_RealSchur_MatrixType.out */ - RealSchur(const MatrixType& matrix) + RealSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_workspaceVector(matrix.rows()), m_hess(matrix.rows()), - m_isInitialized(false) + m_isInitialized(false), + m_matUisUptodate(false) { - compute(matrix); + compute(matrix, computeU); } /** \brief Returns the orthogonal matrix in the Schur decomposition. * * \returns A const reference to the matrix U. * - * \pre Either the constructor RealSchur(const MatrixType&) or the member - * function compute(const MatrixType&) has been called before to compute - * the Schur decomposition of a matrix. + * \pre Either the constructor RealSchur(const MatrixType&, bool) or the + * member function compute(const MatrixType&, bool) has been called before + * to compute the Schur decomposition of a matrix, and \p computeU was set + * to true (the default value). * - * \sa RealSchur(const MatrixType&) for an example + * \sa RealSchur(const MatrixType&, bool) for an example */ const MatrixType& matrixU() const { ei_assert(m_isInitialized && "RealSchur is not initialized."); + ei_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition."); return m_matU; } @@ -140,11 +145,11 @@ template class RealSchur * * \returns A const reference to the matrix T. * - * \pre Either the constructor RealSchur(const MatrixType&) or the member - * function compute(const MatrixType&) has been called before to compute - * the Schur decomposition of a matrix. + * \pre Either the constructor RealSchur(const MatrixType&, bool) or the + * member function compute(const MatrixType&, bool) has been called before + * to compute the Schur decomposition of a matrix. * - * \sa RealSchur(const MatrixType&) for an example + * \sa RealSchur(const MatrixType&, bool) for an example */ const MatrixType& matrixT() const { @@ -154,19 +159,21 @@ template class RealSchur /** \brief Computes Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * The Schur decomposition is computed by first reducing the matrix to * Hessenberg form using the class HessenbergDecomposition. The Hessenberg * matrix is then reduced to triangular form by performing Francis QR * iterations with implicit double shift. The cost of computing the Schur * decomposition depends on the number of iterations; as a rough guide, it - * may be taken to be \f$25n^3\f$ flops. + * may be taken to be \f$25n^3\f$ flops if \a computeU is true and + * \f$10n^3\f$ flops if \a computeU is false. * * Example: \include RealSchur_compute.cpp * Output: \verbinclude RealSchur_compute.out */ - void compute(const MatrixType& matrix); + void compute(const MatrixType& matrix, bool computeU = true); private: @@ -175,38 +182,39 @@ template class RealSchur ColumnVectorType m_workspaceVector; HessenbergDecomposition m_hess; bool m_isInitialized; + bool m_matUisUptodate; typedef Matrix Vector3s; Scalar computeNormOfT(); Index findSmallSubdiagEntry(Index iu, Scalar norm); - void splitOffTwoRows(Index iu, Scalar exshift); + void splitOffTwoRows(Index iu, bool computeU, Scalar exshift); void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo); void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector); - void performFrancisQRStep(Index il, Index im, Index iu, const Vector3s& firstHouseholderVector, Scalar* workspace); + void performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace); }; template -void RealSchur::compute(const MatrixType& matrix) +void RealSchur::compute(const MatrixType& matrix, bool computeU) { assert(matrix.cols() == matrix.rows()); // Step 1. Reduce to Hessenberg form - // TODO skip Q if skipU = true m_hess.compute(matrix); m_matT = m_hess.matrixH(); - m_matU = m_hess.matrixQ(); + if (computeU) + m_matU = m_hess.matrixQ(); // Step 2. Reduce to real Schur form - m_workspaceVector.resize(m_matU.cols()); + m_workspaceVector.resize(m_matT.cols()); Scalar* workspace = &m_workspaceVector.coeffRef(0); // 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 il,...,iu is the part we are working on (the active window). // Rows iu+1,...,end are already brought in triangular form. - Index iu = m_matU.cols() - 1; + Index iu = m_matT.cols() - 1; Index iter = 0; // iteration count Scalar exshift = 0.0; // sum of exceptional shifts Scalar norm = computeNormOfT(); @@ -226,7 +234,7 @@ void RealSchur::compute(const MatrixType& matrix) } else if (il == iu-1) // Two roots found { - splitOffTwoRows(iu, exshift); + splitOffTwoRows(iu, computeU, exshift); iu -= 2; iter = 0; } @@ -237,18 +245,19 @@ void RealSchur::compute(const MatrixType& matrix) iter = iter + 1; // (Could check iteration count here.) Index im; initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); - performFrancisQRStep(il, im, iu, firstHouseholderVector, workspace); + performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); } } m_isInitialized = true; + m_matUisUptodate = computeU; } /** \internal Computes and returns vector L1 norm of T */ template inline typename MatrixType::Scalar RealSchur::computeNormOfT() { - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); // FIXME to be efficient the following would requires a triangular reduxion code // Scalar norm = m_matT.upper().cwiseAbs().sum() // + m_matT.bottomLeftCorner(size-1,size-1).diagonal().cwiseAbs().sum(); @@ -277,9 +286,9 @@ inline typename MatrixType::Index RealSchur::findSmallSubdiagEntry(I /** \internal Update T given that rows iu-1 and iu decouple from the rest. */ template -inline void RealSchur::splitOffTwoRows(Index iu, Scalar exshift) +inline void RealSchur::splitOffTwoRows(Index iu, bool computeU, Scalar exshift) { - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); // The eigenvalues of the 2x2 matrix [a b; c d] are // trace +/- sqrt(discr/4) where discr = tr^2 - 4*det, tr = a + d, det = ad - bc @@ -300,7 +309,8 @@ inline void RealSchur::splitOffTwoRows(Index iu, Scalar exshift) m_matT.rightCols(size-iu+1).applyOnTheLeft(iu-1, iu, rot.adjoint()); m_matT.topRows(iu+1).applyOnTheRight(iu-1, iu, rot); m_matT.coeffRef(iu, iu-1) = Scalar(0); - m_matU.applyOnTheRight(iu-1, iu, rot); + if (computeU) + m_matU.applyOnTheRight(iu-1, iu, rot); } if (iu > 1) @@ -375,12 +385,12 @@ inline void RealSchur::initFrancisQRStep(Index il, Index iu, const V /** \internal Perform a Francis QR step involving rows il:iu and columns im:iu. */ template -inline void RealSchur::performFrancisQRStep(Index il, Index im, Index iu, const Vector3s& firstHouseholderVector, Scalar* workspace) +inline void RealSchur::performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace) { assert(im >= il); assert(im <= iu-2); - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); for (Index k = im; k <= iu-2; ++k) { @@ -406,7 +416,8 @@ inline void RealSchur::performFrancisQRStep(Index il, Index im, Inde // These Householder transformations form the O(n^3) part of the algorithm m_matT.block(k, k, 3, size-k).applyHouseholderOnTheLeft(ess, tau, workspace); m_matT.block(0, k, std::min(iu,k+3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace); - m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace); + if (computeU) + m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace); } } @@ -420,7 +431,8 @@ inline void RealSchur::performFrancisQRStep(Index il, Index im, Inde m_matT.coeffRef(iu-1, iu-2) = beta; m_matT.block(iu-1, iu-1, 2, size-iu+1).applyHouseholderOnTheLeft(ess, tau, workspace); m_matT.block(0, iu-1, iu+1, 2).applyHouseholderOnTheRight(ess, tau, workspace); - m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace); + if (computeU) + m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace); } // clean up pollution due to round-off errors diff --git a/doc/snippets/ComplexEigenSolver_eigenvalues.cpp b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp index 1afa8b086..5509bd897 100644 --- a/doc/snippets/ComplexEigenSolver_eigenvalues.cpp +++ b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp @@ -1,4 +1,4 @@ MatrixXcf ones = MatrixXcf::Ones(3,3); -ComplexEigenSolver ces(ones); +ComplexEigenSolver ces(ones, /* computeEigenvectors = */ false); cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << ces.eigenvalues() << endl; diff --git a/doc/snippets/EigenSolver_compute.cpp b/doc/snippets/EigenSolver_compute.cpp index 06138f608..a5c96e9b4 100644 --- a/doc/snippets/EigenSolver_compute.cpp +++ b/doc/snippets/EigenSolver_compute.cpp @@ -1,6 +1,6 @@ EigenSolver es; MatrixXf A = MatrixXf::Random(4,4); -es.compute(A); +es.compute(A, /* computeEigenvectors = */ false); cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl; -es.compute(A + MatrixXf::Identity(4,4)); // re-use es to compute eigenvalues of A+I +es.compute(A + MatrixXf::Identity(4,4), false); // re-use es to compute eigenvalues of A+I cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl; diff --git a/doc/snippets/EigenSolver_eigenvalues.cpp b/doc/snippets/EigenSolver_eigenvalues.cpp index 8d83ea982..ed28869a0 100644 --- a/doc/snippets/EigenSolver_eigenvalues.cpp +++ b/doc/snippets/EigenSolver_eigenvalues.cpp @@ -1,4 +1,4 @@ MatrixXd ones = MatrixXd::Ones(3,3); -EigenSolver es(ones); +EigenSolver es(ones, false); cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << es.eigenvalues() << endl; diff --git a/doc/snippets/RealSchur_compute.cpp b/doc/snippets/RealSchur_compute.cpp index 4dcfaf0f2..20c2611b8 100644 --- a/doc/snippets/RealSchur_compute.cpp +++ b/doc/snippets/RealSchur_compute.cpp @@ -1,6 +1,6 @@ MatrixXf A = MatrixXf::Random(4,4); RealSchur schur(4); -schur.compute(A); +schur.compute(A, /* computeU = */ false); cout << "The matrix T in the decomposition of A is:" << endl << schur.matrixT() << endl; -schur.compute(A.inverse()); +schur.compute(A.inverse(), /* computeU = */ false); cout << "The matrix T in the decomposition of A^(-1) is:" << endl << schur.matrixT() << endl; diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 1440cd700..3285d26c2 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -2,6 +2,7 @@ // for linear algebra. Eigen itself is part of the KDE project. // // Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2010 Jitse Niesen // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -66,7 +67,10 @@ template void eigensolver(const MatrixType& m) // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus // another algorithm so results may differ slightly verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues()); - + + ComplexEigenSolver eiNoEivecs(a, false); + VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); + // Regression test for issue #66 MatrixType z = MatrixType::Zero(rows,cols); ComplexEigenSolver eiz(z); @@ -76,11 +80,15 @@ template void eigensolver(const MatrixType& m) VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); } -template void eigensolver_verify_assert() +template void eigensolver_verify_assert(const MatrixType& m) { ComplexEigenSolver eig; - VERIFY_RAISES_ASSERT(eig.eigenvectors()) - VERIFY_RAISES_ASSERT(eig.eigenvalues()) + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.eigenvalues()); + + MatrixType a = MatrixType::Random(m.rows(),m.cols()); + eig.compute(a, false); + VERIFY_RAISES_ASSERT(eig.eigenvectors()); } void test_eigensolver_complex() @@ -92,10 +100,10 @@ void test_eigensolver_complex() CALL_SUBTEST_4( eigensolver(Matrix3f()) ); } - CALL_SUBTEST_1( eigensolver_verify_assert() ); - CALL_SUBTEST_2( eigensolver_verify_assert() ); - CALL_SUBTEST_3(( eigensolver_verify_assert, 1, 1> >() )); - CALL_SUBTEST_4( eigensolver_verify_assert() ); + CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) ); + CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(14,14)) ); + CALL_SUBTEST_3( eigensolver_verify_assert(Matrix, 1, 1>()) ); + CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) ); // Test problem size constructors CALL_SUBTEST_5(ComplexEigenSolver(10)); diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index d70f37ea4..79c08ec31 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2010 Jitse Niesen // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -60,19 +61,26 @@ template void eigensolver(const MatrixType& m) ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); VERIFY_IS_APPROX(a.eigenvalues(), ei1.eigenvalues()); + EigenSolver eiNoEivecs(a, false); + VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); + VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix()); + MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); } -template void eigensolver_verify_assert() +template void eigensolver_verify_assert(const MatrixType& m) { - MatrixType tmp; - EigenSolver eig; - VERIFY_RAISES_ASSERT(eig.eigenvectors()) - VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()) - VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix()) - VERIFY_RAISES_ASSERT(eig.eigenvalues()) + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix()); + VERIFY_RAISES_ASSERT(eig.eigenvalues()); + + MatrixType a = MatrixType::Random(m.rows(),m.cols()); + eig.compute(a, false); + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()); } void test_eigensolver_generic() @@ -88,11 +96,11 @@ void test_eigensolver_generic() CALL_SUBTEST_4( eigensolver(Matrix2d()) ); } - CALL_SUBTEST_1( eigensolver_verify_assert() ); - CALL_SUBTEST_2( eigensolver_verify_assert() ); - CALL_SUBTEST_4( eigensolver_verify_assert() ); - CALL_SUBTEST_5( eigensolver_verify_assert() ); + CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4f()) ); + CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXd(17,17)) ); + CALL_SUBTEST_3( eigensolver_verify_assert(Matrix()) ); + CALL_SUBTEST_4( eigensolver_verify_assert(Matrix2d()) ); // Test problem size constructors - CALL_SUBTEST_6(EigenSolver(10)); + CALL_SUBTEST_5(EigenSolver(10)); } diff --git a/test/schur_real.cpp b/test/schur_real.cpp index bcb19c936..116c8dbce 100644 --- a/test/schur_real.cpp +++ b/test/schur_real.cpp @@ -73,6 +73,11 @@ template void schur(int size = MatrixType::ColsAtCompileTim RealSchur rs2(A); VERIFY_IS_EQUAL(rs1.matrixT(), rs2.matrixT()); VERIFY_IS_EQUAL(rs1.matrixU(), rs2.matrixU()); + + // Test computation of only T, not U + RealSchur rsOnlyT(A, false); + VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT()); + VERIFY_RAISES_ASSERT(rsOnlyT.matrixU()); } void test_schur_real() From e2097c55f8b130cac62d52af2cd7d8717ec0d5c1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 31 May 2010 22:46:18 +0200 Subject: [PATCH 06/67] fix issue #125 - *norm() return RealScalar and not Scalar --- Eigen/src/Array/VectorwiseOp.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index b809283a7..f495aae40 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -178,14 +178,16 @@ template class VectorwiseOp public: typedef typename ExpressionType::Scalar Scalar; + typedef typename ExpressionType::RealScalar RealScalar; typedef typename ExpressionType::Index Index; typedef typename ei_meta_if::ret, ExpressionType, const ExpressionType&>::ret ExpressionTypeNested; - template class Functor> struct ReturnType + template class Functor, + typename Scalar=typename ei_traits::Scalar> struct ReturnType { typedef PartialReduxExpr::Scalar>, + Functor, Direction > Type; }; @@ -285,7 +287,7 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_squaredNorm.out * * \sa DenseBase::squaredNorm() */ - const typename ReturnType::Type squaredNorm() const + const typename ReturnType::Type squaredNorm() const { return _expression(); } /** \returns a row (or column) vector expression of the norm @@ -295,7 +297,7 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_norm.out * * \sa DenseBase::norm() */ - const typename ReturnType::Type norm() const + const typename ReturnType::Type norm() const { return _expression(); } @@ -304,7 +306,7 @@ template class VectorwiseOp * blue's algorithm. * * \sa DenseBase::blueNorm() */ - const typename ReturnType::Type blueNorm() const + const typename ReturnType::Type blueNorm() const { return _expression(); } @@ -313,7 +315,7 @@ template class VectorwiseOp * underflow and overflow. * * \sa DenseBase::stableNorm() */ - const typename ReturnType::Type stableNorm() const + const typename ReturnType::Type stableNorm() const { return _expression(); } @@ -322,7 +324,7 @@ template class VectorwiseOp * underflow and overflow using a concatenation of hypot() calls. * * \sa DenseBase::hypotNorm() */ - const typename ReturnType::Type hypotNorm() const + const typename ReturnType::Type hypotNorm() const { return _expression(); } /** \returns a row (or column) vector expression of the sum From 01162614075eef7d3adce4d7d5412fc4146827be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jun 2010 13:57:38 +0200 Subject: [PATCH 07/67] make BenchTimer compatible with 2.0 branch --- bench/BenchTimer.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h index 0a0a5e154..567064360 100644 --- a/bench/BenchTimer.h +++ b/bench/BenchTimer.h @@ -87,7 +87,12 @@ public: { m_times[CPU_TIMER] = getCpuTime() - m_starts[CPU_TIMER]; m_times[REAL_TIMER] = getRealTime() - m_starts[REAL_TIMER]; + #if EIGEN_VERSION_AT_LEAST(2,90,0) m_bests = m_bests.cwiseMin(m_times); + #else + m_bests(0) = std::min(m_bests(0),m_times(0)); + m_bests(1) = std::min(m_bests(1),m_times(1)); + #endif m_totals += m_times; } From 39c568445c7c6fa53069eadf79ca01e0b420fbc2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jun 2010 13:59:21 +0200 Subject: [PATCH 08/67] simplify a using statement --- Eigen/src/Core/TriangularMatrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 47c11ceb6..d4799fbc1 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -156,7 +156,7 @@ template class TriangularView typedef typename MatrixType::PlainObject DenseMatrixType; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename ei_cleantype::type _MatrixTypeNested; - using TriangularBase >::evalToLazy; + using Base::evalToLazy; typedef typename ei_traits::StorageKind StorageKind; typedef typename ei_index::type Index; From 09a1b7f7e1ec09f96dd0f58bb6bc22881e0c76b6 Mon Sep 17 00:00:00 2001 From: Anton Gladky Date: Fri, 28 May 2010 10:18:37 +0200 Subject: [PATCH 09/67] Fixes the problem, described here: http://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2010/05/msg00154.html --- Eigen/src/QR/ColPivHouseholderQR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index b4bcfd529..e0eaf32a9 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -286,6 +286,7 @@ template class ColPivHouseholderQR { m_usePrescribedThreshold = true; m_prescribedThreshold = threshold; + return *this; } /** Allows to come back to the default behavior, letting Eigen use its default formula for @@ -299,6 +300,7 @@ template class ColPivHouseholderQR ColPivHouseholderQR& setThreshold(Default_t) { m_usePrescribedThreshold = false; + return *this; } /** Returns the threshold that will be used by certain methods such as rank(). From 3e95609cd4f036ccb647f9a590062cdb250e9760 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 1 Jun 2010 09:01:39 -0400 Subject: [PATCH 10/67] Backed out changeset 641d968a9a7ed57a3b8a3f45dea43c5ee6717f97 --- Eigen/src/Core/NoAlias.h | 10 ++-------- Eigen/src/Core/ReturnByValue.h | 11 ++++------- Eigen/src/LU/Inverse.h | 19 ++++++++++++++++--- test/prec_inverse_4x4.cpp | 4 +--- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 0542571e2..30ddbeb3c 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -45,18 +45,12 @@ class NoAlias public: NoAlias(ExpressionType& expression) : m_expression(expression) {} - /* \sa MatrixBase::lazyAssign() */ + /** Behaves like MatrixBase::lazyAssign(other) + * \sa MatrixBase::lazyAssign() */ template EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { return m_expression.lazyAssign(other.derived()); } - template - EIGEN_STRONG_INLINE ExpressionType& operator=(const ReturnByValue& other) - { - other.evalTo(m_expression); - return m_expression; - } - /** \sa MatrixBase::operator+= */ template EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index b2e581c70..986bab54d 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -36,9 +36,9 @@ struct ei_traits > enum { // We're disabling the DirectAccess because e.g. the constructor of // the Block-with-DirectAccess expression requires to have a coeffRef method. - // FIXME this should be fixed so we can have DirectAccessBit here. + // Also, we don't want to have to implement the stride stuff. Flags = (ei_traits::ReturnType>::Flags - | EvalBeforeNestingBit | EvalBeforeAssigningBit) & ~DirectAccessBit + | EvalBeforeNestingBit) & ~DirectAccessBit }; }; @@ -83,11 +83,8 @@ template template Derived& DenseBase::operator=(const ReturnByValue& other) { - // since we're by-passing the mechanisms in Assign.h, we implement here the EvalBeforeAssigningBit. - // override by using .noalias(), see corresponding operator= in NoAlias. - typename Derived::PlainObject result(rows(), cols()); - other.evalTo(result); - return (derived() = result); + other.evalTo(derived()); + return derived(); } #endif // EIGEN_RETURNBYVALUE_H diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 1e9d69a22..9e0c46094 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -281,9 +281,15 @@ struct ei_traits > template struct ei_inverse_impl : public ReturnByValue > { - typedef typename MatrixType::Nested MatrixTypeNested; + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost, limits code size, + // and allows for vectorized paths. + typedef typename ei_meta_if< + MatrixType::RowsAtCompileTime == 2, + typename ei_nested::type, + typename ei_eval::type + >::ret MatrixTypeNested; typedef typename ei_cleantype::type MatrixTypeNestedCleaned; - const MatrixTypeNested m_matrix; ei_inverse_impl(const MatrixType& matrix) @@ -353,7 +359,14 @@ inline void MatrixBase::computeInverseAndDetWithCheck( { // i'd love to put some static assertions there, but SFINAE means that they have no effect... ei_assert(rows() == cols()); - ei_compute_inverse_and_det_with_check::run + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost and limits code size. + typedef typename ei_meta_if< + RowsAtCompileTime == 2, + typename ei_cleantype::type>::type, + PlainObject + >::ret MatrixType; + ei_compute_inverse_and_det_with_check::run (derived(), absDeterminantThreshold, inverse, determinant, invertible); } diff --git a/test/prec_inverse_4x4.cpp b/test/prec_inverse_4x4.cpp index 05dbee7b5..4150caec2 100644 --- a/test/prec_inverse_4x4.cpp +++ b/test/prec_inverse_4x4.cpp @@ -64,9 +64,7 @@ template void inverse_general_4x4(int repeat) double error_avg = error_sum / repeat; EIGEN_DEBUG_VAR(error_avg); EIGEN_DEBUG_VAR(error_max); - // FIXME that 1.3 used to be a 1.0 until the NumTraits changes on 28 April 2010, and then a 1.2 until the ReturnByValue/Inverse changes - // on 30 May 2010, what's going wrong (if anything) ?? - VERIFY(error_avg < (NumTraits::IsComplex ? 8.0 : 1.3)); + VERIFY(error_avg < (NumTraits::IsComplex ? 8.0 : 1.2)); // FIXME that 1.2 used to be a 1.0 until the NumTraits changes on 28 April 2010, what's going wrong?? VERIFY(error_max < (NumTraits::IsComplex ? 64.0 : 20.0)); } From 4c6d182c42492b94a2415b9f5c1e50d564b2c78e Mon Sep 17 00:00:00 2001 From: Trevor Irons Date: Tue, 1 Jun 2010 07:09:40 -0600 Subject: [PATCH 11/67] Addressess small compile error with OpenMP --- Eigen/src/Core/products/Parallelizer.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h index 5e4eb6f1e..f7bdceab7 100644 --- a/Eigen/src/Core/products/Parallelizer.h +++ b/Eigen/src/Core/products/Parallelizer.h @@ -71,7 +71,8 @@ void ei_parallelize_gemm(const Functor& func, Index rows, Index cols) typedef typename Functor::BlockBScalar BlockBScalar; BlockBScalar* sharedBlockB = new BlockBScalar[func.sharedBlockBSize()]; - GemmParallelInfo* info = new GemmParallelInfo[threads]; + GemmParallelInfo* info = new + GemmParallelInfo[threads]; #pragma omp parallel for schedule(static,1) num_threads(threads) for(Index i=0; i Date: Tue, 1 Jun 2010 17:40:51 +0100 Subject: [PATCH 12/67] Make all compute() methods return a reference to *this. --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 7 +++++-- Eigen/src/Eigenvalues/ComplexSchur.h | 8 +++++--- Eigen/src/Eigenvalues/HessenbergDecomposition.h | 6 ++++-- Eigen/src/Eigenvalues/RealSchur.h | 6 ++++-- Eigen/src/Eigenvalues/Tridiagonalization.h | 4 +++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index a3a4a4eba..bc44b899a 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -200,6 +200,7 @@ template class ComplexEigenSolver * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are * computed. + * \returns Reference to \c *this * * This function computes the eigenvalues of the complex matrix \p matrix. * The eigenvalues() function can be used to retrieve them. If @@ -217,7 +218,7 @@ template class ComplexEigenSolver * Example: \include ComplexEigenSolver_compute.cpp * Output: \verbinclude ComplexEigenSolver_compute.out */ - void compute(const MatrixType& matrix, bool computeEigenvectors = true); + ComplexEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); protected: EigenvectorType m_eivec; @@ -230,7 +231,7 @@ template class ComplexEigenSolver template -void ComplexEigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) +ComplexEigenSolver& ComplexEigenSolver::compute(const MatrixType& matrix, bool computeEigenvectors) { // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); @@ -292,6 +293,8 @@ void ComplexEigenSolver::compute(const MatrixType& matrix, bool comp m_eivec.col(i).swap(m_eivec.col(k)); } } + + return *this; } diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 84da40f22..a4812dac6 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -175,6 +175,7 @@ template class ComplexSchur * * \param[in] matrix Square matrix whose Schur decomposition is to be computed. * \param[in] computeU If true, both T and U are computed; if false, only T is computed. + * \returns Reference to \c *this * * The Schur decomposition is computed by first reducing the * matrix to Hessenberg form using the class @@ -189,7 +190,7 @@ template class ComplexSchur * Example: \include ComplexSchur_compute.cpp * Output: \verbinclude ComplexSchur_compute.out */ - void compute(const MatrixType& matrix, bool computeU = true); + ComplexSchur& compute(const MatrixType& matrix, bool computeU = true); protected: ComplexMatrixType m_matT, m_matU; @@ -296,7 +297,7 @@ typename ComplexSchur::ComplexScalar ComplexSchur::compu template -void ComplexSchur::compute(const MatrixType& matrix, bool computeU) +ComplexSchur& ComplexSchur::compute(const MatrixType& matrix, bool computeU) { m_matUisUptodate = false; ei_assert(matrix.cols() == matrix.rows()); @@ -307,11 +308,12 @@ void ComplexSchur::compute(const MatrixType& matrix, bool computeU) if(computeU) m_matU = ComplexMatrixType::Identity(1,1); m_isInitialized = true; m_matUisUptodate = computeU; - return; + return *this; } ei_complex_schur_reduce_to_hessenberg::IsComplex>::run(*this, matrix, computeU); reduceToTriangularForm(computeU); + return *this; } /* Reduce given matrix to Hessenberg form */ diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index 220531bf5..4f3c357a8 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -141,6 +141,7 @@ template class HessenbergDecomposition /** \brief Computes Hessenberg decomposition of given matrix. * * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed. + * \returns Reference to \c *this * * The Hessenberg decomposition is computed by bringing the columns of the * matrix successively in the required form using Householder reflections @@ -154,17 +155,18 @@ template class HessenbergDecomposition * Example: \include HessenbergDecomposition_compute.cpp * Output: \verbinclude HessenbergDecomposition_compute.out */ - void compute(const MatrixType& matrix) + HessenbergDecomposition& compute(const MatrixType& matrix) { m_matrix = matrix; if(matrix.rows()<2) { m_isInitialized = true; - return; + return *this; } m_hCoeffs.resize(matrix.rows()-1,1); _compute(m_matrix, m_hCoeffs, m_temp); m_isInitialized = true; + return *this; } /** \brief Returns the Householder coefficients. diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index c92b72a94..41f74e530 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -161,6 +161,7 @@ template class RealSchur * * \param[in] matrix Square matrix whose Schur decomposition is to be computed. * \param[in] computeU If true, both T and U are computed; if false, only T is computed. + * \returns Reference to \c *this * * The Schur decomposition is computed by first reducing the matrix to * Hessenberg form using the class HessenbergDecomposition. The Hessenberg @@ -173,7 +174,7 @@ template class RealSchur * Example: \include RealSchur_compute.cpp * Output: \verbinclude RealSchur_compute.out */ - void compute(const MatrixType& matrix, bool computeU = true); + RealSchur& compute(const MatrixType& matrix, bool computeU = true); private: @@ -196,7 +197,7 @@ template class RealSchur template -void RealSchur::compute(const MatrixType& matrix, bool computeU) +RealSchur& RealSchur::compute(const MatrixType& matrix, bool computeU) { assert(matrix.cols() == matrix.rows()); @@ -251,6 +252,7 @@ void RealSchur::compute(const MatrixType& matrix, bool computeU) m_isInitialized = true; m_matUisUptodate = computeU; + return *this; } /** \internal Computes and returns vector L1 norm of T */ diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index e204c30ea..acf21e2da 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -137,6 +137,7 @@ template class Tridiagonalization * * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition * is to be computed. + * \returns Reference to \c *this * * The tridiagonal decomposition is computed by bringing the columns of * the matrix successively in the required form using Householder @@ -149,12 +150,13 @@ template class Tridiagonalization * Example: \include Tridiagonalization_compute.cpp * Output: \verbinclude Tridiagonalization_compute.out */ - void compute(const MatrixType& matrix) + Tridiagonalization& compute(const MatrixType& matrix) { m_matrix = matrix; m_hCoeffs.resize(matrix.rows()-1, 1); _compute(m_matrix, m_hCoeffs); m_isInitialized = true; + return *this; } /** \brief Returns the Householder coefficients. From ab2b33e8029daade805812f7998190a2e14cf7e4 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 1 Jun 2010 17:45:58 +0100 Subject: [PATCH 13/67] Add cast to aliasing check. Otherwise, one of the geo tests fails to compile. Now there are some compiler warnings about aliasing and type-punned pointers that I don't understand. --- Eigen/src/LU/Inverse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 9e4e1dccf..e1276c6a3 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -296,7 +296,7 @@ struct ei_inverse_impl : public ReturnByValue > template inline void evalTo(Dest& dst) const { // FIXME this is a naive aliasing check that could be improved. It only catches x = x.inverse(); - ei_assert(&dst != &m_matrix && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + ei_assert(&dst != (Dest*)(&m_matrix) && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); ei_compute_inverse::run(m_matrix, dst); } }; From 314bfa13753f153d44ff76a1c8ce0206616b06d9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jun 2010 22:51:47 +0200 Subject: [PATCH 14/67] fix issue #128 : inner stride can also be 0 in which case it means 1... --- Eigen/src/Core/util/BlasUtil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h index 6cbd26689..89c094d31 100644 --- a/Eigen/src/Core/util/BlasUtil.h +++ b/Eigen/src/Core/util/BlasUtil.h @@ -162,7 +162,7 @@ template struct ei_blas_traits && ( /* Uncomment this when the low-level matrix-vector product functions support strided vectors bool(XprType::IsVectorAtCompileTime) || */ - int(ei_inner_stride_at_compile_time::ret) == 1) + int(ei_inner_stride_at_compile_time::ret) <= 1) ) ? 1 : 0 }; typedef typename ei_meta_if Date: Wed, 2 Jun 2010 09:45:57 +0200 Subject: [PATCH 15/67] implicit conversion to scalar for inner product --- Eigen/src/Core/DenseBase.h | 10 +++++----- Eigen/src/Core/Product.h | 5 +++++ test/array.cpp | 10 +++++----- test/array_for_matrix.cpp | 4 ++-- test/product.h | 9 +++++++-- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index c4b4057a4..80db0f421 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -218,8 +218,8 @@ template class DenseBase */ void resize(Index rows, Index cols) { - EIGEN_ONLY_USED_FOR_DEBUG(rows); - EIGEN_ONLY_USED_FOR_DEBUG(cols); + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); ei_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } @@ -247,7 +247,7 @@ template class DenseBase /** \internal expression type of a block of whole rows */ template struct NRowsBlockXpr { typedef Block::ColsAtCompileTime> Type; }; - + #endif // not EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this. \returns a reference to *this. */ @@ -440,8 +440,8 @@ template class DenseBase * a const reference, in order to avoid a useless copy. */ EIGEN_STRONG_INLINE const typename ei_eval::type eval() const - { - // Even though MSVC does not honor strong inlining when the return type + { + // Even though MSVC does not honor strong inlining when the return type // is a dynamic matrix, we desperately need strong inlining for fixed // size types on MSVC. return typename ei_eval::type(derived()); diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 93e978779..859545aa0 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -182,6 +182,11 @@ class GeneralProduct } typename Base::Scalar value() const { return Base::coeff(0,0); } + + /** Convertion to scalar */ + operator const typename Base::Scalar() const { + return Base::coeff(0,0); + } }; /*********************************************************************** diff --git a/test/array.cpp b/test/array.cpp index df1e1b49e..b1fa45b12 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -129,7 +129,7 @@ template void comparisons(const ArrayType& m) VERIFY(((m1.abs()+1)>RealScalar(0.1)).count() == rows*cols); typedef Array ArrayOfIndices; - + // TODO allows colwise/rowwise for array VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose()); VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols)); @@ -151,10 +151,10 @@ template void array_real(const ArrayType& m) VERIFY_IS_APPROX(m1.sin(), ei_sin(m1)); VERIFY_IS_APPROX(m1.cos(), std::cos(m1)); VERIFY_IS_APPROX(m1.cos(), ei_cos(m1)); - + VERIFY_IS_APPROX(ei_cos(m1+RealScalar(3)*m2), ei_cos((m1+RealScalar(3)*m2).eval())); VERIFY_IS_APPROX(std::cos(m1+RealScalar(3)*m2), std::cos((m1+RealScalar(3)*m2).eval())); - + VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1))); VERIFY_IS_APPROX(m1.abs().sqrt(), ei_sqrt(ei_abs(m1))); VERIFY_IS_APPROX(m1.abs(), ei_sqrt(ei_abs2(m1))); @@ -163,10 +163,10 @@ template void array_real(const ArrayType& m) VERIFY_IS_APPROX(ei_abs2(std::real(m1)) + ei_abs2(std::imag(m1)), ei_abs2(m1)); if(!NumTraits::IsComplex) VERIFY_IS_APPROX(ei_real(m1), m1); - + VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1))); VERIFY_IS_APPROX(m1.abs().log(), ei_log(ei_abs(m1))); - + VERIFY_IS_APPROX(m1.exp(), std::exp(m1)); VERIFY_IS_APPROX(m1.exp() * m2.exp(), std::exp(m1+m2)); VERIFY_IS_APPROX(m1.exp(), ei_exp(m1)); diff --git a/test/array_for_matrix.cpp b/test/array_for_matrix.cpp index 477d1788d..5d0b9bbbd 100644 --- a/test/array_for_matrix.cpp +++ b/test/array_for_matrix.cpp @@ -37,10 +37,10 @@ template void array_for_matrix(const MatrixType& m) MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols); - + ColVectorType cv1 = ColVectorType::Random(rows); RowVectorType rv1 = RowVectorType::Random(cols); - + Scalar s1 = ei_random(), s2 = ei_random(); diff --git a/test/product.h b/test/product.h index 277b73c45..71dc4bde2 100644 --- a/test/product.h +++ b/test/product.h @@ -71,8 +71,9 @@ template void product(const MatrixType& m) Scalar s1 = ei_random(); - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); + int r = ei_random(0, rows-1), + c = ei_random(0, cols-1), + c2 = ei_random(0, cols-1); // begin testing Product.h: only associativity for now // (we use Transpose.h but this doesn't count as a test for it) @@ -150,4 +151,8 @@ template void product(const MatrixType& m) { VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1)); } + + // inner product + Scalar x = square2.row(c) * square2.col(c2); + VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum()); } From 143e6ab9d0a86407763e3608ef60f8c9c69a33fd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Jun 2010 10:12:13 +0200 Subject: [PATCH 16/67] improve aliasing detection for inverse and add unit test --- Eigen/src/LU/Inverse.h | 6 ++++-- test/inverse.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index e1276c6a3..5ccc59a32 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -295,8 +295,10 @@ struct ei_inverse_impl : public ReturnByValue > template inline void evalTo(Dest& dst) const { - // FIXME this is a naive aliasing check that could be improved. It only catches x = x.inverse(); - ei_assert(&dst != (Dest*)(&m_matrix) && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + const int Size = EIGEN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime); + ei_assert(( (Size<=1) || (Size>4) || (ei_extract_data(m_matrix)!=ei_extract_data(dst))) + && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + ei_compute_inverse::run(m_matrix, dst); } }; diff --git a/test/inverse.cpp b/test/inverse.cpp index 1e567ad14..4d9297eb4 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -82,6 +82,19 @@ template void inverse(const MatrixType& m) m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); #endif + + // check in-place inversion + if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4) + { + // in-place is forbidden + VERIFY_RAISES_ASSERT(m1 = m1.inverse()); + } + else + { + m2 = m1.inverse(); + m1 = m1.inverse(); + VERIFY_IS_APPROX(m1,m2); + } } void test_inverse() From 8710bd23e7a3727af31e539bfbe039ab3d07fedd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Jun 2010 13:32:13 +0200 Subject: [PATCH 17/67] clean the ambiguity with insertBack and add a insertBackByOuterInner function --- Eigen/src/Sparse/CholmodSupport.h | 1 + Eigen/src/Sparse/DynamicSparseMatrix.h | 94 +++++++++------- Eigen/src/Sparse/RandomSetter.h | 2 +- Eigen/src/Sparse/SparseMatrix.h | 150 +++++++++++++++---------- Eigen/src/Sparse/SparseMatrixBase.h | 4 +- Eigen/src/Sparse/SparseProduct.h | 2 +- Eigen/src/Sparse/SparseVector.h | 80 +++++++------ doc/C07_TutorialSparse.dox | 2 +- test/sparse.h | 12 +- test/sparse_basic.cpp | 4 +- 10 files changed, 205 insertions(+), 146 deletions(-) diff --git a/Eigen/src/Sparse/CholmodSupport.h b/Eigen/src/Sparse/CholmodSupport.h index 82a09f35c..1b34492aa 100644 --- a/Eigen/src/Sparse/CholmodSupport.h +++ b/Eigen/src/Sparse/CholmodSupport.h @@ -128,6 +128,7 @@ class SparseLLT : public SparseLLT typedef typename Base::Scalar Scalar; typedef typename Base::RealScalar RealScalar; typedef typename Base::CholMatrixType CholMatrixType; + typedef typename MatrixType::Index Index; using Base::MatrixLIsDirty; using Base::SupernodalFactorIsDirty; using Base::m_flags; diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index fea707f15..dea71bdba 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -127,13 +127,7 @@ class DynamicSparseMatrix return res; } - /** \deprecated - * Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - reserve(reserveSize); - } + void reserve(Index reserveSize = 1000) { @@ -147,9 +141,21 @@ class DynamicSparseMatrix } } + /** Does nothing: provided for compatibility with SparseMatrix */ inline void startVec(Index /*outer*/) {} - inline Scalar& insertBack(Index outer, Index inner) + /** \returns a reference to the non zero coefficient at position \a row, \a col assuming that: + * - the nonzero does not already exist + * - the new coefficient is the last one of the given inner vector. + * + * \sa insert, insertBackByInnerOuter */ + inline Scalar& insertBack(Index row, Index col) + { + return insertBackByInnerOuter(IsRowMajor?row:col, IsRowMajor?col:row); + } + + /** \sa insertBack */ + inline Scalar& insertBackByOuterInner(Index outer, Index inner) { ei_assert(outer= \a row. Otherwise the matrix is invalid. - * - * \see fillrand(), coeffRef() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return insertBack(outer,inner); - } - - /** \deprecated use insert() - * Like fill() but with random inner coordinates. - * Compared to the generic coeffRef(), the unique limitation is that we assume - * the coefficient does not exist yet. - */ - EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) - { - return insert(row,col); - } - inline Scalar& insert(Index row, Index col) { const Index outer = IsRowMajor ? row : col; @@ -204,12 +184,10 @@ class DynamicSparseMatrix return m_data[outer].value(id+1); } - /** \deprecated use finalize() - * Does nothing. Provided for compatibility with SparseMatrix. */ - EIGEN_DEPRECATED void endFill() {} - + /** Does nothing: provided for compatibility with SparseMatrix */ inline void finalize() {} + /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */ void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) { for (Index j=0; j= \a row. Otherwise the matrix is invalid. + * + * \see fillrand(), coeffRef() + */ + EIGEN_DEPRECATED Scalar& fill(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + return insertBack(outer,inner); + } + + /** \deprecated use insert() + * Like fill() but with random inner coordinates. + * Compared to the generic coeffRef(), the unique limitation is that we assume + * the coefficient does not exist yet. + */ + EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) + { + return insert(row,col); + } + + /** \deprecated use finalize() + * Does nothing. Provided for compatibility with SparseMatrix. */ + EIGEN_DEPRECATED void endFill() {} }; template diff --git a/Eigen/src/Sparse/RandomSetter.h b/Eigen/src/Sparse/RandomSetter.h index abe98815f..18777e23d 100644 --- a/Eigen/src/Sparse/RandomSetter.h +++ b/Eigen/src/Sparse/RandomSetter.h @@ -243,7 +243,7 @@ class RandomSetter mp_target->startVec(j); prevOuter = outer; } - mp_target->insertBack(outer, inner) = it->second.value; + mp_target->insertBackByOuterInner(outer, inner) = it->second.value; } } mp_target->finalize(); diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index fd41d7302..b60aba853 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -135,67 +135,41 @@ class SparseMatrix /** \returns the number of non zero coefficients */ inline Index nonZeros() const { return static_cast(m_data.size()); } - /** \deprecated use setZero() and reserve() - * Initializes the filling process of \c *this. - * \param reserveSize approximate number of nonzeros - * Note that the matrix \c *this is zero-ed. - */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - m_data.reserve(reserveSize); - } - /** Preallocates \a reserveSize non zeros */ inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - /** \deprecated use insert() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - if (m_outerIndex[outer+1]==0) - { - // we start a new inner vector - Index i = outer; - while (i>=0 && m_outerIndex[i]==0) - { - m_outerIndex[i] = m_data.size(); - --i; - } - m_outerIndex[outer+1] = m_outerIndex[outer]; - } - else - { - ei_assert(m_data.index(m_data.size()-1)::dummy_precision()) { Index k = 0; @@ -389,23 +358,29 @@ class SparseMatrix } memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); } + + /** Low level API + * Resize the nonzero vector to \a size */ void resizeNonZeros(Index size) { m_data.resize(size); } + /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ inline SparseMatrix() : m_outerSize(-1), m_innerSize(0), m_outerIndex(0) { resize(0, 0); } + /** Constructs a \a rows \c x \a cols empty matrix */ inline SparseMatrix(Index rows, Index cols) : m_outerSize(0), m_innerSize(0), m_outerIndex(0) { resize(rows, cols); } + /** Constructs a sparse matrix from the sparse expression \a other */ template inline SparseMatrix(const SparseMatrixBase& other) : m_outerSize(0), m_innerSize(0), m_outerIndex(0) @@ -413,12 +388,14 @@ class SparseMatrix *this = other.derived(); } + /** Copy constructor */ inline SparseMatrix(const SparseMatrix& other) : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0) { *this = other.derived(); } + /** Swap the content of two sparse matrices of same type (optimization) */ inline void swap(SparseMatrix& other) { //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); @@ -444,11 +421,13 @@ class SparseMatrix return *this; } + #ifndef EIGEN_PARSED_BY_DOXYGEN template inline SparseMatrix& operator=(const SparseProduct& product) { return Base::operator=(product); } + #endif template EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other) @@ -534,6 +513,61 @@ class SparseMatrix /** Overloaded for performance */ Scalar sum() const; + + public: + + /** \deprecated use setZero() and reserve() + * Initializes the filling process of \c *this. + * \param reserveSize approximate number of nonzeros + * Note that the matrix \c *this is zero-ed. + */ + EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) + { + setZero(); + m_data.reserve(reserveSize); + } + + /** \deprecated use insert() + * Like fill() but with random inner coordinates. + */ + EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) + { + return insert(row,col); + } + + /** \deprecated use insert() + */ + EIGEN_DEPRECATED Scalar& fill(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + if (m_outerIndex[outer+1]==0) + { + // we start a new inner vector + Index i = outer; + while (i>=0 && m_outerIndex[i]==0) + { + m_outerIndex[i] = m_data.size(); + --i; + } + m_outerIndex[outer+1] = m_outerIndex[outer]; + } + else + { + ei_assert(m_data.index(m_data.size()-1) diff --git a/Eigen/src/Sparse/SparseMatrixBase.h b/Eigen/src/Sparse/SparseMatrixBase.h index a4326821d..6f34b5c4e 100644 --- a/Eigen/src/Sparse/SparseMatrixBase.h +++ b/Eigen/src/Sparse/SparseMatrixBase.h @@ -209,7 +209,7 @@ template class SparseMatrixBase : public EigenBase { Scalar v = it.value(); if (v!=Scalar(0)) - temp.insertBack(Flip?it.index():j,Flip?j:it.index()) = v; + temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v; } } temp.finalize(); @@ -239,7 +239,7 @@ template class SparseMatrixBase : public EigenBase { Scalar v = it.value(); if (v!=Scalar(0)) - derived().insertBack(j,it.index()) = v; + derived().insertBackByOuterInner(j,it.index()) = v; } } derived().finalize(); diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index fb53902f4..1cb676132 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -265,7 +265,7 @@ static void ei_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& r } res.startVec(j); for (typename AmbiVector::Iterator it(tempVector); it; ++it) - res.insertBack(j,it.index()) = it.value(); + res.insertBackByOuterInner(j,it.index()) = it.value(); } res.finalize(); } diff --git a/Eigen/src/Sparse/SparseVector.h b/Eigen/src/Sparse/SparseVector.h index 4013b4de5..b15ab8220 100644 --- a/Eigen/src/Sparse/SparseVector.h +++ b/Eigen/src/Sparse/SparseVector.h @@ -127,7 +127,7 @@ class SparseVector ei_assert(outer==0); } - inline Scalar& insertBack(Index outer, Index inner) + inline Scalar& insertBackByOuterInner(Index outer, Index inner) { ei_assert(outer==0); return insertBack(inner); @@ -138,8 +138,10 @@ class SparseVector return m_data.value(m_data.size()-1); } - inline Scalar& insert(Index outer, Index inner) + inline Scalar& insert(Index row, Index col) { + Index inner = IsColVector ? row : col; + Index outer = IsColVector ? col : row; ei_assert(outer==0); return insert(inner); } @@ -165,42 +167,7 @@ class SparseVector */ inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - /** \deprecated use setZero() and reserve() */ - EIGEN_DEPRECATED void startFill(Index reserve) - { - setZero(); - m_data.reserve(reserve); - } - /** \deprecated use insertBack(Index,Index) */ - EIGEN_DEPRECATED Scalar& fill(Index r, Index c) - { - ei_assert(r==0 || c==0); - return fill(IsColVector ? r : c); - } - - /** \deprecated use insertBack(Index) */ - EIGEN_DEPRECATED Scalar& fill(Index i) - { - m_data.append(0, i); - return m_data.value(m_data.size()-1); - } - - /** \deprecated use insert(Index,Index) */ - EIGEN_DEPRECATED Scalar& fillrand(Index r, Index c) - { - ei_assert(r==0 || c==0); - return fillrand(IsColVector ? r : c); - } - - /** \deprecated use insert(Index) */ - EIGEN_DEPRECATED Scalar& fillrand(Index i) - { - return insert(i); - } - - /** \deprecated use finalize() */ - EIGEN_DEPRECATED void endFill() {} inline void finalize() {} void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) @@ -362,6 +329,45 @@ class SparseVector /** Overloaded for performance */ Scalar sum() const; + + public: + + /** \deprecated use setZero() and reserve() */ + EIGEN_DEPRECATED void startFill(Index reserve) + { + setZero(); + m_data.reserve(reserve); + } + + /** \deprecated use insertBack(Index,Index) */ + EIGEN_DEPRECATED Scalar& fill(Index r, Index c) + { + ei_assert(r==0 || c==0); + return fill(IsColVector ? r : c); + } + + /** \deprecated use insertBack(Index) */ + EIGEN_DEPRECATED Scalar& fill(Index i) + { + m_data.append(0, i); + return m_data.value(m_data.size()-1); + } + + /** \deprecated use insert(Index,Index) */ + EIGEN_DEPRECATED Scalar& fillrand(Index r, Index c) + { + ei_assert(r==0 || c==0); + return fillrand(IsColVector ? r : c); + } + + /** \deprecated use insert(Index) */ + EIGEN_DEPRECATED Scalar& fillrand(Index i) + { + return insert(i); + } + + /** \deprecated use finalize() */ + EIGEN_DEPRECATED void endFill() {} }; template diff --git a/doc/C07_TutorialSparse.dox b/doc/C07_TutorialSparse.dox index ae96d77c4..ee8a1a100 100644 --- a/doc/C07_TutorialSparse.dox +++ b/doc/C07_TutorialSparse.dox @@ -183,7 +183,7 @@ for(int j=0; j<1000; ++j) } mat.finalize(); // optional for a DynamicSparseMatrix \endcode - +Note that there also exist the insertBackByOuterInner(Index outer, Index, inner) function which allows to write code agnostic to the storage order. \section TutorialSparseFeatureSet Supported operators and functions diff --git a/test/sparse.h b/test/sparse.h index f0d230153..4733e4d10 100644 --- a/test/sparse.h +++ b/test/sparse.h @@ -81,13 +81,13 @@ initSparse(double density, v = Scalar(0); else if ((flags & MakeUpperTriangular) && jpush_back(Vector2i(i,j)); } @@ -126,13 +126,13 @@ initSparse(double density, v = Scalar(0); else if ((flags & MakeUpperTriangular) && jpush_back(Vector2i(i,j)); } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 9de156d38..43d9c6254 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -323,12 +323,12 @@ template void sparse_basic(const SparseMatrixType& re else if (x<0.5) { countFalseNonZero++; - m2.insertBack(j,i) = Scalar(0); + m2.insertBackByOuterInner(j,i) = Scalar(0); } else { countTrueNonZero++; - m2.insertBack(j,i) = refM2(i,j) = Scalar(1); + m2.insertBackByOuterInner(j,i) = refM2(i,j) = Scalar(1); } } } From 9ff0d67156377e4d7a39669a415f120b61846901 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Jun 2010 17:56:35 +0200 Subject: [PATCH 18/67] fix typos (oops) --- Eigen/src/Sparse/DynamicSparseMatrix.h | 4 ++-- Eigen/src/Sparse/SparseMatrix.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index dea71bdba..defe312b3 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -148,10 +148,10 @@ class DynamicSparseMatrix * - the nonzero does not already exist * - the new coefficient is the last one of the given inner vector. * - * \sa insert, insertBackByInnerOuter */ + * \sa insert, insertBackByOuterInner */ inline Scalar& insertBack(Index row, Index col) { - return insertBackByInnerOuter(IsRowMajor?row:col, IsRowMajor?col:row); + return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); } /** \sa insertBack */ diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index b60aba853..22a7d149a 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -151,10 +151,10 @@ class SparseMatrix * * After an insertion session, you should call the finalize() function. * - * \sa insert, insertBackByInnerOuter, startVec */ + * \sa insert, insertBackByOuterInner, startVec */ inline Scalar& insertBack(Index row, Index col) { - return insertBackByInnerOuter(IsRowMajor?row:col, IsRowMajor?col:row); + return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); } /** \sa insertBack, startVec */ @@ -169,7 +169,7 @@ class SparseMatrix } /** \warning use it only if you know what you are doing */ - inline Scalar& insertBackByInnerOuterUnordered(Index outer, Index inner) + inline Scalar& insertBackByOuterInnerUnordered(Index outer, Index inner) { Index id = m_outerIndex[outer+1]; ++m_outerIndex[outer+1]; @@ -177,7 +177,7 @@ class SparseMatrix return m_data.value(id); } - /** \sa insertBack, insertBackByInnerOuter */ + /** \sa insertBack, insertBackByOuterInner */ inline void startVec(Index outer) { ei_assert(m_outerIndex[outer]==int(m_data.size()) && "You must call startVec for each inner vector sequentially"); From 38d8352b7bc6c839297aee11a91e64aff4d51aff Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Wed, 2 Jun 2010 17:31:02 +0100 Subject: [PATCH 19/67] Add field m_maxIterations; break loop when this limit is exceeded. --- Eigen/src/Eigenvalues/ComplexSchur.h | 12 ++++++++--- Eigen/src/Eigenvalues/RealSchur.h | 15 ++++++++++++-- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 20 +++++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index a4812dac6..cf6755bfc 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -192,6 +192,12 @@ template class ComplexSchur */ ComplexSchur& compute(const MatrixType& matrix, bool computeU = true); + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 30; + protected: ComplexMatrixType m_matT, m_matU; HessenbergDecomposition m_hess; @@ -374,9 +380,9 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) // if iu is zero then we are done; the whole matrix is triangularized if(iu==0) break; - // if we spent 30 iterations on the current element, we give up + // if we spent too many iterations on the current element, we give up iter++; - if(iter >= 30) break; + if(iter >= m_maxIterations) break; // find il, the top row of the active submatrix il = iu-1; @@ -406,7 +412,7 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) } } - if(iter >= 30) + if(iter >= m_maxIterations) { // FIXME : what to do when iter==MAXITER ?? // std::cerr << "MAXITER" << std::endl; diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index 41f74e530..584b1d05e 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -176,6 +176,12 @@ template class RealSchur */ RealSchur& compute(const MatrixType& matrix, bool computeU = true); + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 40; + private: MatrixType m_matT; @@ -244,14 +250,19 @@ RealSchur& RealSchur::compute(const MatrixType& matrix, Vector3s firstHouseholderVector, shiftInfo; computeShift(iu, iter, exshift, shiftInfo); iter = iter + 1; // (Could check iteration count here.) + if (iter >= m_maxIterations) break; Index im; initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); } } - m_isInitialized = true; - m_matUisUptodate = computeU; + if(iter < m_maxIterations) + { + m_isInitialized = true; + m_matUisUptodate = computeU; + } + return *this; } diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 20773a549..b08bbd7e2 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -360,6 +360,11 @@ template class SelfAdjointEigenSolver return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 30; protected: MatrixType m_eivec; @@ -419,6 +424,8 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( Index end = n-1; Index start = 0; + Index iter = 0; // number of iterations we are working on one element + while (end>0) { for (Index i = start; i& SelfAdjointEigenSolver::compute( // find the largest unreduced block while (end>0 && m_subdiag[end-1]==0) + { + iter = 0; end--; + } if (end<=0) break; + + // if we spent too many iterations on the current element, we give up + iter++; + if(iter >= m_maxIterations) break; + start = end - 1; while (start>0 && m_subdiag[start-1]!=0) start--; @@ -437,6 +452,11 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( ei_tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); } + if(iter >= m_maxIterations) + { + return *this; + } + // Sort eigenvalues and corresponding vectors. // TODO make the sort optional ? // TODO use a better sort algorithm !! From e40852d282d0c4434d24f265e355b0708ac71d68 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 2 Jun 2010 19:17:41 +0200 Subject: [PATCH 20/67] Fixes #104. --- Eigen/src/Array/VectorwiseOp.h | 20 ++++++++++---------- Eigen/src/Core/Block.h | 2 +- Eigen/src/Core/DenseStorageBase.h | 6 ++++-- Eigen/src/Core/Dot.h | 2 +- Eigen/src/Core/MatrixStorage.h | 4 ++-- Eigen/src/Core/Redux.h | 4 ++-- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index f495aae40..8926e7a04 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -92,7 +92,7 @@ class PartialReduxExpr : ei_no_assignment_operator, Index rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); } Index cols() const { return (Direction==Horizontal ? 1 : m_matrix.cols()); } - const Scalar coeff(Index i, Index j) const + EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const { if (Direction==Vertical) return m_functor(m_matrix.col(j)); @@ -113,15 +113,15 @@ class PartialReduxExpr : ei_no_assignment_operator, const MemberOp m_functor; }; -#define EIGEN_MEMBER_FUNCTOR(MEMBER,COST) \ - template \ - struct ei_member_##MEMBER { \ - EIGEN_EMPTY_STRUCT_CTOR(ei_member_##MEMBER) \ - typedef ResultType result_type; \ - template struct Cost \ - { enum { value = COST }; }; \ - template \ - inline ResultType operator()(const XprType& mat) const \ +#define EIGEN_MEMBER_FUNCTOR(MEMBER,COST) \ + template \ + struct ei_member_##MEMBER { \ + EIGEN_EMPTY_STRUCT_CTOR(ei_member_##MEMBER) \ + typedef ResultType result_type; \ + template struct Cost \ + { enum { value = COST }; }; \ + template \ + EIGEN_STRONG_INLINE ResultType operator()(const XprType& mat) const \ { return mat.MEMBER(); } \ } diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index bb1b8a6b9..59a0f72bc 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -162,7 +162,7 @@ template c .coeffRef(row + m_startRow.value(), col + m_startCol.value()); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const { return m_xpr.coeff(row + m_startRow.value(), col + m_startCol.value()); } diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index a9c4607b7..211984973 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -159,7 +159,7 @@ class DenseStorageBase : public ei_dense_xpr_base::type * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ - inline void resize(Index rows, Index cols) + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) { #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO Index size = rows*cols; @@ -471,7 +471,9 @@ class DenseStorageBase : public ei_dense_xpr_base::type template EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { - _resize_to_match(other); + // I don't think we need this resize call since the lazyAssign will anyways resize + // and lazyAssign will be called by the assign selector. + //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. return ei_assign_selector::run(this->derived(), other.derived()); diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index 6e54dac3c..dfa313e89 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -85,7 +85,7 @@ MatrixBase::dot(const MatrixBase& other) const * \sa dot(), norm() */ template -inline typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const +EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const { return ei_real((*this).cwiseAbs2().sum()); } diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index aff83a64c..0165966f4 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -243,7 +243,7 @@ template class ei_matrix_storage(m_data, size, _Rows*m_cols); m_cols = cols; } - void resize(DenseIndex size, DenseIndex, DenseIndex cols) + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex cols) { if(size != _Rows*m_cols) { @@ -279,7 +279,7 @@ template class ei_matrix_storage(m_data, size, m_rows*_Cols); m_rows = rows; } - void resize(DenseIndex size, DenseIndex rows, DenseIndex) + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex rows, DenseIndex) { if(size != m_rows*_Cols) { diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 3fd5de74c..4d40a2029 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -177,7 +177,7 @@ struct ei_redux_impl { typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; - static Scalar run(const Derived& mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) { ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix"); Scalar res; @@ -307,7 +307,7 @@ struct ei_redux_impl template -inline typename ei_result_of::Scalar)>::type +EIGEN_STRONG_INLINE typename ei_result_of::Scalar)>::type DenseBase::redux(const Func& func) const { typedef typename ei_cleantype::type ThisNested; From 8350ab9fb85d278cf2687efc86d211b25741c657 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Jun 2010 08:41:11 +0200 Subject: [PATCH 21/67] * remove ei_index, and let ei_traits propagate the index types * add an Index type template parapeter to sparse objects --- Eigen/src/Array/ArrayBase.h | 2 +- Eigen/src/Core/BandMatrix.h | 1 + Eigen/src/Core/CwiseBinaryOp.h | 8 +++-- Eigen/src/Core/CwiseUnaryOp.h | 2 +- Eigen/src/Core/CwiseUnaryView.h | 2 +- Eigen/src/Core/DenseBase.h | 2 +- Eigen/src/Core/DenseCoeffsBase.h | 6 ++-- Eigen/src/Core/DenseStorageBase.h | 2 +- Eigen/src/Core/DiagonalMatrix.h | 6 ++-- Eigen/src/Core/EigenBase.h | 2 +- Eigen/src/Core/MapBase.h | 2 +- Eigen/src/Core/Matrix.h | 1 + Eigen/src/Core/MatrixBase.h | 4 +-- Eigen/src/Core/ProductBase.h | 2 ++ Eigen/src/Core/Transpose.h | 2 +- Eigen/src/Core/TriangularMatrix.h | 4 +-- Eigen/src/Core/products/CoeffBasedProduct.h | 2 ++ Eigen/src/Core/util/Macros.h | 10 ++---- Eigen/src/Core/util/XprHelper.h | 13 +++---- Eigen/src/Householder/HouseholderSequence.h | 1 + Eigen/src/LU/FullPivLU.h | 2 +- Eigen/src/LU/PartialPivLU.h | 2 +- Eigen/src/Sparse/AmbiVector.h | 38 +++++++++++---------- Eigen/src/Sparse/CholmodSupport.h | 4 +-- Eigen/src/Sparse/CompressedStorage.h | 26 +++++++++----- Eigen/src/Sparse/DynamicSparseMatrix.h | 21 ++++++------ Eigen/src/Sparse/MappedSparseMatrix.h | 24 ++++++------- Eigen/src/Sparse/SparseBlock.h | 7 ++-- Eigen/src/Sparse/SparseDiagonalProduct.h | 4 ++- Eigen/src/Sparse/SparseLDLT.h | 2 +- Eigen/src/Sparse/SparseLLT.h | 4 +-- Eigen/src/Sparse/SparseMatrix.h | 18 +++++----- Eigen/src/Sparse/SparseMatrixBase.h | 2 +- Eigen/src/Sparse/SparseProduct.h | 6 ++-- Eigen/src/Sparse/SparseRedux.h | 12 +++---- Eigen/src/Sparse/SparseUtil.h | 33 +++--------------- Eigen/src/Sparse/SparseVector.h | 25 +++++++------- Eigen/src/Sparse/SuperLUSupport.h | 4 +-- Eigen/src/Sparse/TaucsSupport.h | 4 +-- Eigen/src/Sparse/TriangularSolver.h | 6 ++-- 40 files changed, 162 insertions(+), 156 deletions(-) diff --git a/Eigen/src/Array/ArrayBase.h b/Eigen/src/Array/ArrayBase.h index ccbc77202..527bcd329 100644 --- a/Eigen/src/Array/ArrayBase.h +++ b/Eigen/src/Array/ArrayBase.h @@ -61,7 +61,7 @@ template class ArrayBase typename NumTraits::Scalar>::Real>::operator*; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index fbe7e394b..af2a81df3 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -47,6 +47,7 @@ struct ei_traits > { typedef _Scalar Scalar; typedef Dense StorageKind; + typedef DenseIndex Index; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = Rows, diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 530777577..6e158fdf1 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -57,6 +57,8 @@ struct ei_traits > : ei_traits >::type Scalar; typedef typename ei_promote_storage_type::StorageKind, typename ei_traits::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type::Index, + typename ei_traits::Index>::type Index; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename ei_unref::type _LhsNested; @@ -97,7 +99,7 @@ class CwiseBinaryOp : ei_no_assignment_operator, BinaryOp, Lhs, Rhs, typename ei_promote_storage_type::StorageKind, typename ei_traits::StorageKind>::ret>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseBinaryOp) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) typedef typename ei_nested::type LhsNested; typedef typename ei_nested::type RhsNested; @@ -125,14 +127,14 @@ class CwiseBinaryOp : ei_no_assignment_operator, EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations - if (ei_traits::type>::RowsAtCompileTime==Dynamic) + if (ei_traits::type>::RowsAtCompileTime==Dynamic) return m_rhs.rows(); else return m_lhs.rows(); } EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations - if (ei_traits::type>::ColsAtCompileTime==Dynamic) + if (ei_traits::type>::ColsAtCompileTime==Dynamic) return m_rhs.cols(); else return m_lhs.cols(); diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index da398d131..a05ef1d9f 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -71,7 +71,7 @@ class CwiseUnaryOp : ei_no_assignment_operator, public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseUnaryOp) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 11a23c66a..1fbe440af 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -67,7 +67,7 @@ class CwiseUnaryView : ei_no_assignment_operator, public: typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseUnaryView) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 80db0f421..95e37801d 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -51,7 +51,7 @@ template class DenseBase class InnerIterator; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; diff --git a/Eigen/src/Core/DenseCoeffsBase.h b/Eigen/src/Core/DenseCoeffsBase.h index 7026bbe34..c55576c02 100644 --- a/Eigen/src/Core/DenseCoeffsBase.h +++ b/Eigen/src/Core/DenseCoeffsBase.h @@ -30,7 +30,7 @@ class DenseCoeffsBase : public EigenBase { public: typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename ei_meta_if::ret, const Scalar&, Scalar>::ret CoeffReturnType; @@ -40,7 +40,7 @@ class DenseCoeffsBase : public EigenBase using Base::cols; using Base::size; using Base::derived; - + EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 @@ -245,7 +245,7 @@ class DenseCoeffsBase : public DenseCoeffsBase typedef DenseCoeffsBase Base; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index 15f3988ea..a9c4607b7 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -46,7 +46,7 @@ class DenseStorageBase : public ei_dense_xpr_base::type typedef typename ei_dense_xpr_base::type Base; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 8d3b458a9..34eeda089 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -34,7 +34,7 @@ class DiagonalBase : public EigenBase typedef typename ei_traits::DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -103,6 +103,7 @@ struct ei_traits { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; typedef Dense StorageKind; + typedef DenseIndex Index; }; template @@ -115,7 +116,7 @@ class DiagonalMatrix typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; #endif protected: @@ -203,6 +204,7 @@ struct ei_traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::Index Index; typedef typename DiagonalVectorType::StorageKind StorageKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, diff --git a/Eigen/src/Core/EigenBase.h b/Eigen/src/Core/EigenBase.h index c9d3bd875..3485b36d2 100644 --- a/Eigen/src/Core/EigenBase.h +++ b/Eigen/src/Core/EigenBase.h @@ -40,7 +40,7 @@ template struct EigenBase // typedef typename ei_plain_matrix_type::type PlainObject; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; /** \returns a reference to the derived object */ Derived& derived() { return *static_cast(this); } diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 8cdd452ac..e0b3a7857 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -46,7 +46,7 @@ template class MapBase typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 4407b0db1..54fca7046 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -113,6 +113,7 @@ struct ei_traits > { typedef _Scalar Scalar; typedef Dense StorageKind; + typedef DenseIndex Index; typedef MatrixXpr XprKind; enum { RowsAtCompileTime = _Rows, diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 633b0106e..ebda37d07 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -58,11 +58,11 @@ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; - + typedef DenseBase Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 36626f838..35a3a280f 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -37,6 +37,8 @@ struct ei_traits > typedef typename ei_scalar_product_traits::ReturnType Scalar; typedef typename ei_promote_storage_type::StorageKind, typename ei_traits::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type::Index, + typename ei_traits::Index>::type Index; enum { RowsAtCompileTime = ei_traits::RowsAtCompileTime, ColsAtCompileTime = ei_traits::ColsAtCompileTime, diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 38d942e04..6928ae31a 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -66,7 +66,7 @@ template class Transpose public: typedef typename TransposeImpl::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) + EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose) inline Transpose(const MatrixType& matrix) : m_matrix(matrix) {} diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index d4799fbc1..20af49c90 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -46,7 +46,7 @@ template class TriangularBase : public EigenBase }; typedef typename ei_traits::Scalar Scalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; inline TriangularBase() { ei_assert(!((Mode&UnitDiag) && (Mode&ZeroDiag))); } @@ -159,7 +159,7 @@ template class TriangularView using Base::evalToLazy; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; enum { Mode = _Mode, diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 0c39cbd84..317fdfd4c 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -54,6 +54,8 @@ struct ei_traits > typedef typename ei_scalar_product_traits::ReturnType Scalar; typedef typename ei_promote_storage_type::StorageKind, typename ei_traits<_RhsNested>::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type::Index, + typename ei_traits<_RhsNested>::Index>::type Index; enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 312a14414..82045b37c 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -98,10 +98,6 @@ #define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t #endif -#ifndef EIGEN_DEFAULT_SPARSE_INDEX_TYPE -#define EIGEN_DEFAULT_SPARSE_INDEX_TYPE int -#endif - /** Allows to disable some optimizations which might affect the accuracy of the result. * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them. * They currently include: @@ -269,13 +265,13 @@ * documentation in a single line. **/ -#define EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Derived) \ +#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ typedef typename Eigen::ei_traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ typedef typename Eigen::ei_nested::type Nested; \ typedef typename Eigen::ei_traits::StorageKind StorageKind; \ - typedef typename Eigen::ei_index::type Index; \ + typedef typename Eigen::ei_traits::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ Flags = Eigen::ei_traits::Flags, \ @@ -292,7 +288,7 @@ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ typedef typename Eigen::ei_nested::type Nested; \ typedef typename Eigen::ei_traits::StorageKind StorageKind; \ - typedef typename Eigen::ei_index::type Index; \ + typedef typename Eigen::ei_traits::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ MaxRowsAtCompileTime = Eigen::ei_traits::MaxRowsAtCompileTime, \ diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 63e99730a..9b82a609a 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -42,13 +42,14 @@ class ei_no_assignment_operator ei_no_assignment_operator& operator=(const ei_no_assignment_operator&); }; -template struct ei_index {}; +typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; -template<> -struct ei_index -{ typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE type; }; - -typedef ei_index::type DenseIndex; +/** \internal return the index type with the largest number of bits */ +template +struct ei_promote_index_type +{ + typedef typename ei_meta_if<(sizeof(I1)::ret type; +}; /** \internal If the template parameter Value is Dynamic, this class is just a wrapper around a T variable that * can be accessed using value() and setValue(). diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 90c5bf8a2..835fe6a1c 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -53,6 +53,7 @@ template struct ei_traits > { typedef typename VectorsType::Scalar Scalar; + typedef typename VectorsType::Index Index; typedef typename VectorsType::StorageKind StorageKind; enum { RowsAtCompileTime = Side==OnTheLeft ? ei_traits::RowsAtCompileTime diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index da4dce6bc..61a6fd730 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -69,7 +69,7 @@ template class FullPivLU typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename MatrixType::Index Index; typedef typename ei_plain_row_type::type IntRowVectorType; typedef typename ei_plain_col_type::type IntColVectorType; typedef PermutationMatrix PermutationQType; diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 39c348e5e..0bf1ac3ce 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -72,7 +72,7 @@ template class PartialPivLU typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename MatrixType::Index Index; typedef typename ei_plain_col_type::type PermutationVectorType; typedef PermutationMatrix PermutationType; diff --git a/Eigen/src/Sparse/AmbiVector.h b/Eigen/src/Sparse/AmbiVector.h index 7b18f8cc2..673cb32a5 100644 --- a/Eigen/src/Sparse/AmbiVector.h +++ b/Eigen/src/Sparse/AmbiVector.h @@ -30,12 +30,14 @@ * * See BasicSparseLLT and SparseProduct for usage examples. */ -template class AmbiVector +template +class AmbiVector { public: typedef _Scalar Scalar; + typedef _Index Index; typedef typename NumTraits::Real RealScalar; - typedef SparseIndex Index; + AmbiVector(Index size) : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) { @@ -130,8 +132,8 @@ template class AmbiVector }; /** \returns the number of non zeros in the current sub vector */ -template -SparseIndex AmbiVector::nonZeros() const +template +_Index AmbiVector<_Scalar,_Index>::nonZeros() const { if (m_mode==IsSparse) return m_llSize; @@ -139,8 +141,8 @@ SparseIndex AmbiVector::nonZeros() const return m_end - m_start; } -template -void AmbiVector::init(double estimatedDensity) +template +void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) { if (estimatedDensity>0.1) init(IsDense); @@ -148,8 +150,8 @@ void AmbiVector::init(double estimatedDensity) init(IsSparse); } -template -void AmbiVector::init(int mode) +template +void AmbiVector<_Scalar,_Index>::init(int mode) { m_mode = mode; if (m_mode==IsSparse) @@ -164,15 +166,15 @@ void AmbiVector::init(int mode) * * Don't worry, this function is extremely cheap. */ -template -void AmbiVector::restart() +template +void AmbiVector<_Scalar,_Index>::restart() { m_llCurrent = m_llStart; } /** Set all coefficients of current subvector to zero */ -template -void AmbiVector::setZero() +template +void AmbiVector<_Scalar,_Index>::setZero() { if (m_mode==IsDense) { @@ -187,8 +189,8 @@ void AmbiVector::setZero() } } -template -Scalar& AmbiVector::coeffRef(Index i) +template +_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -256,8 +258,8 @@ Scalar& AmbiVector::coeffRef(Index i) } } -template -Scalar& AmbiVector::coeff(Index i) +template +_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -284,8 +286,8 @@ Scalar& AmbiVector::coeff(Index i) } /** Iterator over the nonzero coefficients */ -template -class AmbiVector<_Scalar>::Iterator +template +class AmbiVector<_Scalar,_Index>::Iterator { public: typedef _Scalar Scalar; diff --git a/Eigen/src/Sparse/CholmodSupport.h b/Eigen/src/Sparse/CholmodSupport.h index 1b34492aa..a8d7a8fec 100644 --- a/Eigen/src/Sparse/CholmodSupport.h +++ b/Eigen/src/Sparse/CholmodSupport.h @@ -109,8 +109,8 @@ cholmod_dense ei_cholmod_map_eigen_to_dense(MatrixBase& mat) return res; } -template -MappedSparseMatrix::MappedSparseMatrix(cholmod_sparse& cm) +template +MappedSparseMatrix::MappedSparseMatrix(cholmod_sparse& cm) { m_innerSize = cm.nrow; m_outerSize = cm.ncol; diff --git a/Eigen/src/Sparse/CompressedStorage.h b/Eigen/src/Sparse/CompressedStorage.h index 37d337639..73488f225 100644 --- a/Eigen/src/Sparse/CompressedStorage.h +++ b/Eigen/src/Sparse/CompressedStorage.h @@ -28,12 +28,20 @@ /** Stores a sparse set of values as a list of values and a list of indices. * */ -template +template class CompressedStorage { - typedef typename NumTraits::Real RealScalar; - typedef SparseIndex Index; public: + + typedef _Scalar Scalar; + typedef _Index Index; + + protected: + + typedef typename NumTraits::Real RealScalar; + + public: + CompressedStorage() : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) {} @@ -118,13 +126,13 @@ class CompressedStorage res.m_allocatedSize = res.m_size = size; return res; } - + /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ inline Index searchLowerIndex(Index key) const { return searchLowerIndex(0, m_size, key); } - + /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ inline Index searchLowerIndex(size_t start, size_t end, Index key) const { @@ -138,7 +146,7 @@ class CompressedStorage } return static_cast(start); } - + /** \returns the stored value at index \a key * If the value does not exist, then the value \a defaultValue is returned without any insertion. */ inline Scalar at(Index key, Scalar defaultValue = Scalar(0)) const @@ -152,7 +160,7 @@ class CompressedStorage const size_t id = searchLowerIndex(0,m_size-1,key); return ((id::dummy_precision()) { size_t k = 0; diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index defe312b3..d0ce2b248 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -42,10 +42,11 @@ * * \see SparseMatrix */ -template -struct ei_traits > +template +struct ei_traits > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -59,12 +60,12 @@ struct ei_traits > }; }; -template +template class DynamicSparseMatrix - : public SparseMatrixBase > + : public SparseMatrixBase > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(DynamicSparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(DynamicSparseMatrix) // FIXME: why are these operator already alvailable ??? // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, +=) // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, -=) @@ -76,7 +77,7 @@ class DynamicSparseMatrix typedef DynamicSparseMatrix TransposedSparseMatrix; Index m_innerSize; - std::vector > m_data; + std::vector > m_data; public: @@ -86,8 +87,8 @@ class DynamicSparseMatrix inline Index outerSize() const { return static_cast(m_data.size()); } inline Index innerNonZeros(Index j) const { return m_data[j].size(); } - std::vector >& _data() { return m_data; } - const std::vector >& _data() const { return m_data; } + std::vector >& _data() { return m_data; } + const std::vector >& _data() const { return m_data; } /** \returns the coefficient value at given position \a row, \a col * This operation involes a log(rho*outer_size) binary search. @@ -321,8 +322,8 @@ class DynamicSparseMatrix EIGEN_DEPRECATED void endFill() {} }; -template -class DynamicSparseMatrix::InnerIterator : public SparseVector::InnerIterator +template +class DynamicSparseMatrix::InnerIterator : public SparseVector::InnerIterator { typedef typename SparseVector::InnerIterator Base; public: diff --git a/Eigen/src/Sparse/MappedSparseMatrix.h b/Eigen/src/Sparse/MappedSparseMatrix.h index 07233ac67..99aeeb106 100644 --- a/Eigen/src/Sparse/MappedSparseMatrix.h +++ b/Eigen/src/Sparse/MappedSparseMatrix.h @@ -34,25 +34,25 @@ * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template -struct ei_traits > : ei_traits > +template +struct ei_traits > : ei_traits > {}; -template +template class MappedSparseMatrix - : public SparseMatrixBase > + : public SparseMatrixBase > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(MappedSparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) protected: enum { IsRowMajor = Base::IsRowMajor }; - Index m_outerSize; - Index m_innerSize; - Index m_nnz; - Index* m_outerIndex; - Index* m_innerIndices; + Index m_outerSize; + Index m_innerSize; + Index m_nnz; + Index* m_outerIndex; + Index* m_innerIndices; Scalar* m_values; public: @@ -135,8 +135,8 @@ class MappedSparseMatrix inline ~MappedSparseMatrix() {} }; -template -class MappedSparseMatrix::InnerIterator +template +class MappedSparseMatrix::InnerIterator { public: InnerIterator(const MappedSparseMatrix& mat, Index outer) diff --git a/Eigen/src/Sparse/SparseBlock.h b/Eigen/src/Sparse/SparseBlock.h index bf8b5adc7..8e530182d 100644 --- a/Eigen/src/Sparse/SparseBlock.h +++ b/Eigen/src/Sparse/SparseBlock.h @@ -29,6 +29,7 @@ template struct ei_traits > { typedef typename ei_traits::Scalar Scalar; + typedef typename ei_traits::Index Index; typedef typename ei_traits::StorageKind StorageKind; typedef MatrixXpr XprKind; enum { @@ -50,7 +51,7 @@ class SparseInnerVectorSet : ei_no_assignment_operator, enum { IsRowMajor = ei_traits::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: @@ -111,7 +112,7 @@ class SparseInnerVectorSet, Size> enum { IsRowMajor = ei_traits::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: @@ -209,7 +210,7 @@ class SparseInnerVectorSet, Size> enum { IsRowMajor = ei_traits::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: diff --git a/Eigen/src/Sparse/SparseDiagonalProduct.h b/Eigen/src/Sparse/SparseDiagonalProduct.h index 70b35bc23..f5da2c269 100644 --- a/Eigen/src/Sparse/SparseDiagonalProduct.h +++ b/Eigen/src/Sparse/SparseDiagonalProduct.h @@ -43,6 +43,8 @@ struct ei_traits > typedef typename ei_cleantype::type _Lhs; typedef typename ei_cleantype::type _Rhs; typedef typename _Lhs::Scalar Scalar; + typedef typename ei_promote_index_type::Index, + typename ei_traits::Index>::type Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -82,7 +84,7 @@ class SparseDiagonalProduct public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseDiagonalProduct) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) typedef ei_sparse_diagonal_product_inner_iterator_selector <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; diff --git a/Eigen/src/Sparse/SparseLDLT.h b/Eigen/src/Sparse/SparseLDLT.h index b6a51c6a6..ae1a96b4f 100644 --- a/Eigen/src/Sparse/SparseLDLT.h +++ b/Eigen/src/Sparse/SparseLDLT.h @@ -339,7 +339,7 @@ bool SparseLDLT::solveInPlace(MatrixBase &b) const // FIXME should be .adjoint() but it fails to compile... if (m_matrix.nonZeros()>0) // otherwise L==I - m_matrix.transpose().template triangularView().solveInPlace(b); + m_matrix.adjoint().template triangularView().solveInPlace(b); return true; } diff --git a/Eigen/src/Sparse/SparseLLT.h b/Eigen/src/Sparse/SparseLLT.h index 37c6c3f9a..4ec3ee009 100644 --- a/Eigen/src/Sparse/SparseLLT.h +++ b/Eigen/src/Sparse/SparseLLT.h @@ -132,7 +132,7 @@ void SparseLLT::compute(const MatrixType& a) m_matrix.resize(size, size); // allocate a temporary vector for accumulations - AmbiVector tempVector(size); + AmbiVector tempVector(size); RealScalar density = a.nonZeros()/RealScalar(size*size); // TODO estimate the number of non zeros @@ -177,7 +177,7 @@ void SparseLLT::compute(const MatrixType& a) RealScalar rx = ei_sqrt(ei_real(x)); m_matrix.insert(j,j) = rx; // FIXME use insertBack Scalar y = Scalar(1)/rx; - for (typename AmbiVector::Iterator it(tempVector, m_precision*rx); it; ++it) + for (typename AmbiVector::Iterator it(tempVector, m_precision*rx); it; ++it) { // FIXME use insertBack m_matrix.insert(it.index(), j) = it.value() * y; diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index 22a7d149a..e8e947eea 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -37,14 +37,16 @@ * \param _Scalar the scalar type, i.e. the type of the coefficients * \param _Options Union of bit flags controlling the storage scheme. Currently the only possibility * is RowMajor. The default is 0 which means column-major. + * \param _Index the type of the indices. Default is \c int. * * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template -struct ei_traits > +template +struct ei_traits > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -58,12 +60,12 @@ struct ei_traits > }; }; -template +template class SparseMatrix - : public SparseMatrixBase > + : public SparseMatrixBase > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) // FIXME: why are these operator already alvailable ??? @@ -80,7 +82,7 @@ class SparseMatrix Index m_outerSize; Index m_innerSize; Index* m_outerIndex; - CompressedStorage m_data; + CompressedStorage m_data; public: @@ -570,8 +572,8 @@ class SparseMatrix EIGEN_DEPRECATED void endFill() { finalize(); } }; -template -class SparseMatrix::InnerIterator +template +class SparseMatrix::InnerIterator { public: InnerIterator(const SparseMatrix& mat, Index outer) diff --git a/Eigen/src/Sparse/SparseMatrixBase.h b/Eigen/src/Sparse/SparseMatrixBase.h index 6f34b5c4e..a2b527e53 100644 --- a/Eigen/src/Sparse/SparseMatrixBase.h +++ b/Eigen/src/Sparse/SparseMatrixBase.h @@ -43,7 +43,7 @@ template class SparseMatrixBase : public EigenBase typedef typename ei_traits::Scalar Scalar; typedef typename ei_packet_traits::type PacketScalar; typedef typename ei_traits::StorageKind StorageKind; - typedef typename ei_index::type Index; + typedef typename ei_traits::Index Index; typedef SparseMatrixBase StorageBaseType; diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index 1cb676132..2f86b2b2d 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -57,6 +57,8 @@ struct ei_traits > typedef typename ei_cleantype::type _LhsNested; typedef typename ei_cleantype::type _RhsNested; typedef typename _LhsNested::Scalar Scalar; + typedef typename ei_promote_index_type::Index, + typename ei_traits<_RhsNested>::Index>::type Index; enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, @@ -236,7 +238,7 @@ static void ei_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& r ei_assert(lhs.outerSize() == rhs.innerSize()); // allocate a temporary buffer - AmbiVector tempVector(rows); + AmbiVector tempVector(rows); // estimate the number of non zero entries float ratioLhs = float(lhs.nonZeros())/(float(lhs.rows())*float(lhs.cols())); @@ -264,7 +266,7 @@ static void ei_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& r } } res.startVec(j); - for (typename AmbiVector::Iterator it(tempVector); it; ++it) + for (typename AmbiVector::Iterator it(tempVector); it; ++it) res.insertBackByOuterInner(j,it.index()) = it.value(); } res.finalize(); diff --git a/Eigen/src/Sparse/SparseRedux.h b/Eigen/src/Sparse/SparseRedux.h index ea2ce1870..241be6c2e 100644 --- a/Eigen/src/Sparse/SparseRedux.h +++ b/Eigen/src/Sparse/SparseRedux.h @@ -37,17 +37,17 @@ SparseMatrixBase::sum() const return res; } -template -typename ei_traits >::Scalar -SparseMatrix<_Scalar,_Options>::sum() const +template +typename ei_traits >::Scalar +SparseMatrix<_Scalar,_Options,_Index>::sum() const { ei_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); return Matrix::Map(&m_data.value(0), m_data.size()).sum(); } -template -typename ei_traits >::Scalar -SparseVector<_Scalar,_Options>::sum() const +template +typename ei_traits >::Scalar +SparseVector<_Scalar,_Options,_Index>::sum() const { ei_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); return Matrix::Map(&m_data.value(0), m_data.size()).sum(); diff --git a/Eigen/src/Sparse/SparseUtil.h b/Eigen/src/Sparse/SparseUtil.h index d94f5ce8c..f780f4087 100644 --- a/Eigen/src/Sparse/SparseUtil.h +++ b/Eigen/src/Sparse/SparseUtil.h @@ -56,30 +56,13 @@ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) -#define _EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::ei_traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Eigen::ei_nested::type Nested; \ - typedef typename Eigen::ei_traits::StorageKind StorageKind; \ - typedef typename Eigen::ei_index::type Index; \ - enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ - Flags = Eigen::ei_traits::Flags, \ - CoeffReadCost = Eigen::ei_traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - -#define EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived) \ - _EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) - #define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ typedef typename Eigen::ei_traits::Scalar Scalar; \ typedef typename Eigen::NumTraits::Real RealScalar; \ typedef typename Eigen::ei_nested::type Nested; \ typedef typename Eigen::ei_traits::StorageKind StorageKind; \ - typedef typename Eigen::ei_index::type Index; \ + typedef typename Eigen::ei_traits::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ Flags = Eigen::ei_traits::Flags, \ @@ -92,12 +75,6 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) #define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) -template<> -struct ei_index -{ typedef EIGEN_DEFAULT_SPARSE_INDEX_TYPE type; }; - -typedef ei_index::type SparseIndex; - enum SparseBackend { DefaultBackend, Taucs, @@ -128,10 +105,10 @@ enum { }; template class SparseMatrixBase; -template class SparseMatrix; -template class DynamicSparseMatrix; -template class SparseVector; -template class MappedSparseMatrix; +template class SparseMatrix; +template class DynamicSparseMatrix; +template class SparseVector; +template class MappedSparseMatrix; template class SparseInnerVectorSet; template class SparseTriangularView; diff --git a/Eigen/src/Sparse/SparseVector.h b/Eigen/src/Sparse/SparseVector.h index b15ab8220..dd81b749e 100644 --- a/Eigen/src/Sparse/SparseVector.h +++ b/Eigen/src/Sparse/SparseVector.h @@ -34,10 +34,11 @@ * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template -struct ei_traits > +template +struct ei_traits > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -53,12 +54,12 @@ struct ei_traits > }; }; -template +template class SparseVector - : public SparseMatrixBase > + : public SparseMatrixBase > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseVector) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, =) @@ -69,11 +70,11 @@ class SparseVector typedef SparseMatrixBase SparseBase; enum { IsColVector = ei_traits::IsColVector }; - CompressedStorage m_data; + CompressedStorage m_data; Index m_size; - CompressedStorage& _data() { return m_data; } - CompressedStorage& _data() const { return m_data; } + CompressedStorage& _data() { return m_data; } + CompressedStorage& _data() const { return m_data; } public: @@ -370,8 +371,8 @@ class SparseVector EIGEN_DEPRECATED void endFill() {} }; -template -class SparseVector::InnerIterator +template +class SparseVector::InnerIterator { public: InnerIterator(const SparseVector& vec, Index outer=0) @@ -380,7 +381,7 @@ class SparseVector::InnerIterator ei_assert(outer==0); } - InnerIterator(const CompressedStorage& data) + InnerIterator(const CompressedStorage& data) : m_data(data), m_id(0), m_end(static_cast(m_data.size())) {} @@ -401,7 +402,7 @@ class SparseVector::InnerIterator inline operator bool() const { return (m_id < m_end); } protected: - const CompressedStorage& m_data; + const CompressedStorage& m_data; Index m_id; const Index m_end; }; diff --git a/Eigen/src/Sparse/SuperLUSupport.h b/Eigen/src/Sparse/SuperLUSupport.h index 18a967539..d93f69df8 100644 --- a/Eigen/src/Sparse/SuperLUSupport.h +++ b/Eigen/src/Sparse/SuperLUSupport.h @@ -267,8 +267,8 @@ SluMatrix SparseMatrixBase::asSluMatrix() } /** View a Super LU matrix as an Eigen expression */ -template -MappedSparseMatrix::MappedSparseMatrix(SluMatrix& sluMat) +template +MappedSparseMatrix::MappedSparseMatrix(SluMatrix& sluMat) { if ((Flags&RowMajorBit)==RowMajorBit) { diff --git a/Eigen/src/Sparse/TaucsSupport.h b/Eigen/src/Sparse/TaucsSupport.h index 2a1963f5b..c189e0127 100644 --- a/Eigen/src/Sparse/TaucsSupport.h +++ b/Eigen/src/Sparse/TaucsSupport.h @@ -63,8 +63,8 @@ taucs_ccs_matrix SparseMatrixBase::asTaucsMatrix() return res; } -template -MappedSparseMatrix::MappedSparseMatrix(taucs_ccs_matrix& taucsMat) +template +MappedSparseMatrix::MappedSparseMatrix(taucs_ccs_matrix& taucsMat) { m_innerSize = taucsMat.m; m_outerSize = taucsMat.n; diff --git a/Eigen/src/Sparse/TriangularSolver.h b/Eigen/src/Sparse/TriangularSolver.h index 039424bf0..7528ba534 100644 --- a/Eigen/src/Sparse/TriangularSolver.h +++ b/Eigen/src/Sparse/TriangularSolver.h @@ -207,10 +207,12 @@ template struct ei_sparse_solve_triangular_sparse_selector { typedef typename Rhs::Scalar Scalar; + typedef typename ei_promote_index_type::Index, + typename ei_traits::Index>::type Index; static void run(const Lhs& lhs, Rhs& other) { const bool IsLower = (UpLo==Lower); - AmbiVector tempVector(other.rows()*2); + AmbiVector tempVector(other.rows()*2); tempVector.setBounds(0,other.rows()); Rhs res(other.rows(), other.cols()); @@ -266,7 +268,7 @@ struct ei_sparse_solve_triangular_sparse_selector int count = 0; // FIXME compute a reference value to filter zeros - for (typename AmbiVector::Iterator it(tempVector/*,1e-12*/); it; ++it) + for (typename AmbiVector::Iterator it(tempVector/*,1e-12*/); it; ++it) { ++ count; // std::cerr << "fill " << it.index() << ", " << col << "\n"; From d92de9574a2aec4af51ad04c0dc5cd2eb39e45bf Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Jun 2010 11:56:08 +0200 Subject: [PATCH 22/67] fix sparse LDLT with complexes --- Eigen/src/Sparse/SparseLDLT.h | 27 ++++++++++++++------------- Eigen/src/Sparse/SparseLLT.h | 9 +-------- test/sparse_solvers.cpp | 13 +++++++------ 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/Eigen/src/Sparse/SparseLDLT.h b/Eigen/src/Sparse/SparseLDLT.h index ae1a96b4f..a6785d0af 100644 --- a/Eigen/src/Sparse/SparseLDLT.h +++ b/Eigen/src/Sparse/SparseLDLT.h @@ -71,6 +71,8 @@ LDL License: * * \param MatrixType the type of the matrix of which we are computing the LDLT Cholesky decomposition * + * \warning the upper triangular part has to be specified. The rest of the matrix is not used. The input matrix must be column major. + * * \sa class LDLT, class LDLT */ template @@ -213,7 +215,7 @@ void SparseLDLT::_symbolic(const MatrixType& a) m_parent[k] = -1; /* parent of k is not yet known */ tags[k] = k; /* mark node k as visited */ m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ - Index kk = P ? P[k] : k; /* kth original, or permuted, column */ + Index kk = P ? P[k] : k; /* kth original, or permuted, column */ Index p2 = Ap[kk+1]; for (Index p = Ap[kk]; p < p2; ++p) { @@ -269,10 +271,10 @@ bool SparseLDLT::_numeric(const MatrixType& a) for (Index k = 0; k < size; ++k) { /* compute nonzero pattern of kth row of L, in topological order */ - y[k] = 0.0; /* Y(0:k) is now all zero */ + y[k] = 0.0; /* Y(0:k) is now all zero */ Index top = size; /* stack for pattern is empty */ - tags[k] = k; /* mark node k as visited */ - m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ + tags[k] = k; /* mark node k as visited */ + m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ Index kk = (P) ? (P[k]) : (k); /* kth original, or permuted, column */ Index p2 = Ap[kk+1]; for (Index p = Ap[kk]; p < p2; ++p) @@ -280,7 +282,7 @@ bool SparseLDLT::_numeric(const MatrixType& a) Index i = Pinv ? Pinv[Ai[p]] : Ai[p]; /* get A(i,k) */ if (i <= k) { - y[i] += Ax[p]; /* scatter A(i,k) into Y (sum duplicates) */ + y[i] += ei_conj(Ax[p]); /* scatter A(i,k) into Y (sum duplicates) */ Index len; for (len = 0; tags[i] != k; i = m_parent[i]) { @@ -291,22 +293,23 @@ bool SparseLDLT::_numeric(const MatrixType& a) pattern[--top] = pattern[--len]; } } + /* compute numerical values kth row of L (a sparse triangular solve) */ m_diag[k] = y[k]; /* get D(k,k) and clear Y(k) */ y[k] = 0.0; for (; top < size; ++top) { - Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ - Scalar yi = y[i]; /* get and clear Y(i) */ + Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ + Scalar yi = (y[i]); /* get and clear Y(i) */ y[i] = 0.0; Index p2 = Lp[i] + m_nonZerosPerCol[i]; Index p; for (p = Lp[i]; p < p2; ++p) - y[Li[p]] -= Lx[p] * yi; + y[Li[p]] -= ei_conj(Lx[p]) * (yi); Scalar l_ki = yi / m_diag[i]; /* the nonzero entry L(k,i) */ - m_diag[k] -= l_ki * yi; + m_diag[k] -= l_ki * ei_conj(yi); Li[p] = k; /* store L(k,i) in column form of L */ - Lx[p] = l_ki; + Lx[p] = (l_ki); ++m_nonZerosPerCol[i]; /* increment count of nonzeros in col i */ } if (m_diag[k] == 0.0) @@ -323,7 +326,7 @@ bool SparseLDLT::_numeric(const MatrixType& a) return ok; /* success, diagonal of D is all nonzero */ } -/** Computes b = L^-T L^-1 b */ +/** Computes b = L^-T D^-1 L^-1 b */ template template bool SparseLDLT::solveInPlace(MatrixBase &b) const @@ -336,8 +339,6 @@ bool SparseLDLT::solveInPlace(MatrixBase &b) const if (m_matrix.nonZeros()>0) // otherwise L==I m_matrix.template triangularView().solveInPlace(b); b = b.cwiseQuotient(m_diag); - // FIXME should be .adjoint() but it fails to compile... - if (m_matrix.nonZeros()>0) // otherwise L==I m_matrix.adjoint().template triangularView().solveInPlace(b); diff --git a/Eigen/src/Sparse/SparseLLT.h b/Eigen/src/Sparse/SparseLLT.h index 4ec3ee009..47d58f8e6 100644 --- a/Eigen/src/Sparse/SparseLLT.h +++ b/Eigen/src/Sparse/SparseLLT.h @@ -195,14 +195,7 @@ bool SparseLLT::solveInPlace(MatrixBase &b) const ei_assert(size==b.rows()); m_matrix.template triangularView().solveInPlace(b); - // FIXME should be simply .adjoint() but it fails to compile... - if (NumTraits::IsComplex) - { - CholMatrixType aux = m_matrix.conjugate(); - aux.transpose().template triangularView().solveInPlace(b); - } - else - m_matrix.transpose().template triangularView().solveInPlace(b); + m_matrix.adjoint().template triangularView().solveInPlace(b); return true; } diff --git a/test/sparse_solvers.cpp b/test/sparse_solvers.cpp index 00df1bffd..ea8aee718 100644 --- a/test/sparse_solvers.cpp +++ b/test/sparse_solvers.cpp @@ -149,26 +149,27 @@ template void sparse_solvers(int rows, int cols) } // test LDLT - if (!NumTraits::IsComplex) { - // TODO fix the issue with complex (see SparseLDLT::solveInPlace) SparseMatrix m2(rows, cols); DenseMatrix refMat2(rows, cols); DenseVector b = DenseVector::Random(cols); DenseVector refX(cols), x(cols); -// initSPD(density, refMat2, m2); initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0); - refMat2 += (refMat2.adjoint()).eval(); - refMat2.diagonal() *= 0.5; + for(int i=0; i().llt().solve(b); + // FIXME use LLT to compute the reference because LDLT seems to fail with large matrices typedef SparseMatrix SparseSelfAdjointMatrix; x = b; SparseLDLT ldlt(m2); if (ldlt.succeeded()) ldlt.solveInPlace(x); + else + std::cerr << "warning LDLT failed\n"; + VERIFY(refX.isApprox(x,test_precision()) && "LDLT: default"); } From 4159db979d8a502d628f3ec7fd6f49ded84165d4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Jun 2010 21:33:47 +0200 Subject: [PATCH 23/67] make LDLT uses only the lower triangular part --- Eigen/src/Cholesky/LDLT.h | 65 ++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index a433f8d0f..81f3aaa32 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -31,7 +31,7 @@ * * \class LDLT * - * \brief Robust Cholesky decomposition of a matrix + * \brief Robust Cholesky decomposition of a matrix with pivoting * * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition * @@ -43,7 +43,7 @@ * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root * on D also stabilizes the computation. * - * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky + * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * * \sa MatrixBase::ldlt(), class LLT @@ -82,11 +82,13 @@ template class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) : m_matrix(size, size), - m_p(size), - m_transpositions(size), - m_temporary(size), - m_isInitialized(false) {} + LDLT(Index size) + : m_matrix(size, size), + m_p(size), + m_transpositions(size), + m_temporary(size), + m_isInitialized(false) + {} LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), @@ -98,7 +100,7 @@ template class LDLT compute(matrix); } - /** \returns the lower triangular matrix L */ + /** \returns an expression of the lower triangular matrix L */ inline TriangularView matrixL(void) const { ei_assert(m_isInitialized && "LDLT is not initialized."); @@ -157,7 +159,7 @@ template class LDLT LDLT& compute(const MatrixType& matrix); - /** \returns the LDLT decomposition matrix + /** \returns the internal LDLT decomposition matrix * * TODO: document the storage layout */ @@ -173,6 +175,7 @@ template class LDLT inline Index cols() const { return m_matrix.cols(); } protected: + /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. * The strict upper part is used during the decomposition, the strict lower @@ -201,7 +204,8 @@ LDLT& LDLT::compute(const MatrixType& a) m_transpositions.resize(size); m_isInitialized = false; - if (size <= 1) { + if (size <= 1) + { m_p.setZero(); m_transpositions.setZero(); m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1; @@ -211,17 +215,16 @@ LDLT& LDLT::compute(const MatrixType& a) RealScalar cutoff = 0, biggest_in_corner; - // By using a temorary, packet-aligned products are guarenteed. In the LLT + // By using a temporary, packet-aligned products are guarenteed. In the LLT // case this is unnecessary because the diagonal is included and will always // have optimal alignment. m_temporary.resize(size); - for (Index j = 0; j < size; ++j) { + // Find largest diagonal element Index index_of_biggest_in_corner; - biggest_in_corner = m_matrix.diagonal().tail(size-j).cwiseAbs() - .maxCoeff(&index_of_biggest_in_corner); + biggest_in_corner = m_matrix.diagonal().tail(size-j).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += j; if(j == 0) @@ -248,28 +251,20 @@ LDLT& LDLT::compute(const MatrixType& a) m_matrix.col(j).swap(m_matrix.col(index_of_biggest_in_corner)); } - if (j == 0) { - m_matrix.row(0) = m_matrix.row(0).conjugate(); - m_matrix.col(0).tail(size-1) = m_matrix.row(0).tail(size-1) / m_matrix.coeff(0,0); - continue; - } - - RealScalar Djj = ei_real(m_matrix.coeff(j,j) - m_matrix.row(j).head(j).dot(m_matrix.col(j).head(j))); - m_matrix.coeffRef(j,j) = Djj; - - Index endSize = size - j - 1; - if (endSize > 0) { - m_temporary.tail(endSize).noalias() = m_matrix.block(j+1,0, endSize, j) - * m_matrix.col(j).head(j).conjugate(); - - m_matrix.row(j).tail(endSize) = m_matrix.row(j).tail(endSize).conjugate() - - m_temporary.tail(endSize).transpose(); - - if(ei_abs(Djj) > cutoff) - { - m_matrix.col(j).tail(endSize) = m_matrix.row(j).tail(endSize) / Djj; - } + Index rs = size - j - 1; + Block A21(m_matrix,j+1,j,rs,1); + Block A10(m_matrix,j,0,1,j); + Block A20(m_matrix,j+1,0,rs,j); + + if(j>0) + { + m_temporary.head(j) = m_matrix.diagonal().head(j).asDiagonal() * A10.adjoint(); + m_matrix.coeffRef(j,j) -= (A10 * m_temporary.head(j)).value(); + if(rs>0) + A21.noalias() -= A20 * m_temporary.head(j); } + if((rs>0) && (ei_abs(m_matrix.coeffRef(j,j)) > cutoff)) + A21 /= m_matrix.coeffRef(j,j); } // Reverse applied swaps to get P matrix. From e64460d5d003448e090bac23b9ddc93e7af2ca5a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Jun 2010 22:22:14 +0200 Subject: [PATCH 24/67] LDLT: make it honors the Lower/Upper directive and make it works inplace --- Eigen/src/Cholesky/LDLT.h | 227 ++++++++++++++-------- Eigen/src/Cholesky/LLT.h | 1 - Eigen/src/Core/SelfAdjointView.h | 2 +- Eigen/src/Core/util/ForwardDeclarations.h | 2 +- test/cholesky.cpp | 15 +- 5 files changed, 160 insertions(+), 87 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 81f3aaa32..60cb98307 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -27,6 +27,8 @@ #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H +template struct LDLT_Traits; + /** \ingroup cholesky_Module * * \class LDLT @@ -52,7 +54,7 @@ * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ -template class LDLT +template class LDLT { public: typedef _MatrixType MatrixType; @@ -61,7 +63,8 @@ template class LDLT ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -69,6 +72,8 @@ template class LDLT typedef typename ei_plain_col_type::type IntColVectorType; typedef Matrix TmpMatrixType; + typedef LDLT_Traits Traits; + /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to @@ -100,11 +105,18 @@ template class LDLT compute(matrix); } - /** \returns an expression of the lower triangular matrix L */ - inline TriangularView matrixL(void) const + /** \returns a view of the upper triangular matrix U */ + inline typename Traits::MatrixU matrixU() const { ei_assert(m_isInitialized && "LDLT is not initialized."); - return m_matrix; + return Traits::getU(m_matrix); + } + + /** \returns a view of the lower triangular matrix L */ + inline typename Traits::MatrixL matrixL() const + { + ei_assert(m_isInitialized && "LDLT is not initialized."); + return Traits::getL(m_matrix); } /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, @@ -186,14 +198,115 @@ template class LDLT IntColVectorType m_p; IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions? TmpMatrixType m_temporary; - Index m_sign; + int m_sign; bool m_isInitialized; }; +template struct ei_ldlt_inplace; + +template<> struct ei_ldlt_inplace +{ + template + static bool unblocked(MatrixType& mat, Transpositions& transpositions, Workspace& temp, int* sign=0) + { + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + ei_assert(mat.rows()==mat.cols()); + const Index size = mat.rows(); + + if (size <= 1) + { + transpositions.setZero(); + if(sign) + *sign = ei_real(mat.coeff(0,0))>0 ? 1:-1; + return true; + } + + RealScalar cutoff = 0, biggest_in_corner; + + for (Index k = 0; k < size; ++k) + { + // Find largest diagonal element + Index index_of_biggest_in_corner; + biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + index_of_biggest_in_corner += k; + + if(k == 0) + { + // The biggest overall is the point of reference to which further diagonals + // are compared; if any diagonal is negligible compared + // to the largest overall, the algorithm bails. + cutoff = ei_abs(NumTraits::epsilon() * biggest_in_corner); + + if(sign) + *sign = ei_real(mat.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; + } + + // Finish early if the matrix is not full rank. + if(biggest_in_corner < cutoff) + { + for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i; + break; + } + + transpositions.coeffRef(k) = index_of_biggest_in_corner; + if(k != index_of_biggest_in_corner) + { + mat.row(k).swap(mat.row(index_of_biggest_in_corner)); + mat.col(k).swap(mat.col(index_of_biggest_in_corner)); + } + + Index rs = size - k - 1; + Block A21(mat,k+1,k,rs,1); + Block A10(mat,k,0,1,k); + Block A20(mat,k+1,0,rs,k); + + if(k>0) + { + temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint(); + mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); + if(rs>0) + A21.noalias() -= A20 * temp.head(k); + } + if((rs>0) && (ei_abs(mat.coeffRef(k,k)) > cutoff)) + A21 /= mat.coeffRef(k,k); + } + + return true; + } +}; + +template<> struct ei_ldlt_inplace +{ + template + static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, Transpositions& transpositions, Workspace& temp, int* sign=0) + { + Transpose matt(mat); + return ei_ldlt_inplace::unblocked(matt, transpositions, temp, sign); + } +}; + +template struct LDLT_Traits +{ + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; + inline static MatrixL getL(const MatrixType& m) { return m; } + inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } +}; + +template struct LDLT_Traits +{ + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; + inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } + inline static MatrixU getU(const MatrixType& m) { return m; } +}; + /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ -template -LDLT& LDLT::compute(const MatrixType& a) +template +LDLT& LDLT::compute(const MatrixType& a) { ei_assert(a.rows()==a.cols()); const Index size = a.rows(); @@ -203,85 +316,29 @@ LDLT& LDLT::compute(const MatrixType& a) m_p.resize(size); m_transpositions.resize(size); m_isInitialized = false; - - if (size <= 1) - { - m_p.setZero(); - m_transpositions.setZero(); - m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1; - m_isInitialized = true; - return *this; - } - - RealScalar cutoff = 0, biggest_in_corner; - - // By using a temporary, packet-aligned products are guarenteed. In the LLT - // case this is unnecessary because the diagonal is included and will always - // have optimal alignment. m_temporary.resize(size); - for (Index j = 0; j < size; ++j) - { - // Find largest diagonal element - Index index_of_biggest_in_corner; - biggest_in_corner = m_matrix.diagonal().tail(size-j).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); - index_of_biggest_in_corner += j; + ei_ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign); - if(j == 0) - { - // The biggest overall is the point of reference to which further diagonals - // are compared; if any diagonal is negligible compared - // to the largest overall, the algorithm bails. - cutoff = ei_abs(NumTraits::epsilon() * biggest_in_corner); - - m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; - } - - // Finish early if the matrix is not full rank. - if(biggest_in_corner < cutoff) - { - for(Index i = j; i < size; i++) m_transpositions.coeffRef(i) = i; - break; - } - - m_transpositions.coeffRef(j) = index_of_biggest_in_corner; - if(j != index_of_biggest_in_corner) - { - m_matrix.row(j).swap(m_matrix.row(index_of_biggest_in_corner)); - m_matrix.col(j).swap(m_matrix.col(index_of_biggest_in_corner)); - } - - Index rs = size - j - 1; - Block A21(m_matrix,j+1,j,rs,1); - Block A10(m_matrix,j,0,1,j); - Block A20(m_matrix,j+1,0,rs,j); - - if(j>0) - { - m_temporary.head(j) = m_matrix.diagonal().head(j).asDiagonal() * A10.adjoint(); - m_matrix.coeffRef(j,j) -= (A10 * m_temporary.head(j)).value(); - if(rs>0) - A21.noalias() -= A20 * m_temporary.head(j); - } - if((rs>0) && (ei_abs(m_matrix.coeffRef(j,j)) > cutoff)) - A21 /= m_matrix.coeffRef(j,j); - } + if(size==0) + m_p.setZero(); // Reverse applied swaps to get P matrix. for(Index k = 0; k < size; ++k) m_p.coeffRef(k) = k; for(Index k = size-1; k >= 0; --k) { std::swap(m_p.coeffRef(k), m_p.coeffRef(m_transpositions.coeff(k))); } - + m_isInitialized = true; return *this; } -template -struct ei_solve_retval, Rhs> - : ei_solve_retval_base, Rhs> +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - EIGEN_MAKE_SOLVE_HELPERS(LDLT<_MatrixType>,Rhs) + typedef LDLT<_MatrixType,_UpLo> LDLTType; + EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) template void evalTo(Dest& dst) const { @@ -301,9 +358,9 @@ struct ei_solve_retval, Rhs> * * \sa LDLT::solve(), MatrixBase::ldlt() */ -template +template template -bool LDLT::solveInPlace(MatrixBase &bAndX) const +bool LDLT::solveInPlace(MatrixBase &bAndX) const { ei_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); @@ -314,13 +371,13 @@ bool LDLT::solveInPlace(MatrixBase &bAndX) const // y = L^-1 z //matrixL().solveInPlace(bAndX); - m_matrix.template triangularView().solveInPlace(bAndX); + matrixL().solveInPlace(bAndX); // w = D^-1 y bAndX = m_matrix.diagonal().asDiagonal().inverse() * bAndX; // u = L^-T w - m_matrix.adjoint().template triangularView().solveInPlace(bAndX); + matrixU().solveInPlace(bAndX); // x = P^T u for (Index i = size-1; i >= 0; --i) bAndX.row(m_transpositions.coeff(i)).swap(bAndX.row(i)); @@ -331,8 +388,8 @@ bool LDLT::solveInPlace(MatrixBase &bAndX) const /** \returns the matrix represented by the decomposition, * i.e., it returns the product: P^T L D L^* P. * This function is provided for debug purpose. */ -template -MatrixType LDLT::reconstructedMatrix() const +template +MatrixType LDLT::reconstructedMatrix() const { ei_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); @@ -342,7 +399,7 @@ MatrixType LDLT::reconstructedMatrix() const // PI for(Index i = 0; i < size; ++i) res.row(m_transpositions.coeff(i)).swap(res.row(i)); // L^* P - res = matrixL().adjoint() * res; + res = matrixU() * res; // D(L^*P) res = vectorD().asDiagonal() * res; // L(DL^*P) @@ -353,6 +410,16 @@ MatrixType LDLT::reconstructedMatrix() const return res; } +/** \cholesky_module + * \returns the Cholesky decomposition with full pivoting without square root of \c *this + */ +template +inline const LDLT::PlainObject, UpLo> +SelfAdjointView::ldlt() const +{ + return LDLT(m_matrix); +} + /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this */ diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 29fa465e1..6e853436c 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -162,7 +162,6 @@ template class LLT bool m_isInitialized; }; -// forward declaration (defined at the end of this file) template struct ei_llt_inplace; template<> struct ei_llt_inplace diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index eed3f9336..84c4dc521 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -153,7 +153,7 @@ template class SelfAdjointView /////////// Cholesky module /////////// const LLT llt() const; - const LDLT ldlt() const; + const LDLT ldlt() const; /////////// Eigenvalue module /////////// diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index b3bc9c161..5cf62f4c6 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -158,7 +158,7 @@ template class FullPivHouseholderQR; template class SVD; template class JacobiSVD; template class LLT; -template class LDLT; +template class LDLT; template class HouseholderSequence; template class PlanarRotation; diff --git a/test/cholesky.cpp b/test/cholesky.cpp index 0ae26c7d5..d403af7ba 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -118,11 +118,18 @@ template void cholesky(const MatrixType& m) } { - LDLT ldlt(symm); - VERIFY_IS_APPROX(symm, ldlt.reconstructedMatrix()); - vecX = ldlt.solve(vecB); + LDLT ldltlo(symm); + VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); + vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); - matX = ldlt.solve(matB); + matX = ldltlo.solve(matB); + VERIFY_IS_APPROX(symm * matX, matB); + + LDLT ldltup(symm); + VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); + vecX = ldltup.solve(vecB); + VERIFY_IS_APPROX(symm * vecX, vecB); + matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); } From ed73a195e0a6b840993e31f0d8f5082296feb6bc Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 3 Jun 2010 22:29:11 +0100 Subject: [PATCH 25/67] Refactor compute() by splitting off two smaller private methods. --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 91 ++++++++++++---------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index bc44b899a..a344c2d3c 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -227,6 +227,10 @@ template class ComplexEigenSolver bool m_isInitialized; bool m_eigenvectorsOk; EigenvectorType m_matX; + + private: + void doComputeEigenvectors(RealScalar matrixnorm); + void sortEigenvalues(bool computeEigenvectors); }; @@ -235,52 +239,64 @@ ComplexEigenSolver& ComplexEigenSolver::compute(const Ma { // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); - const Index n = matrix.cols(); - const RealScalar matrixnorm = matrix.norm(); - // Step 1: Do a complex Schur decomposition, A = U T U^* + // Do a complex Schur decomposition, A = U T U^* // The eigenvalues are on the diagonal of T. m_schur.compute(matrix, computeEigenvectors); m_eivalues = m_schur.matrixT().diagonal(); if(computeEigenvectors) - { - // Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T. - // The matrix X is unit triangular. - m_matX = EigenvectorType::Zero(n, n); - for(Index k=n-1 ; k>=0 ; k--) - { - m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0); - // Compute X(i,k) using the (i,k) entry of the equation X T = D X - for(Index i=k-1 ; i>=0 ; i--) - { - m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k); - if(k-i-1>0) - m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value(); - ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k); - if(z==ComplexScalar(0)) - { - // If the i-th and k-th eigenvalue are equal, then z equals 0. - // Use a small value instead, to prevent division by zero. - ei_real_ref(z) = NumTraits::epsilon() * matrixnorm; - } - m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z; - } - } - - // 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.noalias() = m_schur.matrixU() * m_matX; - // .. and normalize the eigenvectors - for(Index k=0 ; k +void ComplexEigenSolver::doComputeEigenvectors(RealScalar matrixnorm) +{ + const Index n = m_eivalues.size(); + + // Compute X such that T = X D X^(-1), where D is the diagonal of T. + // The matrix X is unit triangular. + m_matX = EigenvectorType::Zero(n, n); + for(Index k=n-1 ; k>=0 ; k--) + { + m_matX.coeffRef(k,k) = ComplexScalar(1.0,0.0); + // Compute X(i,k) using the (i,k) entry of the equation X T = D X + for(Index i=k-1 ; i>=0 ; i--) + { + m_matX.coeffRef(i,k) = -m_schur.matrixT().coeff(i,k); + if(k-i-1>0) + m_matX.coeffRef(i,k) -= (m_schur.matrixT().row(i).segment(i+1,k-i-1) * m_matX.col(k).segment(i+1,k-i-1)).value(); + ComplexScalar z = m_schur.matrixT().coeff(i,i) - m_schur.matrixT().coeff(k,k); + if(z==ComplexScalar(0)) + { + // If the i-th and k-th eigenvalue are equal, then z equals 0. + // Use a small value instead, to prevent division by zero. + ei_real_ref(z) = NumTraits::epsilon() * matrixnorm; + } + m_matX.coeffRef(i,k) = m_matX.coeff(i,k) / z; + } + } + + // Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1) + m_eivec.noalias() = m_schur.matrixU() * m_matX; + // .. and normalize the eigenvectors + for(Index k=0 ; k +void ComplexEigenSolver::sortEigenvalues(bool computeEigenvectors) +{ + const Index n = m_eivalues.size(); for (Index i=0; i& ComplexEigenSolver::compute(const Ma m_eivec.col(i).swap(m_eivec.col(k)); } } - - return *this; } - #endif // EIGEN_COMPLEX_EIGEN_SOLVER_H From 9178e2bd54f64febb43025b9710387d2e98fea34 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 3 Jun 2010 22:59:57 +0100 Subject: [PATCH 26/67] Add info() method which can be queried to check whether iteration converged. --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 24 ++++++-- Eigen/src/Eigenvalues/ComplexSchur.h | 27 ++++++--- Eigen/src/Eigenvalues/EigenSolver.h | 60 +++++++++++-------- Eigen/src/Eigenvalues/EigenvaluesCommon.h | 39 ++++++++++++ Eigen/src/Eigenvalues/RealSchur.h | 27 ++++++--- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 42 +++++++++---- test/eigensolver_complex.cpp | 12 ++++ test/eigensolver_generic.cpp | 14 ++++- test/eigensolver_selfadjoint.cpp | 14 +++++ test/schur_complex.cpp | 11 ++++ test/schur_real.cpp | 11 ++++ 11 files changed, 224 insertions(+), 57 deletions(-) create mode 100644 Eigen/src/Eigenvalues/EigenvaluesCommon.h diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index a344c2d3c..a164aaae6 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -27,6 +27,9 @@ #ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H #define EIGEN_COMPLEX_EIGEN_SOLVER_H +#include "./EigenvaluesCommon.h" +#include "./ComplexSchur.h" + /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * @@ -220,6 +223,16 @@ template class ComplexEigenSolver */ ComplexEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_schur.info(); + } + protected: EigenvectorType m_eivec; EigenvalueType m_eivalues; @@ -243,11 +256,14 @@ ComplexEigenSolver& ComplexEigenSolver::compute(const Ma // Do a complex Schur decomposition, A = U T U^* // The eigenvalues are on the diagonal of T. m_schur.compute(matrix, computeEigenvectors); - m_eivalues = m_schur.matrixT().diagonal(); - if(computeEigenvectors) - doComputeEigenvectors(matrix.norm()); - sortEigenvalues(computeEigenvectors); + if(m_schur.info() == Success) + { + m_eivalues = m_schur.matrixT().diagonal(); + if(computeEigenvectors) + doComputeEigenvectors(matrix.norm()); + sortEigenvalues(computeEigenvectors); + } m_isInitialized = true; m_eigenvectorsOk = computeEigenvectors; diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index cf6755bfc..6a8daebb8 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -27,6 +27,9 @@ #ifndef EIGEN_COMPLEX_SCHUR_H #define EIGEN_COMPLEX_SCHUR_H +#include "./EigenvaluesCommon.h" +#include "./HessenbergDecomposition.h" + template struct ei_complex_schur_reduce_to_hessenberg; /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -192,6 +195,16 @@ template class ComplexSchur */ ComplexSchur& compute(const MatrixType& matrix, bool computeU = true); + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "RealSchur is not initialized."); + return m_info; + } + /** \brief Maximum number of iterations. * * Maximum number of iterations allowed for an eigenvalue to converge. @@ -201,6 +214,7 @@ template class ComplexSchur protected: ComplexMatrixType m_matT, m_matU; HessenbergDecomposition m_hess; + ComputationInfo m_info; bool m_isInitialized; bool m_matUisUptodate; @@ -312,6 +326,7 @@ ComplexSchur& ComplexSchur::compute(const MatrixType& ma { m_matT = matrix.template cast(); if(computeU) m_matU = ComplexMatrixType::Identity(1,1); + m_info = Success; m_isInitialized = true; m_matUisUptodate = computeU; return *this; @@ -382,7 +397,7 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) // if we spent too many iterations on the current element, we give up iter++; - if(iter >= m_maxIterations) break; + if(iter > m_maxIterations) break; // find il, the top row of the active submatrix il = iu-1; @@ -412,12 +427,10 @@ void ComplexSchur::reduceToTriangularForm(bool computeU) } } - if(iter >= m_maxIterations) - { - // FIXME : what to do when iter==MAXITER ?? - // std::cerr << "MAXITER" << std::endl; - return; - } + if(iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; m_isInitialized = true; m_matUisUptodate = computeU; diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index f745413a8..04caee658 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -26,6 +26,7 @@ #ifndef EIGEN_EIGENSOLVER_H #define EIGEN_EIGENSOLVER_H +#include "./EigenvaluesCommon.h" #include "./RealSchur.h" /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -286,6 +287,12 @@ template class EigenSolver */ EigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); + ComputationInfo info() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_realSchur.info(); + } + private: void doComputeEigenvectors(); @@ -358,33 +365,36 @@ EigenSolver& EigenSolver::compute(const MatrixType& matr // Reduce to real Schur form. m_realSchur.compute(matrix, computeEigenvectors); - m_matT = m_realSchur.matrixT(); - if (computeEigenvectors) - m_eivec = m_realSchur.matrixU(); - - // Compute eigenvalues from matT - m_eivalues.resize(matrix.cols()); - Index i = 0; - while (i < matrix.cols()) + if (m_realSchur.info() == Success) { - if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0)) - { - m_eivalues.coeffRef(i) = m_matT.coeff(i, i); - ++i; - } - else - { - Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1)); - Scalar z = ei_sqrt(ei_abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1))); - m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z); - m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z); - i += 2; - } - } + m_matT = m_realSchur.matrixT(); + if (computeEigenvectors) + m_eivec = m_realSchur.matrixU(); - // Compute eigenvectors. - if (computeEigenvectors) - doComputeEigenvectors(); + // Compute eigenvalues from matT + m_eivalues.resize(matrix.cols()); + Index i = 0; + while (i < matrix.cols()) + { + if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0)) + { + m_eivalues.coeffRef(i) = m_matT.coeff(i, i); + ++i; + } + else + { + Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1)); + Scalar z = ei_sqrt(ei_abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1))); + m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z); + m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z); + i += 2; + } + } + + // Compute eigenvectors. + if (computeEigenvectors) + doComputeEigenvectors(); + } m_isInitialized = true; m_eigenvectorsOk = computeEigenvectors; diff --git a/Eigen/src/Eigenvalues/EigenvaluesCommon.h b/Eigen/src/Eigenvalues/EigenvaluesCommon.h new file mode 100644 index 000000000..d5fff9ba1 --- /dev/null +++ b/Eigen/src/Eigenvalues/EigenvaluesCommon.h @@ -0,0 +1,39 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Jitse Niesen +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_EIGENVALUES_COMMON_H +#define EIGEN_EIGENVALUES_COMMON_H + +/** \eigenvalues_module \ingroup Eigenvalues_Module + * \nonstableyet + * + * \brief Enum for reporting the status of a computation. + */ +enum ComputationInfo { + Success = 0, /**< \brief Computation was successful. */ + NoConvergence = 1 /**< \brief Iterative procedure did not converge. */ +}; + +#endif // EIGEN_EIGENVALUES_COMMON_H + diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index 584b1d05e..156706573 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -26,6 +26,7 @@ #ifndef EIGEN_REAL_SCHUR_H #define EIGEN_REAL_SCHUR_H +#include "./EigenvaluesCommon.h" #include "./HessenbergDecomposition.h" /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -176,6 +177,16 @@ template class RealSchur */ RealSchur& compute(const MatrixType& matrix, bool computeU = true); + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "RealSchur is not initialized."); + return m_info; + } + /** \brief Maximum number of iterations. * * Maximum number of iterations allowed for an eigenvalue to converge. @@ -188,6 +199,7 @@ template class RealSchur MatrixType m_matU; ColumnVectorType m_workspaceVector; HessenbergDecomposition m_hess; + ComputationInfo m_info; bool m_isInitialized; bool m_matUisUptodate; @@ -249,20 +261,21 @@ RealSchur& RealSchur::compute(const MatrixType& matrix, { Vector3s firstHouseholderVector, shiftInfo; computeShift(iu, iter, exshift, shiftInfo); - iter = iter + 1; // (Could check iteration count here.) - if (iter >= m_maxIterations) break; + iter = iter + 1; + if (iter > m_maxIterations) break; Index im; initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); } } - if(iter < m_maxIterations) - { - m_isInitialized = true; - m_matUisUptodate = computeU; - } + if(iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; + m_isInitialized = true; + m_matUisUptodate = computeU; return *this; } diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index b08bbd7e2..6a7d46b39 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -26,6 +26,9 @@ #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H #define EIGEN_SELFADJOINTEIGENSOLVER_H +#include "./EigenvaluesCommon.h" +#include "./Tridiagonalization.h" + /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * @@ -360,6 +363,16 @@ template class SelfAdjointEigenSolver return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + return m_info; + } + /** \brief Maximum number of iterations. * * Maximum number of iterations allowed for an eigenvalue to converge. @@ -371,6 +384,7 @@ template class SelfAdjointEigenSolver RealVectorType m_eivalues; TridiagonalizationType m_tridiag; typename TridiagonalizationType::SubDiagonalType m_subdiag; + ComputationInfo m_info; bool m_isInitialized; bool m_eigenvectorsOk; }; @@ -410,6 +424,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0)); if(computeEigenvectors) m_eivec.setOnes(); + m_info = Success; m_isInitialized = true; m_eigenvectorsOk = computeEigenvectors; return *this; @@ -443,7 +458,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( // if we spent too many iterations on the current element, we give up iter++; - if(iter >= m_maxIterations) break; + if(iter > m_maxIterations) break; start = end - 1; while (start>0 && m_subdiag[start-1]!=0) @@ -452,23 +467,26 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( ei_tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); } - if(iter >= m_maxIterations) - { - return *this; - } + if (iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; // Sort eigenvalues and corresponding vectors. // TODO make the sort optional ? // TODO use a better sort algorithm !! - for (Index i = 0; i < n-1; ++i) + if (m_info == Success) { - Index k; - m_eivalues.segment(i,n-i).minCoeff(&k); - if (k > 0) + for (Index i = 0; i < n-1; ++i) { - std::swap(m_eivalues[i], m_eivalues[k+i]); - if(computeEigenvectors) - m_eivec.col(i).swap(m_eivec.col(k+i)); + Index k; + m_eivalues.segment(i,n-i).minCoeff(&k); + if (k > 0) + { + std::swap(m_eivalues[i], m_eivalues[k+i]); + if(computeEigenvectors) + m_eivec.col(i).swap(m_eivec.col(k+i)); + } } } diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 3285d26c2..dc3b2cfb0 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -24,6 +24,7 @@ // Eigen. If not, see . #include "main.h" +#include #include #include @@ -60,15 +61,18 @@ template void eigensolver(const MatrixType& m) MatrixType symmA = a.adjoint() * a; ComplexEigenSolver ei0(symmA); + VERIFY_IS_EQUAL(ei0.info(), Success); VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal()); ComplexEigenSolver ei1(a); + VERIFY_IS_EQUAL(ei1.info(), Success); VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus // another algorithm so results may differ slightly verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues()); ComplexEigenSolver eiNoEivecs(a, false); + VERIFY_IS_EQUAL(eiNoEivecs.info(), Success); VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); // Regression test for issue #66 @@ -78,6 +82,14 @@ template void eigensolver(const MatrixType& m) MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); + + if (rows > 1) + { + // Test matrix with NaN + a(0,0) = std::numeric_limits::quiet_NaN(); + ComplexEigenSolver eiNaN(a); + VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); + } } template void eigensolver_verify_assert(const MatrixType& m) diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index 79c08ec31..92741a35c 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -24,6 +24,7 @@ // Eigen. If not, see . #include "main.h" +#include #include #ifdef HAS_GSL @@ -44,29 +45,38 @@ template void eigensolver(const MatrixType& m) typedef Matrix RealVectorType; typedef typename std::complex::Real> Complex; - // RealScalar largerEps = 10*test_precision(); - MatrixType a = MatrixType::Random(rows,cols); MatrixType a1 = MatrixType::Random(rows,cols); MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; EigenSolver ei0(symmA); + VERIFY_IS_EQUAL(ei0.info(), Success); VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix()); VERIFY_IS_APPROX((symmA.template cast()) * (ei0.pseudoEigenvectors().template cast()), (ei0.pseudoEigenvectors().template cast()) * (ei0.eigenvalues().asDiagonal())); EigenSolver ei1(a); + VERIFY_IS_EQUAL(ei1.info(), Success); VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix()); VERIFY_IS_APPROX(a.template cast() * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); VERIFY_IS_APPROX(a.eigenvalues(), ei1.eigenvalues()); EigenSolver eiNoEivecs(a, false); + VERIFY_IS_EQUAL(eiNoEivecs.info(), Success); VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix()); MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); + + if (rows > 2) + { + // Test matrix with NaN + a(0,0) = std::numeric_limits::quiet_NaN(); + EigenSolver eiNaN(a); + VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); + } } template void eigensolver_verify_assert(const MatrixType& m) diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 3ff84c4e0..9f0c4cf38 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2010 Jitse Niesen // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ // Eigen. If not, see . #include "main.h" +#include #include #ifdef HAS_GSL @@ -101,14 +103,17 @@ template void selfadjointeigensolver(const MatrixType& m) } #endif + VERIFY_IS_EQUAL(eiSymm.info(), Success); VERIFY((symmA * eiSymm.eigenvectors()).isApprox( eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); VERIFY_IS_APPROX(symmA.template selfadjointView().eigenvalues(), eiSymm.eigenvalues()); SelfAdjointEigenSolver eiSymmNoEivecs(symmA, false); + VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success); VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues()); // generalized eigen problem Ax = lBx + VERIFY_IS_EQUAL(eiSymmGen.info(), Success); VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); @@ -120,6 +125,7 @@ template void selfadjointeigensolver(const MatrixType& m) VERIFY_IS_APPROX(id.template selfadjointView().operatorNorm(), RealScalar(1)); SelfAdjointEigenSolver eiSymmUninitialized; + VERIFY_RAISES_ASSERT(eiSymmUninitialized.info()); VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues()); VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); @@ -129,6 +135,14 @@ template void selfadjointeigensolver(const MatrixType& m) VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt()); + + if (rows > 1) + { + // Test matrix with NaN + symmA(0,0) = std::numeric_limits::quiet_NaN(); + SelfAdjointEigenSolver eiSymmNaN(symmA); + VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence); + } } void test_eigensolver_selfadjoint() diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp index cc8174d00..67c41d41f 100644 --- a/test/schur_complex.cpp +++ b/test/schur_complex.cpp @@ -23,6 +23,7 @@ // Eigen. If not, see . #include "main.h" +#include #include template void schur(int size = MatrixType::ColsAtCompileTime) @@ -34,6 +35,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); ComplexSchur schurOfA(A); + VERIFY_IS_EQUAL(schurOfA.info(), Success); ComplexMatrixType U = schurOfA.matrixU(); ComplexMatrixType T = schurOfA.matrixT(); for(int row = 1; row < size; ++row) { @@ -48,19 +50,28 @@ template void schur(int size = MatrixType::ColsAtCompileTim ComplexSchur csUninitialized; VERIFY_RAISES_ASSERT(csUninitialized.matrixT()); VERIFY_RAISES_ASSERT(csUninitialized.matrixU()); + VERIFY_RAISES_ASSERT(csUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); ComplexSchur cs1; cs1.compute(A); ComplexSchur cs2(A); + VERIFY_IS_EQUAL(cs1.info(), Success); + VERIFY_IS_EQUAL(cs2.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT()); VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU()); // Test computation of only T, not U ComplexSchur csOnlyT(A, false); + VERIFY_IS_EQUAL(csOnlyT.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); + + // Test matrix with NaN + A(0,0) = std::numeric_limits::quiet_NaN(); + ComplexSchur csNaN(A); + VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); } void test_schur_complex() diff --git a/test/schur_real.cpp b/test/schur_real.cpp index 116c8dbce..1e8c4b0ba 100644 --- a/test/schur_real.cpp +++ b/test/schur_real.cpp @@ -23,6 +23,7 @@ // Eigen. If not, see . #include "main.h" +#include #include template void verifyIsQuasiTriangular(const MatrixType& T) @@ -55,6 +56,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); RealSchur schurOfA(A); + VERIFY_IS_EQUAL(schurOfA.info(), Success); MatrixType U = schurOfA.matrixU(); MatrixType T = schurOfA.matrixT(); verifyIsQuasiTriangular(T); @@ -65,19 +67,28 @@ template void schur(int size = MatrixType::ColsAtCompileTim RealSchur rsUninitialized; VERIFY_RAISES_ASSERT(rsUninitialized.matrixT()); VERIFY_RAISES_ASSERT(rsUninitialized.matrixU()); + VERIFY_RAISES_ASSERT(rsUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); RealSchur rs1; rs1.compute(A); RealSchur rs2(A); + VERIFY_IS_EQUAL(rs1.info(), Success); + VERIFY_IS_EQUAL(rs2.info(), Success); VERIFY_IS_EQUAL(rs1.matrixT(), rs2.matrixT()); VERIFY_IS_EQUAL(rs1.matrixU(), rs2.matrixU()); // Test computation of only T, not U RealSchur rsOnlyT(A, false); + VERIFY_IS_EQUAL(rsOnlyT.info(), Success); VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT()); VERIFY_RAISES_ASSERT(rsOnlyT.matrixU()); + + // Test matrix with NaN + A(0,0) = std::numeric_limits::quiet_NaN(); + RealSchur rsNaN(A); + VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence); } void test_schur_real() From 1ff1bd69acc8f2d50348a57855c8ec35521590bd Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Fri, 4 Jun 2010 09:40:35 +0100 Subject: [PATCH 27/67] Schur decomposition of 1-by-1 always converges. --- test/schur_complex.cpp | 11 +++++++---- test/schur_real.cpp | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp index 67c41d41f..7c4dcb21a 100644 --- a/test/schur_complex.cpp +++ b/test/schur_complex.cpp @@ -68,10 +68,13 @@ template void schur(int size = MatrixType::ColsAtCompileTim VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); - // Test matrix with NaN - A(0,0) = std::numeric_limits::quiet_NaN(); - ComplexSchur csNaN(A); - VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); + if (size > 1) + { + // Test matrix with NaN + A(0,0) = std::numeric_limits::quiet_NaN(); + ComplexSchur csNaN(A); + VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); + } } void test_schur_complex() diff --git a/test/schur_real.cpp b/test/schur_real.cpp index 1e8c4b0ba..2eae52956 100644 --- a/test/schur_real.cpp +++ b/test/schur_real.cpp @@ -85,10 +85,13 @@ template void schur(int size = MatrixType::ColsAtCompileTim VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT()); VERIFY_RAISES_ASSERT(rsOnlyT.matrixU()); - // Test matrix with NaN - A(0,0) = std::numeric_limits::quiet_NaN(); - RealSchur rsNaN(A); - VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence); + if (size > 1) + { + // Test matrix with NaN + A(0,0) = std::numeric_limits::quiet_NaN(); + RealSchur rsNaN(A); + VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence); + } } void test_schur_real() From bfeba41174638c1a19df74436a1572b6f8a6da33 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Jun 2010 23:17:57 +0200 Subject: [PATCH 28/67] Add a Transpositions class to ease the representation and manipulation of permutations as a sequence of transpositions. Make LDLT use it. --- Eigen/Core | 1 + Eigen/src/Cholesky/LDLT.h | 87 ++++----- Eigen/src/Core/PermutationMatrix.h | 1 + Eigen/src/Core/Transpositions.h | 285 +++++++++++++++++++++++++++++ test/cholesky.cpp | 27 +++ 5 files changed, 351 insertions(+), 50 deletions(-) create mode 100644 Eigen/src/Core/Transpositions.h diff --git a/Eigen/Core b/Eigen/Core index 595e1cb89..70c2c2207 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -260,6 +260,7 @@ using std::size_t; #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" #include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 60cb98307..79657f086 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2009 Keir Mierle // Copyright (C) 2009 Benoit Jacob // @@ -69,9 +69,12 @@ template class LDLT typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; - typedef typename ei_plain_col_type::type IntColVectorType; +// typedef typename ei_plain_col_type::type IntColVectorType; typedef Matrix TmpMatrixType; + typedef Transpositions TranspositionType; + typedef PermutationMatrix PermutationType; + typedef LDLT_Traits Traits; /** \brief Default Constructor. @@ -79,7 +82,7 @@ template class LDLT * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ - LDLT() : m_matrix(), m_p(), m_transpositions(), m_isInitialized(false) {} + LDLT() : m_matrix(), m_transpositions(), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * @@ -89,7 +92,6 @@ template class LDLT */ LDLT(Index size) : m_matrix(size, size), - m_p(size), m_transpositions(size), m_temporary(size), m_isInitialized(false) @@ -97,7 +99,6 @@ template class LDLT LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), - m_p(matrix.rows()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_isInitialized(false) @@ -119,14 +120,12 @@ template class LDLT return Traits::getL(m_matrix); } - /** \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 FullPivLU. + /** \returns the permutation matrix P as a transposition sequence. */ - inline const IntColVectorType& permutationP() const + inline const TranspositionType& transpositionsP() const { ei_assert(m_isInitialized && "LDLT is not initialized."); - return m_p; + return m_transpositions; } /** \returns the coefficients of the diagonal matrix D */ @@ -195,8 +194,7 @@ template class LDLT * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; - IntColVectorType m_p; - IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions? + TranspositionType m_transpositions; TmpMatrixType m_temporary; int m_sign; bool m_isInitialized; @@ -206,18 +204,18 @@ template struct ei_ldlt_inplace; template<> struct ei_ldlt_inplace { - template - static bool unblocked(MatrixType& mat, Transpositions& transpositions, Workspace& temp, int* sign=0) + template + static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) { typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef typename MatrixType::Index Index; ei_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); - + if (size <= 1) { - transpositions.setZero(); + transpositions.setIdentity(); if(sign) *sign = ei_real(mat.coeff(0,0))>0 ? 1:-1; return true; @@ -272,15 +270,15 @@ template<> struct ei_ldlt_inplace if((rs>0) && (ei_abs(mat.coeffRef(k,k)) > cutoff)) A21 /= mat.coeffRef(k,k); } - + return true; } }; template<> struct ei_ldlt_inplace { - template - static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, Transpositions& transpositions, Workspace& temp, int* sign=0) + template + static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) { Transpose matt(mat); return ei_ldlt_inplace::unblocked(matt, transpositions, temp, sign); @@ -313,22 +311,12 @@ LDLT& LDLT::compute(const MatrixType& a) m_matrix = a; - m_p.resize(size); m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); ei_ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign); - if(size==0) - m_p.setZero(); - - // Reverse applied swaps to get P matrix. - for(Index k = 0; k < size; ++k) m_p.coeffRef(k) = k; - for(Index k = size-1; k >= 0; --k) { - std::swap(m_p.coeffRef(k), m_p.coeffRef(m_transpositions.coeff(k))); - } - m_isInitialized = true; return *this; } @@ -342,8 +330,21 @@ struct ei_solve_retval, Rhs> template void evalTo(Dest& dst) const { - dst = rhs(); - dec().solveInPlace(dst); + ei_assert(rhs().rows() == dec().matrixLDLT().rows()); + // dst = P b + dst = dec().transpositionsP() * rhs(); + + // dst = L^-1 (P b) + dec().matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + dst = dec().vectorD().asDiagonal().inverse() * dst; + + // dst = L^-T (D^-1 L^-1 P b) + dec().matrixU().solveInPlace(dst); + + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = dec().transpositionsP().transpose() * dst; } }; @@ -366,21 +367,7 @@ bool LDLT::solveInPlace(MatrixBase &bAndX) const const Index size = m_matrix.rows(); ei_assert(size == bAndX.rows()); - // z = P b - for(Index i = 0; i < size; ++i) bAndX.row(m_transpositions.coeff(i)).swap(bAndX.row(i)); - - // y = L^-1 z - //matrixL().solveInPlace(bAndX); - matrixL().solveInPlace(bAndX); - - // w = D^-1 y - bAndX = m_matrix.diagonal().asDiagonal().inverse() * bAndX; - - // u = L^-T w - matrixU().solveInPlace(bAndX); - - // x = P^T u - for (Index i = size-1; i >= 0; --i) bAndX.row(m_transpositions.coeff(i)).swap(bAndX.row(i)); + bAndX = this->solve(bAndX); return true; } @@ -394,10 +381,10 @@ MatrixType LDLT::reconstructedMatrix() const ei_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); MatrixType res(size,size); - res.setIdentity(); - // PI - for(Index i = 0; i < size; ++i) res.row(m_transpositions.coeff(i)).swap(res.row(i)); + // P + res.setIdentity(); + res = transpositionsP() * res; // L^* P res = matrixU() * res; // D(L^*P) @@ -405,7 +392,7 @@ MatrixType LDLT::reconstructedMatrix() const // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) - for (Index i = size-1; i >= 0; --i) res.row(m_transpositions.coeff(i)).swap(res.row(i)); + res = transpositionsP().transpose() * res; return res; } diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 46884dc3f..d3e36c73a 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff --git a/Eigen/src/Core/Transpositions.h b/Eigen/src/Core/Transpositions.h new file mode 100644 index 000000000..39cb24fd7 --- /dev/null +++ b/Eigen/src/Core/Transpositions.h @@ -0,0 +1,285 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_TRANSPOSITIONS_H +#define EIGEN_TRANSPOSITIONS_H + +/** \class Transpositions + * + * \brief Represents a sequence of transpositions (row/column interchange) + * + * \param SizeAtCompileTime the number of transpositions, or Dynamic + * \param MaxSizeAtCompileTime the maximum number of transpositions, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * + * This class represents a permutation transformation as a sequence of \em n transpositions + * \f$[T_{n-1} \ldots T_{i} \ldots T_{0}]\f$. It is internally stored as a vector of integers \c indices. + * Each transposition \f$ T_{i} \f$ applied on the left of a matrix (\f$ T_{i} M\f$) interchanges + * the rows \c i and \c indices[i] of the matrix \c M. + * A transposition applied on the right (e.g., \f$ M T_{i}\f$) yields a column interchange. + * + * Compared to the class PermutationMatrix, such a sequence of transpositions is what is + * computed during a decomposition with pivoting, and it is faster when applying the permutation in-place. + * + * To apply a sequence of transpositions to a matrix, simply use the operator * as in the following example: + * \code + * Transpositions tr; + * MatrixXf mat; + * mat = tr * mat; + * \endcode + * In this example, we detect that the matrix appears on both side, and so the transpositions + * are applied in-place without any temporary or extra copy. + * + * \sa class PermutationMatrix + */ +template class Transpositions; +template struct ei_transposition_matrix_product_retval; + +template +class Transpositions +{ + public: + + typedef Matrix IndicesType; + typedef typename IndicesType::Index Index; + + inline Transpositions() {} + + /** Copy constructor. */ + template + inline Transpositions(const Transpositions& other) + : m_indices(other.indices()) {} + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** Standard copy constructor. Defined only to prevent a default copy constructor + * from hiding the other templated constructor */ + inline Transpositions(const Transpositions& other) : m_indices(other.indices()) {} + #endif + + /** Generic constructor from expression of the transposition indices. */ + template + explicit inline Transpositions(const MatrixBase& indices) : m_indices(indices) + {} + + /** Copies the \a other transpositions into \c *this */ + template + Transpositions& operator=(const Transpositions& other) + { + m_indices = other.indices(); + return *this; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + Transpositions& operator=(const Transpositions& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline Transpositions(Index size) : m_indices(size) + {} + + /** \returns the number of transpositions */ + inline Index size() const { return m_indices.size(); } + + inline const Index& coeff(Index i) const { return m_indices.coeff(i); } + inline Index& coeffRef(Index i) { return m_indices.coeffRef(i); } + inline const Index& operator()(Index i) const { return m_indices(i); } + inline Index& operator()(Index i) { return m_indices(i); } + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the transpositions. */ + IndicesType& indices() { return m_indices; } + + /** Resizes to given size. */ + inline void resize(int size) + { + m_indices.resize(size); + } + + /** Sets \c *this to represents an identity transformation */ + void setIdentity() + { + for(int i = 0; i < m_indices.size(); ++i) + m_indices.coeffRef(i) = i; + } + + // FIXME: do we want such methods ? + // might be usefull when the target matrix expression is complex, e.g.: + // object.matrix().block(..,..,..,..) = trans * object.matrix().block(..,..,..,..); + /* + template + void applyForwardToRows(MatrixType& mat) const + { + for(Index k=0 ; k + void applyBackwardToRows(MatrixType& mat) const + { + for(Index k=size()-1 ; k>=0 ; --k) + if(m_indices(k)!=k) + mat.row(k).swap(mat.row(m_indices(k))); + } + */ + + /** \returns the inverse transformation */ + inline Transpose inverse() const + { return *this; } + + /** \returns the tranpose transformation */ + inline Transpose transpose() const + { return *this; } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template + Transpositions(const Transpose >& other) + : m_indices(other.size()) + { + Index n = size(); + Index j = size-1; + for(Index i=0; i +inline const ei_transposition_matrix_product_retval, Derived, OnTheRight> +operator*(const MatrixBase& matrix, + const Transpositions &transpositions) +{ + return ei_transposition_matrix_product_retval + , Derived, OnTheRight> + (transpositions, matrix.derived()); +} + +/** \returns the \a matrix with the \a transpositions applied to the rows. + */ +template +inline const ei_transposition_matrix_product_retval + , Derived, OnTheLeft> +operator*(const Transpositions &transpositions, + const MatrixBase& matrix) +{ + return ei_transposition_matrix_product_retval + , Derived, OnTheLeft> + (transpositions, matrix.derived()); +} + +template +struct ei_traits > +{ + typedef typename MatrixType::PlainObject ReturnType; +}; + +template +struct ei_transposition_matrix_product_retval + : public ReturnByValue > +{ + typedef typename ei_cleantype::type MatrixTypeNestedCleaned; + typedef typename TranspositionType::Index Index; + + ei_transposition_matrix_product_retval(const TranspositionType& tr, const MatrixType& matrix) + : m_transpositions(tr), m_matrix(matrix) + {} + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + + template inline void evalTo(Dest& dst) const + { + const int size = m_transpositions.size(); + Index j = 0; + + if(!(ei_is_same_type::ret && ei_extract_data(dst) == ei_extract_data(m_matrix))) + dst = m_matrix; + + for(int k=(Transposed?size-1:0) ; Transposed?k>=0:k +class Transpose > +{ + typedef Transpositions TranspositionType; + typedef typename TranspositionType::IndicesType IndicesType; + public: + + Transpose(const TranspositionType& t) : m_transpositions(t) {} + + inline int size() const { return m_transpositions.size(); } + + /** \returns the \a matrix with the inverse transpositions applied to the columns. + */ + template friend + inline const ei_transposition_matrix_product_retval + operator*(const MatrixBase& matrix, const Transpose& trt) + { + return ei_transposition_matrix_product_retval(trt.m_transpositions, matrix.derived()); + } + + /** \returns the \a matrix with the inverse transpositions applied to the rows. + */ + template + inline const ei_transposition_matrix_product_retval + operator*(const MatrixBase& matrix) const + { + return ei_transposition_matrix_product_retval(m_transpositions, matrix.derived()); + } + + const TranspositionType& nestedTranspositions() const { return m_transpositions; } + + protected: + const TranspositionType& m_transpositions; +}; + +#endif // EIGEN_TRANSPOSITIONS_H diff --git a/test/cholesky.cpp b/test/cholesky.cpp index d403af7ba..feb7be289 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -26,10 +26,21 @@ #define EIGEN_NO_ASSERTION_CHECKING #endif +static int nb_temporaries; + +#define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; } + #include "main.h" #include #include +#define VERIFY_EVALUATION_COUNT(XPR,N) {\ + nb_temporaries = 0; \ + XPR; \ + if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ + VERIFY( (#XPR) && nb_temporaries==N ); \ + } + #ifdef HAS_GSL #include "gsl_helper.h" #endif @@ -131,6 +142,21 @@ template void cholesky(const MatrixType& m) VERIFY_IS_APPROX(symm * vecX, vecB); matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + + if(MatrixType::RowsAtCompileTime==Dynamic) + { + // note : each inplace permutation requires a small temporary vector (mask) + + // check inplace solve + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); + + + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); + } } } @@ -141,6 +167,7 @@ template void cholesky_verify_assert() LLT llt; VERIFY_RAISES_ASSERT(llt.matrixL()) + VERIFY_RAISES_ASSERT(llt.matrixU()) VERIFY_RAISES_ASSERT(llt.solve(tmp)) VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp)) From 7726cc8a29c34e775f179de986530eca60df3d60 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Jun 2010 14:47:20 +0200 Subject: [PATCH 29/67] clean old stuff used to support precompilation inside a binary lib --- Eigen/Cholesky | 32 -------- Eigen/Eigenvalues | 35 --------- Eigen/QR | 29 -------- .../Core/products/GeneralBlockPanelKernel.h | 4 - Eigen/src/Core/products/GeneralMatrixMatrix.h | 4 - .../src/Eigenvalues/HessenbergDecomposition.h | 42 +++++------ .../src/Eigenvalues/SelfAdjointEigenSolver.h | 74 +++++++++---------- Eigen/src/Eigenvalues/Tridiagonalization.h | 50 ++++++------- Eigen/src/QR/ColPivHouseholderQR.h | 4 - Eigen/src/QR/FullPivHouseholderQR.h | 4 - Eigen/src/QR/HouseholderQR.h | 4 - 11 files changed, 76 insertions(+), 206 deletions(-) diff --git a/Eigen/Cholesky b/Eigen/Cholesky index a0e0d146b..7d209966f 100644 --- a/Eigen/Cholesky +++ b/Eigen/Cholesky @@ -5,15 +5,6 @@ #include "src/Core/util/DisableMSVCWarnings.h" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup Cholesky_Module Cholesky module @@ -37,29 +28,6 @@ namespace Eigen { } // namespace Eigen -#define EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class LLT; \ - PREFIX template class LDLT - -#define EIGEN_CHOLESKY_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - -namespace Eigen { - EIGEN_CHOLESKY_MODULE_INSTANTIATE(extern); -} // namespace Eigen -#endif - #include "src/Core/util/EnableMSVCWarnings.h" #endif // EIGEN_CHOLESKY_MODULE_H diff --git a/Eigen/Eigenvalues b/Eigen/Eigenvalues index f22a3bc30..5a9757ad5 100644 --- a/Eigen/Eigenvalues +++ b/Eigen/Eigenvalues @@ -10,15 +10,6 @@ #include "Householder" #include "LU" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup Eigenvalues_Module Eigenvalues module @@ -44,32 +35,6 @@ namespace Eigen { #include "src/Eigenvalues/ComplexEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" -// declare all classes for a given matrix type -#define EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class Tridiagonalization; \ - PREFIX template class HessenbergDecomposition; \ - PREFIX template class SelfAdjointEigenSolver - -// removed because it does not support complex yet -// PREFIX template class EigenSolver - -// declare all class for all types -#define EIGEN_EIGENVALUES_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - EIGEN_EIGENVALUES_MODULE_INSTANTIATE(extern); -#endif // EIGEN_EXTERN_INSTANTIATIONS - } // namespace Eigen #include "src/Core/util/EnableMSVCWarnings.h" diff --git a/Eigen/QR b/Eigen/QR index 825cfb149..d64f96002 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -9,15 +9,6 @@ #include "Jacobi" #include "Householder" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup QR_Module QR module @@ -38,26 +29,6 @@ namespace Eigen { #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" -// declare all classes for a given matrix type -#define EIGEN_QR_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class HouseholderQR; \ - -// declare all class for all types -#define EIGEN_QR_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - EIGEN_QR_MODULE_INSTANTIATE(extern); -#endif // EIGEN_EXTERN_INSTANTIATIONS } // namespace Eigen diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index d81715528..ca3e4eaf3 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -25,8 +25,6 @@ #ifndef EIGEN_GENERAL_BLOCK_PANEL_H #define EIGEN_GENERAL_BLOCK_PANEL_H -#ifndef EIGEN_EXTERN_INSTANTIATIONS - #ifdef EIGEN_HAS_FUSE_CJMADD #define CJMADD(A,B,C,T) C = cj.pmadd(A,B,C); #else @@ -762,6 +760,4 @@ struct ei_gemm_pack_rhs } }; -#endif // EIGEN_EXTERN_INSTANTIATIONS - #endif // EIGEN_GENERAL_BLOCK_PANEL_H diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 991977c1f..457173382 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -25,8 +25,6 @@ #ifndef EIGEN_GENERAL_MATRIX_MATRIX_H #define EIGEN_GENERAL_MATRIX_MATRIX_H -#ifndef EIGEN_EXTERN_INSTANTIATIONS - /* Specialization for a row-major destination matrix => simple transposition of the product */ template< typename Scalar, typename Index, @@ -203,8 +201,6 @@ static void run(Index rows, Index cols, Index depth, }; -#endif // EIGEN_EXTERN_INSTANTIATIONS - /********************************************************************************* * Specialization of GeneralProduct<> for "large" GEMM, i.e., * implementation of the high level wrapper to ei_general_matrix_matrix_product diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index 4f3c357a8..783042782 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -53,11 +53,11 @@ struct ei_traits > * \f$ Q^{-1} = Q^* \f$). * * Call the function compute() to compute the Hessenberg decomposition of a - * given matrix. Alternatively, you can use the + * given matrix. Alternatively, you can use the * HessenbergDecomposition(const MatrixType&) constructor which computes the * Hessenberg decomposition at construction time. Once the decomposition is * computed, you can use the matrixH() and matrixQ() functions to construct - * the matrices H and Q in the decomposition. + * the matrices H and Q in the decomposition. * * The documentation for matrixH() contains an example of the typical use of * this class. @@ -114,8 +114,8 @@ template class HessenbergDecomposition m_hCoeffs.resize(size-1); } - /** \brief Constructor; computes Hessenberg decomposition of given matrix. - * + /** \brief Constructor; computes Hessenberg decomposition of given matrix. + * * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed. * * This constructor calls compute() to compute the Hessenberg @@ -138,8 +138,8 @@ template class HessenbergDecomposition m_isInitialized = true; } - /** \brief Computes Hessenberg decomposition of given matrix. - * + /** \brief Computes Hessenberg decomposition of given matrix. + * * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed. * \returns Reference to \c *this * @@ -177,18 +177,18 @@ template class HessenbergDecomposition * or the member function compute(const MatrixType&) has been called * before to compute the Hessenberg decomposition of a matrix. * - * The Householder coefficients allow the reconstruction of the matrix + * The Householder coefficients allow the reconstruction of the matrix * \f$ Q \f$ in the Hessenberg decomposition from the packed data. * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - const CoeffVectorType& householderCoefficients() const - { + const CoeffVectorType& householderCoefficients() const + { ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); - return m_hCoeffs; + return m_hCoeffs; } - /** \brief Returns the internal representation of the decomposition + /** \brief Returns the internal representation of the decomposition * * \returns a const reference to a matrix with the internal representation * of the decomposition. @@ -201,11 +201,11 @@ template class HessenbergDecomposition * - the upper part and lower sub-diagonal represent the Hessenberg matrix H * - the rest of the lower part contains the Householder vectors that, combined with * Householder coefficients returned by householderCoefficients(), - * allows to reconstruct the matrix Q as + * allows to reconstruct the matrix Q as * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. - * Here, the matrices \f$ H_i \f$ are the Householder transformations + * Here, the matrices \f$ H_i \f$ are the Householder transformations * \f$ H_i = (I - h_i v_i v_i^T) \f$ - * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and + * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and * \f$ v_i \f$ is the Householder vector defined by * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$ * with M the matrix returned by this function. @@ -217,13 +217,13 @@ template class HessenbergDecomposition * * \sa householderCoefficients() */ - const MatrixType& packedMatrix() const - { + const MatrixType& packedMatrix() const + { ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); - return m_matrix; + return m_matrix; } - /** \brief Reconstructs the orthogonal matrix Q in the decomposition + /** \brief Reconstructs the orthogonal matrix Q in the decomposition * * \returns object representing the matrix Q * @@ -274,7 +274,7 @@ template class HessenbergDecomposition typedef Matrix VectorType; typedef typename NumTraits::Real RealScalar; static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp); - + protected: MatrixType m_matrix; CoeffVectorType m_hCoeffs; @@ -282,8 +282,6 @@ template class HessenbergDecomposition bool m_isInitialized; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal * Performs a tridiagonal decomposition of \a matA in place. * @@ -325,8 +323,6 @@ void HessenbergDecomposition::_compute(MatrixType& matA, CoeffVector } } -#endif // EIGEN_HIDE_HEAVY_CODE - /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 6a7d46b39..04402f844 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -43,7 +43,7 @@ * A matrix \f$ A \f$ is selfadjoint if it equals its adjoint. For real * matrices, this means that the matrix is symmetric: it equals its * transpose. This class computes the eigenvalues and eigenvectors of a - * selfadjoint matrix. These are the scalars \f$ \lambda \f$ and vectors + * selfadjoint matrix. These are the scalars \f$ \lambda \f$ and vectors * \f$ v \f$ such that \f$ Av = \lambda v \f$. The eigenvalues of a * selfadjoint matrix are always real. If \f$ D \f$ is a diagonal matrix with * the eigenvalues on the diagonal, and \f$ V \f$ is a matrix with the @@ -68,7 +68,7 @@ * * The documentation for SelfAdjointEigenSolver(const MatrixType&, bool) * contains an example of the typical use of this class. - * + * * \sa MatrixBase::eigenvalues(), class EigenSolver, class ComplexEigenSolver */ template class SelfAdjointEigenSolver @@ -87,15 +87,15 @@ template class SelfAdjointEigenSolver typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; - /** \brief Real scalar type for \p _MatrixType. + /** \brief Real scalar type for \p _MatrixType. * - * This is just \c Scalar if #Scalar is real (e.g., \c float or + * This is just \c Scalar if #Scalar is real (e.g., \c float or * \c double), and the type of the real part of \c Scalar if #Scalar is * complex. */ typedef typename NumTraits::Real RealScalar; - /** \brief Type for vector of eigenvalues as returned by eigenvalues(). + /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #RealScalar. * The length of the vector is the size of \p _MatrixType. @@ -130,7 +130,7 @@ template class SelfAdjointEigenSolver * This constructor is useful for dynamic-size matrices, when the user * intends to perform decompositions via compute(const MatrixType&, bool) * or compute(const MatrixType&, const MatrixType&, bool). The \p size - * parameter is only used as a hint. It is not an error to give a wrong + * parameter is only used as a hint. It is not an error to give a wrong * \p size, but it may impair performance. * * \sa compute(const MatrixType&, bool) for an example @@ -143,13 +143,13 @@ template class SelfAdjointEigenSolver m_isInitialized(false) {} - /** \brief Constructor; computes eigendecomposition of given matrix. - * + /** \brief Constructor; computes eigendecomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * * This constructor calls compute(const MatrixType&, bool) to compute the * eigenvalues of the matrix \p matrix. The eigenvectors are computed if @@ -158,7 +158,7 @@ template class SelfAdjointEigenSolver * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.out * - * \sa compute(const MatrixType&, bool), + * \sa compute(const MatrixType&, bool), * SelfAdjointEigenSolver(const MatrixType&, const MatrixType&, bool) */ SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) @@ -172,14 +172,14 @@ template class SelfAdjointEigenSolver } /** \brief Constructor; computes eigendecomposition of given matrix pencil. - * + * * \param[in] matA Selfadjoint matrix in matrix pencil. * \param[in] matB Positive-definite matrix in matrix pencil. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * - * This constructor calls compute(const MatrixType&, const MatrixType&, bool) + * This constructor calls compute(const MatrixType&, const MatrixType&, bool) * to compute the eigenvalues and (if requested) the eigenvectors of the * generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA the * selfadjoint matrix \f$ A \f$ and \a matB the positive definite matrix @@ -189,7 +189,7 @@ template class SelfAdjointEigenSolver * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.out * - * \sa compute(const MatrixType&, const MatrixType&, bool), + * \sa compute(const MatrixType&, const MatrixType&, bool), * SelfAdjointEigenSolver(const MatrixType&, bool) */ SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true) @@ -202,13 +202,13 @@ template class SelfAdjointEigenSolver compute(matA, matB, computeEigenvectors); } - /** \brief Computes eigendecomposition of given matrix. - * + /** \brief Computes eigendecomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * \returns Reference to \c *this * * This function computes the eigenvalues of \p matrix. The eigenvalues() @@ -236,13 +236,13 @@ template class SelfAdjointEigenSolver */ SelfAdjointEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); - /** \brief Computes eigendecomposition of given matrix pencil. - * + /** \brief Computes eigendecomposition of given matrix pencil. + * * \param[in] matA Selfadjoint matrix in matrix pencil. * \param[in] matB Positive-definite matrix in matrix pencil. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * \returns Reference to \c *this * * This function computes eigenvalues and (if requested) the eigenvectors @@ -253,11 +253,11 @@ template class SelfAdjointEigenSolver * eigenvectors are also computed and can be retrieved by calling * eigenvectors(). * - * The implementation uses LLT to compute the Cholesky decomposition + * The implementation uses LLT to compute the Cholesky decomposition * \f$ B = LL^* \f$ and calls compute(const MatrixType&, bool) to compute * the eigendecomposition \f$ L^{-1} A (L^*)^{-1} \f$. This solves the * generalized eigenproblem, because any solution of the generalized - * eigenproblem \f$ Ax = \lambda B x \f$ corresponds to a solution + * eigenproblem \f$ Ax = \lambda B x \f$ corresponds to a solution * \f$ L^{-1} A (L^*)^{-1} (L^* x) = \lambda (L^* x) \f$ of the * eigenproblem for \f$ L^{-1} A (L^*)^{-1} \f$. * @@ -268,7 +268,7 @@ template class SelfAdjointEigenSolver */ SelfAdjointEigenSolver& compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true); - /** \brief Returns the eigenvectors of given matrix (pencil). + /** \brief Returns the eigenvectors of given matrix (pencil). * * \returns A const reference to the matrix whose columns are the eigenvectors. * @@ -293,7 +293,7 @@ template class SelfAdjointEigenSolver return m_eivec; } - /** \brief Returns the eigenvalues of given matrix (pencil). + /** \brief Returns the eigenvalues of given matrix (pencil). * * \returns A const reference to the column vector containing the eigenvalues. * @@ -307,13 +307,13 @@ template class SelfAdjointEigenSolver * * \sa eigenvectors(), MatrixBase::eigenvalues() */ - const RealVectorType& eigenvalues() const - { + const RealVectorType& eigenvalues() const + { ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); - return m_eivalues; + return m_eivalues; } - /** \brief Computes the positive-definite square root of the matrix. + /** \brief Computes the positive-definite square root of the matrix. * * \returns the positive-definite square root of the matrix * @@ -328,7 +328,7 @@ template class SelfAdjointEigenSolver * Example: \include SelfAdjointEigenSolver_operatorSqrt.cpp * Output: \verbinclude SelfAdjointEigenSolver_operatorSqrt.out * - * \sa operatorInverseSqrt(), + * \sa operatorInverseSqrt(), * \ref MatrixFunctions_Module "MatrixFunctions Module" */ MatrixType operatorSqrt() const @@ -338,7 +338,7 @@ template class SelfAdjointEigenSolver return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } - /** \brief Computes the inverse square root of the matrix. + /** \brief Computes the inverse square root of the matrix. * * \returns the inverse positive-definite square root of the matrix * @@ -375,7 +375,7 @@ template class SelfAdjointEigenSolver /** \brief Maximum number of iterations. * - * Maximum number of iterations allowed for an eigenvalue to converge. + * Maximum number of iterations allowed for an eigenvalue to converge. */ static const int m_maxIterations = 30; @@ -389,8 +389,6 @@ template class SelfAdjointEigenSolver bool m_eigenvectorsOk; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal * * \eigenvalues_module \ingroup Eigenvalues_Module @@ -467,7 +465,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( ei_tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); } - if (iter <= m_maxIterations) + if (iter <= m_maxIterations) m_info = Success; else m_info = NoConvergence; @@ -531,9 +529,6 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors return *this; } -#endif // EIGEN_HIDE_HEAVY_CODE - -#ifndef EIGEN_EXTERN_INSTANTIATIONS template static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n) { @@ -575,6 +570,5 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index } } } -#endif #endif // EIGEN_SELFADJOINTEIGENSOLVER_H diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index acf21e2da..62a607176 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -80,7 +80,7 @@ template class Tridiagonalization typedef Matrix CoeffVectorType; typedef typename ei_plain_col_type::type DiagonalType; typedef Matrix SubDiagonalType; - + typedef typename ei_meta_if::IsComplex, typename Diagonal::RealReturnType, Diagonal @@ -109,13 +109,13 @@ template class Tridiagonalization * \sa compute() for an example. */ Tridiagonalization(Index size = Size==Dynamic ? 2 : Size) - : m_matrix(size,size), + : m_matrix(size,size), m_hCoeffs(size > 1 ? size-1 : 1), m_isInitialized(false) {} - /** \brief Constructor; computes tridiagonal decomposition of given matrix. - * + /** \brief Constructor; computes tridiagonal decomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition * is to be computed. * @@ -125,7 +125,7 @@ template class Tridiagonalization * Output: \verbinclude Tridiagonalization_Tridiagonalization_MatrixType.out */ Tridiagonalization(const MatrixType& matrix) - : m_matrix(matrix), + : m_matrix(matrix), m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1), m_isInitialized(false) { @@ -133,8 +133,8 @@ template class Tridiagonalization m_isInitialized = true; } - /** \brief Computes tridiagonal decomposition of given matrix. - * + /** \brief Computes tridiagonal decomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition * is to be computed. * \returns Reference to \c *this @@ -167,7 +167,7 @@ template class Tridiagonalization * the member function compute(const MatrixType&) has been called before * to compute the tridiagonal decomposition of a matrix. * - * The Householder coefficients allow the reconstruction of the matrix + * The Householder coefficients allow the reconstruction of the matrix * \f$ Q \f$ in the tridiagonal decomposition from the packed data. * * Example: \include Tridiagonalization_householderCoefficients.cpp @@ -175,13 +175,13 @@ template class Tridiagonalization * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - inline CoeffVectorType householderCoefficients() const - { + inline CoeffVectorType householderCoefficients() const + { ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); - return m_hCoeffs; + return m_hCoeffs; } - /** \brief Returns the internal representation of the decomposition + /** \brief Returns the internal representation of the decomposition * * \returns a const reference to a matrix with the internal representation * of the decomposition. @@ -193,14 +193,14 @@ template class Tridiagonalization * The returned matrix contains the following information: * - the strict upper triangular part is equal to the input matrix A. * - the diagonal and lower sub-diagonal represent the real tridiagonal - * symmetric matrix T. + * symmetric matrix T. * - the rest of the lower part contains the Householder vectors that, * combined with Householder coefficients returned by * householderCoefficients(), allows to reconstruct the matrix Q as * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. - * Here, the matrices \f$ H_i \f$ are the Householder transformations + * Here, the matrices \f$ H_i \f$ are the Householder transformations * \f$ H_i = (I - h_i v_i v_i^T) \f$ - * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and + * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and * \f$ v_i \f$ is the Householder vector defined by * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$ * with M the matrix returned by this function. @@ -212,13 +212,13 @@ template class Tridiagonalization * * \sa householderCoefficients() */ - inline const MatrixType& packedMatrix() const - { + inline const MatrixType& packedMatrix() const + { ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); - return m_matrix; + return m_matrix; } - /** \brief Returns the unitary matrix Q in the decomposition + /** \brief Returns the unitary matrix Q in the decomposition * * \returns object representing the matrix Q * @@ -285,7 +285,7 @@ template class Tridiagonalization */ const SubDiagonalReturnType subDiagonal() const; - /** \brief Performs a full decomposition in place + /** \brief Performs a full decomposition in place * * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal * decomposition is to be computed. On output, the orthogonal matrix Q @@ -293,7 +293,7 @@ template class Tridiagonalization * \param[out] diag The diagonal of the tridiagonal matrix T in the * decomposition. * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in - * the decomposition. + * the decomposition. * \param[in] extractQ If true, the orthogonal matrix Q in the * decomposition is computed and stored in \p mat. * @@ -311,10 +311,10 @@ template class Tridiagonalization * * \note Notwithstanding the name, the current implementation copies * \p mat to a temporary matrix and uses that matrix to compute the - * decomposition. + * decomposition. * * Example (this uses the same matrix as the example in - * Tridiagonalization(const MatrixType&)): + * Tridiagonalization(const MatrixType&)): * \include Tridiagonalization_decomposeInPlace.cpp * Output: \verbinclude Tridiagonalization_decomposeInPlace.out * @@ -367,8 +367,6 @@ Tridiagonalization::matrixT() const return matT; } -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal * Performs a tridiagonal decomposition of \a matA in place. * @@ -473,6 +471,4 @@ void Tridiagonalization::_decomposeInPlace3x3(MatrixType& mat, Diago } } -#endif // EIGEN_HIDE_HEAVY_CODE - #endif // EIGEN_TRIDIAGONALIZATION_H diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index e0eaf32a9..6914d6873 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -347,8 +347,6 @@ template class ColPivHouseholderQR Index m_det_pq; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template typename MatrixType::RealScalar ColPivHouseholderQR::absDeterminant() const { @@ -513,8 +511,6 @@ typename ColPivHouseholderQR::HouseholderSequenceType ColPivHousehol return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate(), false, m_nonzero_pivots, 0); } -#endif // EIGEN_HIDE_HEAVY_CODE - /** \return the column-pivoting Householder QR decomposition of \c *this. * * \sa class ColPivHouseholderQR diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 3b4d02d67..cfb0b30a9 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -271,8 +271,6 @@ template class FullPivHouseholderQR Index m_det_pq; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template typename MatrixType::RealScalar FullPivHouseholderQR::absDeterminant() const { @@ -437,8 +435,6 @@ typename FullPivHouseholderQR::MatrixQType FullPivHouseholderQR class HouseholderQR bool m_isInitialized; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template typename MatrixType::RealScalar HouseholderQR::absDeterminant() const { @@ -254,8 +252,6 @@ struct ei_solve_retval, Rhs> } }; -#endif // EIGEN_HIDE_HEAVY_CODE - /** \return the Householder QR decomposition of \c *this. * * \sa class HouseholderQR From 88cd6885be191440648b6886e0224f5cdae62ae0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Jun 2010 16:35:25 +0200 Subject: [PATCH 30/67] Add a proof concept API to configure the blocking parameters at runtime. After validation of the final API I'll update the other products to use it. --- Eigen/src/Core/arch/AltiVec/PacketMath.h | 6 +- Eigen/src/Core/arch/Default/Settings.h | 2 +- Eigen/src/Core/arch/NEON/PacketMath.h | 2 +- .../Core/products/GeneralBlockPanelKernel.h | 95 ++++++++++++++++++- Eigen/src/Core/products/GeneralMatrixMatrix.h | 11 ++- Eigen/src/Core/util/BlasUtil.h | 2 +- Eigen/src/Core/util/Constants.h | 2 + 7 files changed, 108 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 0a7b07645..2feca365a 100644 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -31,10 +31,10 @@ #ifndef EIGEN_HAS_FUSE_CJMADD #define EIGEN_HAS_FUSE_CJMADD 1 -#endif +#endif #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 8*128*128 +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 8*256*256 #endif // NOTE Altivec has 32 registers, but Eigen only accepts a value of 8 or 16 @@ -153,7 +153,7 @@ template<> EIGEN_STRONG_INLINE Packet4f ei_pset1(const float& from) { return vc; } -template<> EIGEN_STRONG_INLINE Packet4i ei_pset1(const int& from) { +template<> EIGEN_STRONG_INLINE Packet4i ei_pset1(const int& from) { int EIGEN_ALIGN16 ai[4]; ai[0] = from; Packet4i vc = vec_ld(0, ai); diff --git a/Eigen/src/Core/arch/Default/Settings.h b/Eigen/src/Core/arch/Default/Settings.h index 1ab2877b6..150c4bdc7 100644 --- a/Eigen/src/Core/arch/Default/Settings.h +++ b/Eigen/src/Core/arch/Default/Settings.h @@ -52,7 +52,7 @@ * Typically for a single-threaded application you would set that to 25% of the size of your CPU caches in bytes */ #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE (sizeof(float)*256*256) +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE (sizeof(float)*512*512) #endif /** Defines the maximal width of the blocks used in the triangular product and solver diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index 96c75101c..d4dd33322 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -32,7 +32,7 @@ #endif #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 4*96*96 +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 4*192*192 #endif // FIXME NEON has 16 quad registers, but since the current register allocator diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index ca3e4eaf3..dc6c2ebf3 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -25,11 +25,100 @@ #ifndef EIGEN_GENERAL_BLOCK_PANEL_H #define EIGEN_GENERAL_BLOCK_PANEL_H +/** \internal */ +inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptrdiff_t* b=0, int scalar_size = 0) +{ + const int nbScalarSizes = 12; + static std::ptrdiff_t m_maxK[nbScalarSizes]; + static std::ptrdiff_t m_maxM[nbScalarSizes]; + static std::ptrdiff_t m_cpuCacheSize = 0; + if(m_cpuCacheSize==0) + { + // initialization + m_cpuCacheSize = EIGEN_TUNE_FOR_CPU_CACHE_SIZE; + ei_manage_caching_sizes(SetAction,&m_cpuCacheSize); + } + + if(action==SetAction && scalar_size==0) + { + // set the cpu cache size and cache all block sizes from a global cache size in byte + ei_internal_assert(a!=0 && b==0); + m_cpuCacheSize = *a; + int ss = 4; + for(int i=0; i>2)-1,0); + if(i>2),1),nbScalarSizes)-1; + *a = m_maxK[i]; + *b = m_maxM[i]; + } + else + { + ei_internal_assert(false); + } +} + +/** \returns the currently set cpu cache size (in bytes) used to estimate the ideal blocking size parameters */ +std::ptrdiff_t ei_cpuCacheSize() +{ + std::ptrdiff_t ret; + ei_manage_caching_sizes(GetAction, &ret); + return ret; +} + +/** Set the cpu cache size (in bytes) for blocking. + * This function also automatically set the blocking size parameters for each scalar type using the following formula: + * \code + * max_k = 4 * sqrt(cache_size/(64*sizeof(Scalar))); + * max_m = 2 * k; + * \endcode + * overwriting custom values set using the ei_setBlockingSizes function. + * \sa ei_setBlockingSizes */ +void ei_setCpuCacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } + +/** Set the blocking size parameters \a maxK and \a maxM for the scalar type \a Scalar. + * Note that in practice there is no distinction between scalar types of same size. + * \sa ei_setCpuCacheSize */ +template +void ei_setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM) +{ + ei_manage_caching_sizes(SetAction,&maxK,&maxM,sizeof(Scalar)); +} + +/** \returns in \a makK, \a maxM the blocking size parameters for the scalar type \a Scalar. + * \sa ei_setBlockingSizes */ +template +void ei_getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM) +{ + ei_manage_caching_sizes(GetAction,&maxK,&maxM,sizeof(Scalar)); +} + #ifdef EIGEN_HAS_FUSE_CJMADD -#define CJMADD(A,B,C,T) C = cj.pmadd(A,B,C); + #define CJMADD(A,B,C,T) C = cj.pmadd(A,B,C); #else -#define CJMADD(A,B,C,T) T = B; T = cj.pmul(A,T); C = ei_padd(C,T); -// #define CJMADD(A,B,C,T) T = A; T = cj.pmul(T,B); C = ei_padd(C,T); + #define CJMADD(A,B,C,T) T = B; T = cj.pmul(A,T); C = ei_padd(C,T); #endif // optimized GEneral packed Block * packed Panel product kernel diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 457173382..3086616f8 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -75,8 +75,11 @@ static void run(Index rows, Index cols, Index depth, typedef typename ei_packet_traits::type PacketType; typedef ei_product_blocking_traits Blocking; - Index kc = std::min(Blocking::Max_kc,depth); // cache block size along the K direction - Index mc = std::min(Blocking::Max_mc,rows); // cache block size along the M direction + Index kc; // cache block size along the K direction + Index mc; // cache block size along the M direction + ei_getBlockingSizes(kc, mc); + kc = std::min(kc,depth); + mc = std::min(mc,rows); ei_gemm_pack_rhs pack_rhs; ei_gemm_pack_lhs pack_lhs; @@ -235,7 +238,9 @@ struct ei_gemm_functor Index sharedBlockBSize() const { - return std::min(ei_product_blocking_traits::Max_kc,m_rhs.rows()) * m_rhs.cols(); + int maxKc, maxMc; + ei_getBlockingSizes(maxKc,maxMc); + return std::min(maxKc,m_rhs.rows()) * m_rhs.cols(); } protected: diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h index 89c094d31..24d27bce2 100644 --- a/Eigen/src/Core/util/BlasUtil.h +++ b/Eigen/src/Core/util/BlasUtil.h @@ -139,7 +139,7 @@ struct ei_product_blocking_traits mr = 2 * PacketSize, // max cache block size along the K direction - Max_kc = 8 * ei_meta_sqrt::ret, + Max_kc = 4 * ei_meta_sqrt::ret, // max cache block size along the M direction Max_mc = 2*Max_kc diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index a586f2a5d..a36e7d05b 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -269,6 +269,8 @@ namespace Architecture enum { CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; +enum Action {GetAction, SetAction}; + /** The type used to identify a dense storage. */ struct Dense {}; From 727376b5f43bfa52aa7b7d492001824071f2d1dd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Jun 2010 18:55:39 +0200 Subject: [PATCH 31/67] compilation fix (std::sqrt(int) does not exist) --- Eigen/src/Core/products/GeneralBlockPanelKernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index dc6c2ebf3..b17c8e2dc 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -47,7 +47,7 @@ inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptr int ss = 4; for(int i=0; i(m_cpuCacheSize/(64*ss))); m_maxM[i] = 2 * m_maxK[i]; } } From f3a568c81d1b0b03ca9e7295f3db36fbd3c768af Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Jun 2010 19:05:30 +0200 Subject: [PATCH 32/67] remove ei_ prefix of public global functions, and s/cpu/l1 --- .../Core/products/GeneralBlockPanelKernel.h | 30 ++++++++++++++----- Eigen/src/Core/products/GeneralMatrixMatrix.h | 4 +-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index b17c8e2dc..f4a4ac2b4 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -80,8 +80,9 @@ inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptr } } -/** \returns the currently set cpu cache size (in bytes) used to estimate the ideal blocking size parameters */ -std::ptrdiff_t ei_cpuCacheSize() +/** \returns the currently set cpu cache size (in bytes) used to estimate the ideal blocking size parameters. + * \sa setL1CacheSize */ +std::ptrdiff_t l1CacheSize() { std::ptrdiff_t ret; ei_manage_caching_sizes(GetAction, &ret); @@ -89,28 +90,41 @@ std::ptrdiff_t ei_cpuCacheSize() } /** Set the cpu cache size (in bytes) for blocking. - * This function also automatically set the blocking size parameters for each scalar type using the following formula: + * This function also automatically set the blocking size parameters + * for each scalar type using the following formula: * \code * max_k = 4 * sqrt(cache_size/(64*sizeof(Scalar))); * max_m = 2 * k; * \endcode * overwriting custom values set using the ei_setBlockingSizes function. + * + * \b Explanations: \n + * Let A * B be a m x k times k x n matrix product. Then Eigen's product yield + * L2 blocking on B with panels of size max_k x n, and L1 blocking on A, + * with blocks of size max_m x max_k. + * * \sa ei_setBlockingSizes */ -void ei_setCpuCacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } +void setL1CacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } /** Set the blocking size parameters \a maxK and \a maxM for the scalar type \a Scalar. * Note that in practice there is no distinction between scalar types of same size. - * \sa ei_setCpuCacheSize */ + * + * See ei_setCpuCacheSize for an explanation about the meaning of maxK and maxM. + * + * \sa setL1CacheSize */ template -void ei_setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM) +void setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM) { ei_manage_caching_sizes(SetAction,&maxK,&maxM,sizeof(Scalar)); } /** \returns in \a makK, \a maxM the blocking size parameters for the scalar type \a Scalar. - * \sa ei_setBlockingSizes */ + * + * See ei_setCpuCacheSize for an explanation about the meaning of maxK and maxM. + * + * \sa setL1CacheSize */ template -void ei_getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM) +void getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM) { ei_manage_caching_sizes(GetAction,&maxK,&maxM,sizeof(Scalar)); } diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 3086616f8..3286379e8 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -77,7 +77,7 @@ static void run(Index rows, Index cols, Index depth, Index kc; // cache block size along the K direction Index mc; // cache block size along the M direction - ei_getBlockingSizes(kc, mc); + getBlockingSizes(kc, mc); kc = std::min(kc,depth); mc = std::min(mc,rows); @@ -239,7 +239,7 @@ struct ei_gemm_functor Index sharedBlockBSize() const { int maxKc, maxMc; - ei_getBlockingSizes(maxKc,maxMc); + getBlockingSizes(maxKc,maxMc); return std::min(maxKc,m_rhs.rows()) * m_rhs.cols(); } From 04274f6793641b7570ae5e2a2dbdf315a3de9d9f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 00:05:20 +0200 Subject: [PATCH 33/67] Fixed eigensolver warning. --- test/eigensolver_complex.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index dc3b2cfb0..48c43f7f0 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -33,12 +33,14 @@ template void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2) { + typedef typename NumTraits::Real RealScalar; + VERIFY(vec1.cols() == 1); VERIFY(vec2.cols() == 1); VERIFY(vec1.rows() == vec2.rows()); for (int k = 1; k <= vec1.rows(); ++k) { - VERIFY_IS_APPROX(vec1.array().pow(k).sum(), vec2.array().pow(k).sum()); + VERIFY_IS_APPROX(vec1.array().pow(RealScalar(k)).sum(), vec2.array().pow(RealScalar(k)).sum()); } } From f6d26bf6dc05d2d7093f32284360208e7d5de7f5 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 00:41:33 +0200 Subject: [PATCH 34/67] Fixed more warnings. --- test/first_aligned.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp index f00ed57a5..5fb806298 100644 --- a/test/first_aligned.cpp +++ b/test/first_aligned.cpp @@ -34,6 +34,9 @@ void test_first_aligned_helper(Scalar *array, int size) template void test_none_aligned_helper(Scalar *array, int size) { + // Suppress 'unreferenced formal parameter's warnings. + (void)array; + (void)size; VERIFY(ei_packet_traits::size == 1 || ei_first_aligned(array, size) == size); } From bda40da002b7c944b993414214b3b240465c8660 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 09:37:13 +0200 Subject: [PATCH 35/67] Fixed GCC compilation. --- test/eigensolver_complex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 48c43f7f0..1c1dd98f3 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -33,7 +33,7 @@ template void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2) { - typedef typename NumTraits::Real RealScalar; + typedef typename NumTraits::Real RealScalar; VERIFY(vec1.cols() == 1); VERIFY(vec2.cols() == 1); From 626afe8b625c7bbccf84698dd27c7fe56cce01dd Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 10:06:14 +0200 Subject: [PATCH 36/67] Fixed integer type warnings. --- test/integer_types.cpp | 63 ++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/test/integer_types.cpp b/test/integer_types.cpp index 4e7a093c6..d2feb8a65 100644 --- a/test/integer_types.cpp +++ b/test/integer_types.cpp @@ -31,7 +31,37 @@ #undef VERIFY_IS_NOT_APPROX #define VERIFY_IS_NOT_APPROX(a, b) VERIFY((a)!=(b)); -template void integer_types(const MatrixType& m) +template void signed_integer_type_tests(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + + enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 }; + VERIFY(is_signed == 1); + + int rows = m.rows(); + int cols = m.cols(); + + MatrixType m1(rows, cols), + m2 = MatrixType::Random(rows, cols), + mzero = MatrixType::Zero(rows, cols); + + do { + m1 = MatrixType::Random(rows, cols); + } while(m1 == mzero || m1 == m2); + + // check linear structure + + Scalar s1; + do { + s1 = ei_random(); + } while(s1 == 0); + + VERIFY_IS_EQUAL(-(-m1), m1); + VERIFY_IS_EQUAL(-m2+m1+m2, m1); + VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2); +} + +template void integer_type_tests(const MatrixType& m) { typedef typename MatrixType::Scalar Scalar; @@ -97,13 +127,10 @@ template void integer_types(const MatrixType& m) s1 = ei_random(); } while(s1 == 0); - VERIFY_IS_EQUAL(-(-m1), m1); VERIFY_IS_EQUAL(m1+m1, 2*m1); VERIFY_IS_EQUAL(m1+m2-m1, m2); - VERIFY_IS_EQUAL(-m2+m1+m2, m1); VERIFY_IS_EQUAL(m1*s1, s1*m1); VERIFY_IS_EQUAL((m1+m2)*s1, s1*m1+s1*m2); - VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2); m3 = m2; m3 += m1; VERIFY_IS_EQUAL(m3, m1+m2); m3 = m2; m3 -= m1; @@ -122,18 +149,26 @@ template void integer_types(const MatrixType& m) void test_integer_types() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( integer_types(Matrix()) ); - CALL_SUBTEST_1( integer_types(Matrix()) ); - CALL_SUBTEST_2( integer_types(Matrix()) ); + CALL_SUBTEST_1( integer_type_tests(Matrix()) ); + CALL_SUBTEST_1( integer_type_tests(Matrix()) ); - CALL_SUBTEST_3( integer_types(Matrix(2, 10)) ); - CALL_SUBTEST_4( integer_types(Matrix()) ); - CALL_SUBTEST_4( integer_types(Matrix(20, 20)) ); + CALL_SUBTEST_2( integer_type_tests(Matrix()) ); + CALL_SUBTEST_2( signed_integer_type_tests(Matrix()) ); - CALL_SUBTEST_5( integer_types(Matrix(7, 4)) ); - CALL_SUBTEST_6( integer_types(Matrix()) ); + CALL_SUBTEST_3( integer_type_tests(Matrix(2, 10)) ); + CALL_SUBTEST_3( signed_integer_type_tests(Matrix(2, 10)) ); - CALL_SUBTEST_7( integer_types(Matrix()) ); - CALL_SUBTEST_8( integer_types(Matrix(1, 5)) ); + CALL_SUBTEST_4( integer_type_tests(Matrix()) ); + CALL_SUBTEST_4( integer_type_tests(Matrix(20, 20)) ); + + CALL_SUBTEST_5( integer_type_tests(Matrix(7, 4)) ); + CALL_SUBTEST_5( signed_integer_type_tests(Matrix(7, 4)) ); + + CALL_SUBTEST_6( integer_type_tests(Matrix()) ); + + CALL_SUBTEST_7( integer_type_tests(Matrix()) ); + CALL_SUBTEST_7( signed_integer_type_tests(Matrix()) ); + + CALL_SUBTEST_8( integer_type_tests(Matrix(1, 5)) ); } } From 4b5d359c3afc2caf5f2f89e2f44f13243bacb5f7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 8 Jun 2010 13:29:27 +0200 Subject: [PATCH 37/67] improve/fix stable_norm unit test --- test/nullary.cpp | 6 +++--- test/stable_norm.cpp | 47 +++++++++++++++++++++++++++++++------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/test/nullary.cpp b/test/nullary.cpp index 3adfc33fe..6e91ddd52 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -51,8 +51,8 @@ void testVectorType(const VectorType& base) { typedef typename ei_traits::Scalar Scalar; Scalar low = ei_random(-500,500); - Scalar high = ei_random(-500,500); - if (low>high) std::swap(low,high); + Scalar high = ei_random(-500,500); + if (low>high) std::swap(low,high); const int size = base.size(); const Scalar step = (high-low)/(size-1); @@ -91,7 +91,7 @@ void testVectorType(const VectorType& base) Matrix size_changer(size+50); size_changer.setLinSpaced(low,high,size); - VERIFY( size_changer.size() == size ); + VERIFY( size_changer.size() == size ); } template diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index b0c6e0183..a308b34eb 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -24,6 +24,11 @@ #include "main.h" +template bool isFinite(const T& x) +{ + return x==x && x>=NumTraits::lowest() && x<=NumTraits::highest(); +} + template void stable_norm(const MatrixType& m) { /* this test covers the following files: @@ -50,7 +55,7 @@ template void stable_norm(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - Scalar big = ei_abs(ei_random()) * (std::numeric_limits::max() * RealScalar(1e-4)); + Scalar big = ei_random()) * (std::numeric_limits::max() * RealScalar(1e-4); Scalar small = static_cast(1)/big; MatrixType vzero = MatrixType::Zero(rows, cols), @@ -68,22 +73,36 @@ template void stable_norm(const MatrixType& m) RealScalar size = static_cast(m.size()); - // test overflow -/* VERIFY_IS_NOT_APPROX(static_cast(vbig.norm()), ei_sqrt(size)*big); // here the default norm must fail - Does not succeed on gcc (Ubuntu 4.4.1-4ubuntu9) 4.4.1, Intel Core 2 Duo T7300 with no SSE optimizations -*/ + // test isFinite + VERIFY(!isFinite( ei_abs(big)/RealScalar(0))); + VERIFY(!isFinite(-ei_abs(big)/RealScalar(0))); + VERIFY(!isFinite(ei_sqrt(-ei_abs(big)))); - VERIFY_IS_APPROX(static_cast(vbig.stableNorm()), ei_sqrt(size)*big); - VERIFY_IS_APPROX(static_cast(vbig.blueNorm()), ei_sqrt(size)*big); - VERIFY_IS_APPROX(static_cast(vbig.hypotNorm()), ei_sqrt(size)*big); + // test overflow + VERIFY(isFinite(ei_sqrt(size)*ei_abs(big))); + #ifdef EIGEN_VECTORIZE_SSE + // since x87 FPU uses 80bits of precision overflow is not detected + if(ei_packet_traits::size>1) + { + VERIFY_IS_NOT_APPROX(static_cast(vbig.norm()), ei_sqrt(size)*big); // here the default norm must fail + } + #endif + VERIFY_IS_APPROX(vbig.stableNorm(), ei_sqrt(size)*ei_abs(big)); + VERIFY_IS_APPROX(vbig.blueNorm(), ei_sqrt(size)*ei_abs(big)); + VERIFY_IS_APPROX(vbig.hypotNorm(), ei_sqrt(size)*ei_abs(big)); // test underflow -/* VERIFY_IS_NOT_APPROX(static_cast(vsmall.norm()), ei_sqrt(size)*small); // here the default norm must fail - Does not succeed on gcc (Ubuntu 4.4.1-4ubuntu9) 4.4.1, Intel Core 2 Duo T7300 with no SSE optimizations -*/ - VERIFY_IS_APPROX(static_cast(vsmall.stableNorm()), ei_sqrt(size)*small); - VERIFY_IS_APPROX(static_cast(vsmall.blueNorm()), ei_sqrt(size)*small); - VERIFY_IS_APPROX(static_cast(vsmall.hypotNorm()), ei_sqrt(size)*small); + VERIFY(isFinite(ei_sqrt(size)*ei_abs(small))); + #ifdef EIGEN_VECTORIZE_SSE + // since x87 FPU uses 80bits of precision underflow is not detected + if(ei_packet_traits::size>1) + { + VERIFY_IS_NOT_APPROX(static_cast(vsmall.norm()), ei_sqrt(size)*small); // here the default norm must fail + } + #endif + VERIFY_IS_APPROX(vsmall.stableNorm(), ei_sqrt(size)*ei_abs(small)); + VERIFY_IS_APPROX(vsmall.blueNorm(), ei_sqrt(size)*ei_abs(small)); + VERIFY_IS_APPROX(vsmall.hypotNorm(), ei_sqrt(size)*ei_abs(small)); // Test compilation of cwise() version VERIFY_IS_APPROX(vrand.colwise().stableNorm(), vrand.colwise().norm()); From 2a64fa49475b64a7c7bcd560359d5f67180322e3 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 13:49:40 +0200 Subject: [PATCH 38/67] Eigen types must always be passed by reference in order to retain memory alignment. --- test/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main.h b/test/main.h index d1a68befb..184a35b15 100644 --- a/test/main.h +++ b/test/main.h @@ -368,7 +368,7 @@ inline bool test_isUnitary(const MatrixBase& m) } template -bool test_is_equal(T actual, U expected) +bool test_is_equal(const T& actual, const U& expected) { if (actual==expected) return true; From 4c5778d29da3ddb21b3f1c64b8179571c7ba8847 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 15:52:00 +0200 Subject: [PATCH 39/67] Made the supression of unused variables portable. EIGEN_UNUSED is not supported on non GCC systems. --- Eigen/src/Core/products/GeneralMatrixMatrix.h | 3 ++- Eigen/src/Core/util/Macros.h | 3 +++ Eigen/src/Core/util/Memory.h | 2 +- Eigen/src/Sparse/SparseProduct.h | 6 +++--- test/first_aligned.cpp | 5 ++--- test/triangular.cpp | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 3286379e8..07721145a 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -160,7 +160,8 @@ static void run(Index rows, Index cols, Index depth, else #endif // EIGEN_HAS_OPENMP { - (void)info; // info is not used + EIGEN_UNUSED_VARIABLE(info); + // this is the sequential version! Scalar* blockA = ei_aligned_stack_new(Scalar, kc*mc); std::size_t sizeB = kc*Blocking::PacketSize*Blocking::nr + kc*cols; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 82045b37c..061767039 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -176,6 +176,9 @@ #define EIGEN_UNUSED #endif +// Suppresses 'unused variable' warnings. +#define EIGEN_UNUSED_VARIABLE(var) (void)var; + #if (defined __GNUC__) #define EIGEN_ASM_COMMENT(X) asm("#"X) #else diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 6b202dbc8..c67b9774f 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -218,7 +218,7 @@ inline void ei_aligned_free(void *ptr) **/ inline void* ei_aligned_realloc(void *ptr, size_t new_size, size_t old_size) { - (void)old_size; // Suppress 'unused variable' warning. Seen in boost tee. + EIGEN_UNUSED_VARIABLE(old_size); void *result; #if !EIGEN_ALIGN diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index 2f86b2b2d..7a91c9cf0 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -382,9 +382,9 @@ struct ei_sparse_product_selector2 RowMajorMatrix; // RowMajorMatrix rhsRow = rhs; diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp index 5fb806298..687f4a5dc 100644 --- a/test/first_aligned.cpp +++ b/test/first_aligned.cpp @@ -34,9 +34,8 @@ void test_first_aligned_helper(Scalar *array, int size) template void test_none_aligned_helper(Scalar *array, int size) { - // Suppress 'unreferenced formal parameter's warnings. - (void)array; - (void)size; + EIGEN_UNUSED_VARIABLE(array); + EIGEN_UNUSED_VARIABLE(size); VERIFY(ei_packet_traits::size == 1 || ei_first_aligned(array, size) == size); } diff --git a/test/triangular.cpp b/test/triangular.cpp index d6d64e595..12452515e 100644 --- a/test/triangular.cpp +++ b/test/triangular.cpp @@ -235,8 +235,8 @@ void test_triangular() { for(int i = 0; i < g_repeat ; i++) { - EIGEN_UNUSED int r = ei_random(2,20); - EIGEN_UNUSED int c = ei_random(2,20); + int r = ei_random(2,20); EIGEN_UNUSED_VARIABLE(r); + int c = ei_random(2,20); EIGEN_UNUSED_VARIABLE(c); CALL_SUBTEST_1( triangular_square(Matrix()) ); CALL_SUBTEST_2( triangular_square(Matrix()) ); From 1c9b7a8d9f23afae703bf525bd4f68c9cb8f61c1 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 16:02:22 +0200 Subject: [PATCH 40/67] Fighting for a green dashboard! Next warning's gone. --- test/lu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lu.cpp b/test/lu.cpp index 22dca76d2..9aa793e00 100644 --- a/test/lu.cpp +++ b/test/lu.cpp @@ -120,7 +120,7 @@ template void lu_invertible() MatrixType m1(size, size), m2(size, size), m3(size, size); FullPivLU lu; - lu.setThreshold(0.01); + lu.setThreshold(RealScalar(0.01)); do { m1 = MatrixType::Random(size,size); lu.compute(m1); From 8b0da2de640e15abbb745ec296ef9bc95741962c Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 20:09:39 +0200 Subject: [PATCH 41/67] Fix stable_norm compilation. --- test/stable_norm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index a308b34eb..c5a0296c5 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -55,7 +55,7 @@ template void stable_norm(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - Scalar big = ei_random()) * (std::numeric_limits::max() * RealScalar(1e-4); + Scalar big = ei_random() * (std::numeric_limits::max() * RealScalar(1e-4)); Scalar small = static_cast(1)/big; MatrixType vzero = MatrixType::Zero(rows, cols), From fb3fcd0919cb21e5edecbcc336c949c358ebe2bb Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Jun 2010 20:21:55 +0200 Subject: [PATCH 42/67] Disabled warning caused by declspec(align()). --- Eigen/src/Core/util/DisableMSVCWarnings.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/DisableMSVCWarnings.h b/Eigen/src/Core/util/DisableMSVCWarnings.h index dcc71143d..7bab741ff 100644 --- a/Eigen/src/Core/util/DisableMSVCWarnings.h +++ b/Eigen/src/Core/util/DisableMSVCWarnings.h @@ -3,7 +3,8 @@ // 4273 - QtAlignedMalloc, inconsistent DLL linkage // 4100 - unreferenced formal parameter (occurred e.g. in aligned_allocator::destroy(pointer p)) // 4101 - unreferenced local variable + // 4324 - structure was padded due to declspec(align()) // 4512 - assignment operator could not be generated #pragma warning( push ) - #pragma warning( disable : 4100 4101 4181 4244 4127 4211 4273 4512 4522 4717 ) + #pragma warning( disable : 4100 4101 4181 4244 4127 4211 4273 4324 4512 4522 4717 ) #endif From 684656d41c3b1b87018719a474ec8c7c244fffa2 Mon Sep 17 00:00:00 2001 From: Trevor Irons Date: Tue, 8 Jun 2010 10:56:50 -0600 Subject: [PATCH 43/67] added inline to setL1Cache functions to avoid shared object compile error --- Eigen/src/Core/products/GeneralBlockPanelKernel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index f4a4ac2b4..12934b3b9 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -82,7 +82,7 @@ inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptr /** \returns the currently set cpu cache size (in bytes) used to estimate the ideal blocking size parameters. * \sa setL1CacheSize */ -std::ptrdiff_t l1CacheSize() +inline std::ptrdiff_t l1CacheSize() { std::ptrdiff_t ret; ei_manage_caching_sizes(GetAction, &ret); @@ -104,7 +104,7 @@ std::ptrdiff_t l1CacheSize() * with blocks of size max_m x max_k. * * \sa ei_setBlockingSizes */ -void setL1CacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } +inline void setL1CacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } /** Set the blocking size parameters \a maxK and \a maxM for the scalar type \a Scalar. * Note that in practice there is no distinction between scalar types of same size. From 50e43bc75ad3cccc5e9755bac16c5023dd22eba4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 8 Jun 2010 22:23:11 +0200 Subject: [PATCH 44/67] * add Transpositions to PermutationMatrix conversion * make PartialPivLu uses the Transpositions class --- Eigen/src/Core/PermutationMatrix.h | 31 +++++++++++++++++------ Eigen/src/Core/Transpositions.h | 9 ++++++- Eigen/src/Core/util/ForwardDeclarations.h | 2 ++ Eigen/src/LU/PartialPivLU.h | 12 ++++----- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index d3e36c73a..6ce357091 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -47,7 +47,6 @@ * * \sa class DiagonalMatrix */ -template class PermutationMatrix; template struct ei_permut_matrix_product_retval; template @@ -78,8 +77,12 @@ class PermutationMatrix : public EigenBase IndicesType; inline PermutationMatrix() - { - } + {} + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline PermutationMatrix(int size) : m_indices(size) + {} /** Copy constructor. */ template @@ -103,6 +106,14 @@ class PermutationMatrix : public EigenBase& indices) : m_indices(indices) {} + /** Convert the Transpositions \a tr to a permutation matrix */ + template + explicit PermutationMatrix(const Transpositions& tr) + : m_indices(tr.size()) + { + *this = tr; + } + /** Copies the other permutation into *this */ template PermutationMatrix& operator=(const PermutationMatrix& other) @@ -111,6 +122,15 @@ class PermutationMatrix : public EigenBase + PermutationMatrix& operator=(const Transpositions& tr) + { + setIdentity(tr.size()); + for(int k=size()-1; k>=0; --k) + applyTranspositionOnTheRight(k,tr.coeff(k)); + } + #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. @@ -122,11 +142,6 @@ class PermutationMatrix : public EigenBase class Transpositions; template struct ei_transposition_matrix_product_retval; template @@ -108,10 +107,18 @@ class Transpositions /** \returns the number of transpositions */ inline Index size() const { return m_indices.size(); } + /** Direct access to the underlying index vector */ inline const Index& coeff(Index i) const { return m_indices.coeff(i); } + /** Direct access to the underlying index vector */ inline Index& coeffRef(Index i) { return m_indices.coeffRef(i); } + /** Direct access to the underlying index vector */ inline const Index& operator()(Index i) const { return m_indices(i); } + /** Direct access to the underlying index vector */ inline Index& operator()(Index i) { return m_indices(i); } + /** Direct access to the underlying index vector */ + inline const Index& operator[](Index i) const { return m_indices(i); } + /** Direct access to the underlying index vector */ + inline Index& operator[](Index i) { return m_indices(i); } /** const version of indices(). */ const IndicesType& indices() const { return m_indices; } diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 5cf62f4c6..6a9a7941c 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -77,6 +77,8 @@ template class DiagonalWrapper; template class DiagonalMatrix; template class DiagonalProduct; template class Diagonal; +template class PermutationMatrix; +template class Transpositions; template class Stride; template > class Map; diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 0bf1ac3ce..a9172289c 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -73,8 +73,8 @@ template class PartialPivLU typedef typename NumTraits::Real RealScalar; typedef typename ei_traits::StorageKind StorageKind; typedef typename MatrixType::Index Index; - typedef typename ei_plain_col_type::type PermutationVectorType; typedef PermutationMatrix PermutationType; + typedef Transpositions TranspositionType; /** @@ -186,7 +186,7 @@ template class PartialPivLU protected: MatrixType m_lu; PermutationType m_p; - PermutationVectorType m_rowsTranspositions; + TranspositionType m_rowsTranspositions; Index m_det_p; bool m_isInitialized; }; @@ -389,8 +389,8 @@ struct ei_partial_lu_impl /** \internal performs the LU decomposition with partial pivoting in-place. */ -template -void ei_partial_lu_inplace(MatrixType& lu, IntVector& row_transpositions, typename MatrixType::Index& nb_transpositions) +template +void ei_partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename MatrixType::Index& nb_transpositions) { ei_assert(lu.cols() == row_transpositions.size()); ei_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1); @@ -414,9 +414,7 @@ PartialPivLU& PartialPivLU::compute(const MatrixType& ma ei_partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions); m_det_p = (nb_transpositions%2) ? -1 : 1; - m_p.setIdentity(size); - for(Index k = size-1; k >= 0; --k) - m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k)); + m_p = m_rowsTranspositions; m_isInitialized = true; return *this; From 45d3b405eb1bd3f3f7f4f2043621a57e6bee1365 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 9 Jun 2010 09:30:22 +0200 Subject: [PATCH 45/67] Fixed many MSVC warnings. --- test/selfadjoint.cpp | 2 +- unsupported/Eigen/FFT | 20 +++++++++++-------- unsupported/Eigen/src/BVH/BVAlgorithms.h | 6 +++++- .../HybridNonLinearSolver.h | 2 ++ .../LevenbergMarquardt.h | 2 ++ .../Eigen/src/NumericalDiff/NumericalDiff.h | 2 ++ unsupported/test/NonLinearOptimization.cpp | 4 ++++ 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/test/selfadjoint.cpp b/test/selfadjoint.cpp index 2eaf6d459..1ea5a3a3c 100644 --- a/test/selfadjoint.cpp +++ b/test/selfadjoint.cpp @@ -55,7 +55,7 @@ void test_selfadjoint() { for(int i = 0; i < g_repeat ; i++) { - EIGEN_UNUSED int s = ei_random(1,20); + int s = ei_random(1,20); EIGEN_UNUSED_VARIABLE(s); CALL_SUBTEST_1( selfadjoint(Matrix()) ); CALL_SUBTEST_2( selfadjoint(Matrix()) ); diff --git a/unsupported/Eigen/FFT b/unsupported/Eigen/FFT index a41a89a8a..0e8e57e50 100644 --- a/unsupported/Eigen/FFT +++ b/unsupported/Eigen/FFT @@ -136,10 +136,12 @@ struct fft_fwd_proxy int rows() const { return m_src.rows(); } int cols() const { return m_src.cols(); } - protected: - const T_SrcMat & m_src; - T_FftIfc & m_ifc; - int m_nfft; +protected: + const T_SrcMat & m_src; + T_FftIfc & m_ifc; + int m_nfft; +private: + fft_fwd_proxy& operator=(const fft_fwd_proxy&); }; template @@ -152,10 +154,12 @@ struct fft_inv_proxy int rows() const { return m_src.rows(); } int cols() const { return m_src.cols(); } - protected: - const T_SrcMat & m_src; - T_FftIfc & m_ifc; - int m_nfft; +protected: + const T_SrcMat & m_src; + T_FftIfc & m_ifc; + int m_nfft; +private: + fft_inv_proxy& operator=(const fft_inv_proxy&); }; diff --git a/unsupported/Eigen/src/BVH/BVAlgorithms.h b/unsupported/Eigen/src/BVH/BVAlgorithms.h index 63725763a..40320291d 100644 --- a/unsupported/Eigen/src/BVH/BVAlgorithms.h +++ b/unsupported/Eigen/src/BVH/BVAlgorithms.h @@ -86,9 +86,11 @@ struct ei_intersector_helper2 bool intersectObject(const Object2 &obj) { return intersector.intersectObjectObject(stored, obj); } Object1 stored; Intersector &intersector; +private: + ei_intersector_helper2& operator=(const ei_intersector_helper2&); }; -/** Given two BVH's, runs the query on their cartesian product encapsulated by \a intersector. +/** Given two BVH's, runs the query on their Cartesian product encapsulated by \a intersector. * The Intersector type must provide the following members: \code bool intersectVolumeVolume(const BVH1::Volume &v1, const BVH2::Volume &v2) //returns true if product of volumes intersects the query bool intersectVolumeObject(const BVH1::Volume &v1, const BVH2::Object &o2) //returns true if the volume-object product intersects the query @@ -207,6 +209,8 @@ struct ei_minimizer_helper1 Scalar minimumOnObject(const Object1 &obj) { return minimizer.minimumOnObjectObject(obj, stored); } Object2 stored; Minimizer &minimizer; +private: + ei_minimizer_helper1& operator=(const ei_minimizer_helper1&) {} }; template diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index aba31b238..0ef3ecafa 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -124,6 +124,8 @@ private: Index ncfail; Scalar actred, prered; FVectorType wa1, wa2, wa3, wa4; + + HybridNonLinearSolver& operator=(const HybridNonLinearSolver&); }; diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 63eb66738..a8f3f3e64 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -133,6 +133,8 @@ private: Scalar delta; Scalar ratio; Scalar pnorm, xnorm, fnorm1, actred, dirder, prered; + + LevenbergMarquardt& operator=(const LevenbergMarquardt&); }; template diff --git a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h index 8d23cb4ae..a25c9cd6d 100644 --- a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h +++ b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h @@ -130,6 +130,8 @@ public: } private: Scalar epsfcn; + + NumericalDiff& operator=(const NumericalDiff&); }; //vim: ai ts=4 sts=4 et sw=4 diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index 0a609f750..c5dd08417 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -8,6 +8,10 @@ #include "main.h" #include +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include + int fcn_chkder(const VectorXd &x, VectorXd &fvec, MatrixXd &fjac, int iflag) { /* subroutine fcn for chkder example. */ From 8cc02169fde556a06af0e641f26fa39fcb9f95be Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 9 Jun 2010 09:48:06 +0200 Subject: [PATCH 46/67] Fix devision by zero warning. --- test/stable_norm.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index c5a0296c5..77b062303 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -74,8 +74,7 @@ template void stable_norm(const MatrixType& m) RealScalar size = static_cast(m.size()); // test isFinite - VERIFY(!isFinite( ei_abs(big)/RealScalar(0))); - VERIFY(!isFinite(-ei_abs(big)/RealScalar(0))); + VERIFY(!isFinite( std::numeric_limits::infinity())); VERIFY(!isFinite(ei_sqrt(-ei_abs(big)))); // test overflow From 201bd253ad5df543d10396bdde3a56d8ebd3400e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 9 Jun 2010 13:18:10 +0200 Subject: [PATCH 47/67] fix ldlt unit test --- test/cholesky.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/cholesky.cpp b/test/cholesky.cpp index feb7be289..4cc09ec05 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -129,34 +129,34 @@ template void cholesky(const MatrixType& m) } { - LDLT ldltlo(symm); + LDLT ldltlo(symmLo); VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); matX = ldltlo.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); - LDLT ldltup(symm); + LDLT ldltup(symmUp); VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); vecX = ldltup.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); - if(MatrixType::RowsAtCompileTime==Dynamic) - { - // note : each inplace permutation requires a small temporary vector (mask) - - // check inplace solve - matX = matB; - VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); - VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); - - - matX = matB; - VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); - VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); - } +// if(MatrixType::RowsAtCompileTime==Dynamic) +// { +// // note : each inplace permutation requires a small temporary vector (mask) +// +// // check inplace solve +// matX = matB; +// VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); +// VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); +// +// +// matX = matB; +// VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); +// VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); +// } } } From e242ac9345e728d8e347bb0d48497891e3891276 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 9 Jun 2010 14:01:06 +0200 Subject: [PATCH 48/67] fix LDLT, now it really only uses a given triangular part! --- Eigen/src/Cholesky/LDLT.h | 21 +++++++++++++++--- Eigen/src/Cholesky/LLT.h | 5 ++++- Eigen/src/LU/PartialPivLU.h | 12 +++++----- test/cholesky.cpp | 44 ++++++++++++++++++++----------------- 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 79657f086..e9fa4a5d2 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -69,7 +69,6 @@ template class LDLT typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Index Index; -// typedef typename ei_plain_col_type::type IntColVectorType; typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; @@ -251,10 +250,26 @@ template<> struct ei_ldlt_inplace transpositions.coeffRef(k) = index_of_biggest_in_corner; if(k != index_of_biggest_in_corner) { - mat.row(k).swap(mat.row(index_of_biggest_in_corner)); - mat.col(k).swap(mat.col(index_of_biggest_in_corner)); + // apply the transposition while taking care to consider only + // the lower triangular part + Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element + mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); + mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); + std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); + for(int i=k+1;i::IsComplex) + mat.coeffRef(index_of_biggest_in_corner,k) = ei_conj(mat.coeff(index_of_biggest_in_corner,k)); } + // partition the matrix: + // A00 | - | - + // lu = A10 | A11 | - + // A20 | A21 | A22 Index rs = size - k - 1; Block A21(mat,k+1,k,rs,1); Block A10(mat,k,0,1,k); diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 6e853436c..6e7660ddf 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -208,9 +208,12 @@ template<> struct ei_llt_inplace for (Index k=0; k A11(m,k, k, bs,bs); Block A21(m,k+bs,k, rs,bs); Block A22(m,k+bs,k+bs,rs,rs); diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index a9172289c..7e7516a5c 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -339,9 +339,9 @@ struct ei_partial_lu_impl Index tsize = size - k - bs; // trailing size // partition the matrix: - // A00 | A01 | A02 - // lu = A10 | A11 | A12 - // A20 | A21 | A22 + // A00 | A01 | A02 + // lu = A_0 | A_1 | A_2 = A10 | A11 | A12 + // A20 | A21 | A22 BlockType A_0(lu,0,0,rows,k); BlockType A_2(lu,0,k+bs,rows,tsize); BlockType A11(lu,k,k,bs,bs); @@ -350,8 +350,8 @@ struct ei_partial_lu_impl BlockType A22(lu,k+bs,k+bs,trows,tsize); Index nb_transpositions_in_panel; - // recursively calls the blocked LU algorithm with a very small - // blocking size: + // recursively call the blocked LU algorithm on [A11^T A21^T]^T + // with a very small blocking size: if(!blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride, row_transpositions+k, nb_transpositions_in_panel, 16)) { @@ -364,7 +364,7 @@ struct ei_partial_lu_impl } nb_transpositions += nb_transpositions_in_panel; - // update permutations and apply them to A10 + // update permutations and apply them to A_0 for(Index i=k; i void cholesky(const MatrixType& m) VERIFY_IS_APPROX(symm * matX, matB); } - int sign = ei_random()%2 ? 1 : -1; - - if(sign == -1) + // LDLT { - symm = -symm; // test a negative matrix - } + int sign = ei_random()%2 ? 1 : -1; + + if(sign == -1) + { + symm = -symm; // test a negative matrix + } + + SquareMatrixType symmUp = symm.template triangularView(); + SquareMatrixType symmLo = symm.template triangularView(); - { LDLT ldltlo(symmLo); VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); vecX = ldltlo.solve(vecB); @@ -143,20 +147,20 @@ template void cholesky(const MatrixType& m) matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); -// if(MatrixType::RowsAtCompileTime==Dynamic) -// { -// // note : each inplace permutation requires a small temporary vector (mask) -// -// // check inplace solve -// matX = matB; -// VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); -// VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); -// -// -// matX = matB; -// VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); -// VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); -// } + if(MatrixType::RowsAtCompileTime==Dynamic) + { + // note : each inplace permutation requires a small temporary vector (mask) + + // check inplace solve + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); + + + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); + } } } From 2b7b549e9e2319f0b33615c675b8453adf693fed Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 9 Jun 2010 17:16:05 +0200 Subject: [PATCH 49/67] Fix #131. --- Eigen/src/Core/CwiseBinaryOp.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 6e158fdf1..3593e07d6 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -45,8 +45,19 @@ * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp */ template -struct ei_traits > : ei_traits +struct ei_traits > { + // we must not inherit from ei_traits since it incurrs + // the potential to cause problems with MSVC + typedef typename ei_cleantype::type Ancestor; + typedef typename ei_traits::XprKind XprKind; + enum { + RowsAtCompileTime = ei_traits::RowsAtCompileTime, + ColsAtCompileTime = ei_traits::ColsAtCompileTime, + MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ei_traits::MaxColsAtCompileTime + }; + // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), // we still want to handle the case when the result type is different. typedef typename ei_result_of< From 56e585efcc4e598fcb5d1cb1261ab9767f744973 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 9 Jun 2010 17:20:31 +0200 Subject: [PATCH 50/67] Fixed language issue. --- Eigen/src/Core/CwiseBinaryOp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 3593e07d6..d0816211a 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -47,7 +47,7 @@ template struct ei_traits > { - // we must not inherit from ei_traits since it incurrs + // we must not inherit from ei_traits since it has // the potential to cause problems with MSVC typedef typename ei_cleantype::type Ancestor; typedef typename ei_traits::XprKind XprKind; From bcf738811e28f6387b2644ffe457e1c81f6de545 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 10 Jun 2010 00:02:10 +0200 Subject: [PATCH 51/67] Added missing return statement. --- Eigen/src/Core/PermutationMatrix.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 6ce357091..8227c9bf9 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -129,6 +129,7 @@ class PermutationMatrix : public EigenBase=0; --k) applyTranspositionOnTheRight(k,tr.coeff(k)); + return *this; } #ifndef EIGEN_PARSED_BY_DOXYGEN From 8692ccc5fb6ddcb16838eaa98c17d5659232c82e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 00:04:33 +0200 Subject: [PATCH 52/67] Fix generalized symm eigensolver (I don't know why the eigenvectors were normalized) --- Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 04402f844..0fef247e0 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -523,8 +523,6 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors { // transform back the eigen vectors: evecs = inv(U) * evecs cholB.matrixU().solveInPlace(m_eivec); - for (Index i=0; i Date: Thu, 10 Jun 2010 00:19:45 +0200 Subject: [PATCH 53/67] fix unit test when GSL is enabled --- test/eigensolver_selfadjoint.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 9f0c4cf38..4f81132e7 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -91,10 +91,9 @@ template void selfadjointeigensolver(const MatrixType& m) VERIFY((symmA * _evec).isApprox(symmB * (_evec * _eval.asDiagonal()), largerEps)); // compare with eigen -// std::cerr << _eval.transpose() << "\n" << eiSymmGen.eigenvalues().transpose() << "\n\n"; -// std::cerr << _evec.format(6) << "\n\n" << eiSymmGen.eigenvectors().format(6) << "\n\n\n"; + MatrixType normalized_eivec = eiSymmGen.eigenvectors()*eiSymmGen.eigenvectors().colwise().norm().asDiagonal().inverse(); VERIFY_IS_APPROX(_eval, eiSymmGen.eigenvalues()); - VERIFY_IS_APPROX(_evec.cwiseAbs(), eiSymmGen.eigenvectors().cwiseAbs()); + VERIFY_IS_APPROX(_evec.cwiseAbs(), normalized_eivec.cwiseAbs()); Gsl::free(gSymmA); Gsl::free(gSymmB); From 3f388282ae8a0e999127dccc5fd57c813b140cc3 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 10 Jun 2010 00:23:11 +0200 Subject: [PATCH 54/67] Fixes geo_transformations_3 unit test. --- Eigen/src/Geometry/Scaling.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h index 27bbec8cd..0de014f62 100644 --- a/Eigen/src/Geometry/Scaling.h +++ b/Eigen/src/Geometry/Scaling.h @@ -174,7 +174,7 @@ template inline Transform UniformScaling::operator* (const Transform& t) const { - Transform res = t; + Transform res = t; res.prescale(factor()); return res; } From 41e5625f96b9d9642c1724ff3859e709d9cfe8cb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 09:34:49 +0200 Subject: [PATCH 55/67] clean general symm eigensolver --- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 0fef247e0..636aa090c 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -499,31 +499,20 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors { ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows()); - // Compute the cholesky decomposition of matB = L L' + // Compute the cholesky decomposition of matB = L L' = U'U LLT cholB(matB); // compute C = inv(L) A inv(L') MatrixType matC = matA; - cholB.matrixL().solveInPlace(matC); - // FIXME since we currently do not support A * inv(L'), let's do (inv(L) A')' : - matC.adjointInPlace(); - cholB.matrixL().solveInPlace(matC); - matC.adjointInPlace(); - // this version works too: -// matC = matC.transpose(); -// cholB.matrixL().conjugate().template marked().solveTriangularInPlace(matC); -// matC = matC.transpose(); - // FIXME: this should work: (currently it only does for small matrices) -// Transpose trMatC(matC); -// cholB.matrixL().conjugate().eval().template marked().solveTriangularInPlace(trMatC); + cholB.matrixL().template solveInPlace(matC); + cholB.matrixU().template solveInPlace(matC); compute(matC, computeEigenvectors); - if (computeEigenvectors) - { - // transform back the eigen vectors: evecs = inv(U) * evecs + // transform back the eigen vectors: evecs = inv(U) * evecs + if(computeEigenvectors) cholB.matrixU().solveInPlace(m_eivec); - } + return *this; } From f8683c409f7524db471e76b1540344ecdc7b0be6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 09:44:52 +0200 Subject: [PATCH 56/67] generalized eigendecomposition doc --- Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 636aa090c..2878a1494 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -171,7 +171,7 @@ template class SelfAdjointEigenSolver compute(matrix, computeEigenvectors); } - /** \brief Constructor; computes eigendecomposition of given matrix pencil. + /** \brief Constructor; computes generalized eigendecomposition of given matrix pencil. * * \param[in] matA Selfadjoint matrix in matrix pencil. * \param[in] matB Positive-definite matrix in matrix pencil. @@ -183,8 +183,9 @@ template class SelfAdjointEigenSolver * to compute the eigenvalues and (if requested) the eigenvectors of the * generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA the * selfadjoint matrix \f$ A \f$ and \a matB the positive definite matrix - * \f$ B \f$ . The eigenvectors are computed if \a computeEigenvectors is - * true. + * \f$ B \f$. Each eigenvector \f$ x \f$ satisfies the property + * \f$ x^* B x = 1 \f$. The eigenvectors are computed if + * \a computeEigenvectors is true. * * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.out @@ -236,7 +237,7 @@ template class SelfAdjointEigenSolver */ SelfAdjointEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); - /** \brief Computes eigendecomposition of given matrix pencil. + /** \brief Computes generalized eigendecomposition of given matrix pencil. * * \param[in] matA Selfadjoint matrix in matrix pencil. * \param[in] matB Positive-definite matrix in matrix pencil. @@ -248,7 +249,10 @@ template class SelfAdjointEigenSolver * This function computes eigenvalues and (if requested) the eigenvectors * of the generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA * the selfadjoint matrix \f$ A \f$ and \a matB the positive definite - * matrix \f$ B \f$. The eigenvalues() function can be used to retrieve + * matrix \f$ B \f$. In addition, each eigenvector \f$ x \f$ + * satisfies the property \f$ x^* B x = 1 \f$. + * + * The eigenvalues() function can be used to retrieve * the eigenvalues. If \p computeEigenvectors is true, then the * eigenvectors are also computed and can be retrieved by calling * eigenvectors(). From 941ca80b80a6db11a5a78a8d323cc40294208891 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 10 Jun 2010 10:06:14 +0200 Subject: [PATCH 57/67] Adapted the determinant test for rank 1 matrices with zero determinant. --- test/inverse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/inverse.cpp b/test/inverse.cpp index 4d9297eb4..b75232727 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -78,7 +78,7 @@ template void inverse(const MatrixType& m) MatrixType m3 = v3*v3.transpose(), m4(rows,cols); m3.computeInverseAndDetWithCheck(m4, det, invertible); VERIFY( rows==1 ? invertible : !invertible ); - VERIFY_IS_APPROX(det, m3.determinant()); + VERIFY_IS_MUCH_SMALLER_THAN(m3.determinant(), RealScalar(1)); m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); #endif From dad19c4173a9e93d100514e49375142b1e0a0ddb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 10:55:49 +0200 Subject: [PATCH 58/67] compilation fix for gcc 4.2 --- Eigen/src/Core/StableNorm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index d2bed929b..e3eab4bd8 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -87,7 +87,7 @@ MatrixBase::blueNorm() const static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr; if(nmax <= 0) { - Index nbig, ibeta, it, iemin, iemax, iexp; + int nbig, ibeta, it, iemin, iemax, iexp; RealScalar abig, eps; // This program calculates the machine-dependent constants // bl, b2, slm, s2m, relerr overfl, nmax From d2779a1a8ea18daecd70103fc68b813daf216f78 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 10:59:06 +0200 Subject: [PATCH 59/67] fix warning with gcc 4.3 --- unsupported/Eigen/src/NonLinearOptimization/qrsolv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h index bce8a4441..15a27d53d 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h @@ -70,7 +70,7 @@ void ei_qrsolv( /* solve the triangular system for z. if the system is */ /* singular, then obtain a least squares solution. */ Index nsing; - for (nsing=0; nsing().solveInPlace(wa.head(nsing)); From 469382407ca5d730f23788c593e71e91d24e9b89 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 16:39:46 +0200 Subject: [PATCH 60/67] * Make HouseholderSequence::evalTo works in place * Clean a bit the Triadiagonalization making sure it the inplace function really works inplace ;), and that only the lower triangular part of the matrix is referenced. * Remove the Tridiagonalization member object of SelfAdjointEigenSolver exploiting the in place capability of HouseholdeSequence. * Update unit test to check SelfAdjointEigenSolver only consider the lower triangular part. --- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 34 +-- Eigen/src/Eigenvalues/Tridiagonalization.h | 238 +++++++++++------- Eigen/src/Householder/HouseholderSequence.h | 47 +++- test/eigensolver_selfadjoint.cpp | 15 +- 4 files changed, 208 insertions(+), 126 deletions(-) diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 2878a1494..a77b96186 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -38,7 +38,7 @@ * * \tparam _MatrixType the type of the matrix of which we are computing the * eigendecomposition; this is expected to be an instantiation of the Matrix - * class template. Currently, only real matrices are supported. + * class template. * * A matrix \f$ A \f$ is selfadjoint if it equals its adjoint. For real * matrices, this means that the matrix is symmetric: it equals its @@ -55,6 +55,8 @@ * faster and more accurate than the general purpose eigenvalue algorithms * implemented in EigenSolver and ComplexEigenSolver. * + * Only the \b lower \b triangular \b part of the input matrix is referenced. + * * This class can also be used to solve the generalized eigenvalue problem * \f$ Av = \lambda Bv \f$. In this case, the matrix \f$ A \f$ should be * selfadjoint and the matrix \f$ B \f$ should be positive definite. @@ -117,7 +119,6 @@ template class SelfAdjointEigenSolver SelfAdjointEigenSolver() : m_eivec(), m_eivalues(), - m_tridiag(), m_subdiag(), m_isInitialized(false) { } @@ -138,7 +139,6 @@ template class SelfAdjointEigenSolver SelfAdjointEigenSolver(Index size) : m_eivec(size, size), m_eivalues(size), - m_tridiag(size), m_subdiag(size > 1 ? size - 1 : 1), m_isInitialized(false) {} @@ -146,7 +146,7 @@ template class SelfAdjointEigenSolver /** \brief Constructor; computes eigendecomposition of given matrix. * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are * computed. @@ -164,7 +164,6 @@ template class SelfAdjointEigenSolver SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), - m_tridiag(matrix.rows()), m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1), m_isInitialized(false) { @@ -174,7 +173,9 @@ template class SelfAdjointEigenSolver /** \brief Constructor; computes generalized eigendecomposition of given matrix pencil. * * \param[in] matA Selfadjoint matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] matB Positive-definite matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are * computed. @@ -196,7 +197,6 @@ template class SelfAdjointEigenSolver SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true) : m_eivec(matA.rows(), matA.cols()), m_eivalues(matA.cols()), - m_tridiag(matA.rows()), m_subdiag(matA.rows() > 1 ? matA.rows() - 1 : 1), m_isInitialized(false) { @@ -206,7 +206,7 @@ template class SelfAdjointEigenSolver /** \brief Computes eigendecomposition of given matrix. * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are * computed. @@ -240,7 +240,9 @@ template class SelfAdjointEigenSolver /** \brief Computes generalized eigendecomposition of given matrix pencil. * * \param[in] matA Selfadjoint matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] matB Positive-definite matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are * computed. @@ -386,7 +388,6 @@ template class SelfAdjointEigenSolver protected: MatrixType m_eivec; RealVectorType m_eivalues; - TridiagonalizationType m_tridiag; typename TridiagonalizationType::SubDiagonalType m_subdiag; ComputationInfo m_info; bool m_isInitialized; @@ -418,8 +419,6 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( assert(matrix.cols() == matrix.rows()); Index n = matrix.cols(); m_eivalues.resize(n,1); - if(computeEigenvectors) - m_eivec.resize(n,n); if(n==1) { @@ -432,12 +431,13 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( return *this; } - m_tridiag.compute(matrix); + // declare some aliases RealVectorType& diag = m_eivalues; - diag = m_tridiag.diagonal(); - m_subdiag = m_tridiag.subDiagonal(); - if (computeEigenvectors) - m_eivec = m_tridiag.matrixQ(); + MatrixType& mat = m_eivec; + + mat = matrix; + m_subdiag.resize(n-1); + ei_tridiagonalization_inplace(mat, diag, m_subdiag, computeEigenvectors); Index end = n-1; Index start = 0; @@ -487,7 +487,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( { std::swap(m_eivalues[i], m_eivalues[k+i]); if(computeEigenvectors) - m_eivec.col(i).swap(m_eivec.col(k+i)); + m_eivec.col(i).swap(m_eivec.col(k+i)); } } } @@ -507,7 +507,7 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors LLT cholB(matB); // compute C = inv(L) A inv(L') - MatrixType matC = matA; + MatrixType matC = matA.template selfadjointView(); cholB.matrixL().template solveInPlace(matC); cholB.matrixU().template solveInPlace(matC); diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index 62a607176..af970e94d 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -154,7 +154,7 @@ template class Tridiagonalization { m_matrix = matrix; m_hCoeffs.resize(matrix.rows()-1, 1); - _compute(m_matrix, m_hCoeffs); + ei_tridiagonalization_inplace(m_matrix, m_hCoeffs); m_isInitialized = true; return *this; } @@ -285,43 +285,6 @@ template class Tridiagonalization */ const SubDiagonalReturnType subDiagonal() const; - /** \brief Performs a full decomposition in place - * - * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal - * decomposition is to be computed. On output, the orthogonal matrix Q - * in the decomposition if \p extractQ is true. - * \param[out] diag The diagonal of the tridiagonal matrix T in the - * decomposition. - * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in - * the decomposition. - * \param[in] extractQ If true, the orthogonal matrix Q in the - * decomposition is computed and stored in \p mat. - * - * Compute the tridiagonal matrix of \p mat in place. The tridiagonal - * matrix T is passed to the output parameters \p diag and \p subdiag. If - * \p extractQ is true, then the orthogonal matrix Q is passed to \p mat. - * - * The vectors \p diag and \p subdiag are not resized. The function - * assumes that they are already of the correct size. The length of the - * vector \p diag should equal the number of rows in \p mat, and the - * length of the vector \p subdiag should be one left. - * - * This implementation contains an optimized path for real 3-by-3 matrices - * which is especially useful for plane fitting. - * - * \note Notwithstanding the name, the current implementation copies - * \p mat to a temporary matrix and uses that matrix to compute the - * decomposition. - * - * Example (this uses the same matrix as the example in - * Tridiagonalization(const MatrixType&)): - * \include Tridiagonalization_decomposeInPlace.cpp - * Output: \verbinclude Tridiagonalization_decomposeInPlace.out - * - * \sa Tridiagonalization(const MatrixType&), compute() - */ - static void decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ = true); - protected: static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs); @@ -368,21 +331,36 @@ Tridiagonalization::matrixT() const } /** \internal - * Performs a tridiagonal decomposition of \a matA in place. + * Performs a tridiagonal decomposition of the selfadjoint matrix \a matA in-place. * - * \param matA the input selfadjoint matrix - * \param hCoeffs returned Householder coefficients + * \param[in,out] matA On input the selfadjoint matrix. Only the \b lower triangular part is referenced. + * On output, the strict upper part is left unchanged, and the lower triangular part + * represents the T and Q matrices in packed format has detailed below. + * \param[out] hCoeffs returned Householder coefficients (see below) * - * The result is written in the lower triangular part of \a matA. + * On output, the tridiagonal selfadjoint matrix T is stored in the diagonal + * and lower sub-diagonal of the matrix \a matA. + * The unitary matrix Q is represented in a compact way as a product of + * Householder reflectors \f$ H_i \f$ such that: + * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. + * The Householder reflectors are defined as + * \f$ H_i = (I - h_i v_i v_i^T) \f$ + * where \f$ h_i = hCoeffs[i]\f$ is the \f$ i \f$th Householder coefficient and + * \f$ v_i \f$ is the Householder vector defined by + * \f$ v_i = [ 0, \ldots, 0, 1, matA(i+2,i), \ldots, matA(N-1,i) ]^T \f$. * * Implemented from Golub's "Matrix Computations", algorithm 8.3.1. * - * \sa packedMatrix() + * \sa Tridiagonalization::packedMatrix() */ -template -void Tridiagonalization::_compute(MatrixType& matA, CoeffVectorType& hCoeffs) +template +void ei_tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs) { - assert(matA.rows()==matA.cols()); + ei_assert(matA.rows()==matA.cols()); + ei_assert(matA.rows()==hCoeffs.size()+1); + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; Index n = matA.rows(); for (Index i = 0; i::_compute(MatrixType& matA, CoeffVectorType& } } -template -void Tridiagonalization::decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) +// forward declaration, implementation at the end of this file +template +struct ei_tridiagonalization_inplace_selector; + +/** \brief Performs a full tridiagonalization in place + * + * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal + * decomposition is to be computed. Only the lower triangular part referenced. + * The rest is left unchanged. On output, the orthogonal matrix Q + * in the decomposition if \p extractQ is true. + * \param[out] diag The diagonal of the tridiagonal matrix T in the + * decomposition. + * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in + * the decomposition. + * \param[in] extractQ If true, the orthogonal matrix Q in the + * decomposition is computed and stored in \p mat. + * + * Computes the tridiagonal decomposition of the selfadjoint matrix \p mat in place + * such that \f$ mat = Q T Q^* \f$ where \f$ Q \f$ is unitary and \f$ T \f$ a real + * symmetric tridiagonal matrix. + * + * The tridiagonal matrix T is passed to the output parameters \p diag and \p subdiag. If + * \p extractQ is true, then the orthogonal matrix Q is passed to \p mat. Otherwise the lower + * part of the matrix \p mat is destroyed. + * + * The vectors \p diag and \p subdiag are not resized. The function + * assumes that they are already of the correct size. The length of the + * vector \p diag should equal the number of rows in \p mat, and the + * length of the vector \p subdiag should be one left. + * + * This implementation contains an optimized path for 3-by-3 matrices + * which is especially useful for plane fitting. + * + * \note Currently, it requires two temporary vectors to hold the intermediate + * Householder coefficients, and to reconstruct the matrix Q from the Householder + * reflectors. + * + * Example (this uses the same matrix as the example in + * Tridiagonalization::Tridiagonalization(const MatrixType&)): + * \include Tridiagonalization_decomposeInPlace.cpp + * Output: \verbinclude Tridiagonalization_decomposeInPlace.out + * + * \sa class Tridiagonalization + */ +template +void ei_tridiagonalization_inplace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) { + typedef typename MatrixType::Index Index; Index n = mat.rows(); ei_assert(mat.cols()==n && diag.size()==n && subdiag.size()==n-1); - if (n==3 && (!NumTraits::IsComplex) ) - { - _decomposeInPlace3x3(mat, diag, subdiag, extractQ); - } - else - { - Tridiagonalization tridiag(mat); - diag = tridiag.diagonal(); - subdiag = tridiag.subDiagonal(); - if (extractQ) - mat = tridiag.matrixQ(); - } + ei_tridiagonalization_inplace_selector::run(mat, diag, subdiag, extractQ); } /** \internal - * Optimized path for 3x3 matrices. + * General full tridiagonalization + */ +template +struct ei_tridiagonalization_inplace_selector +{ + typedef typename Tridiagonalization::CoeffVectorType CoeffVectorType; + typedef typename Tridiagonalization::HouseholderSequenceType HouseholderSequenceType; + typedef typename MatrixType::Index Index; + template + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) + { + CoeffVectorType hCoeffs(mat.cols()-1); + ei_tridiagonalization_inplace(mat,hCoeffs); + diag = mat.diagonal().real(); + subdiag = mat.template diagonal<-1>().real(); + if(extractQ) + mat = HouseholderSequenceType(mat, hCoeffs.conjugate(), false, mat.rows() - 1, 1); + } +}; + +/** \internal + * Specialization for 3x3 matrices. * Especially useful for plane fitting. */ template -void Tridiagonalization::_decomposeInPlace3x3(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) +struct ei_tridiagonalization_inplace_selector { - diag[0] = ei_real(mat(0,0)); - RealScalar v1norm2 = ei_abs2(mat(0,2)); - if (ei_isMuchSmallerThan(v1norm2, RealScalar(1))) + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + template + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) { - diag[1] = ei_real(mat(1,1)); - diag[2] = ei_real(mat(2,2)); - subdiag[0] = ei_real(mat(0,1)); - subdiag[1] = ei_real(mat(1,2)); - if (extractQ) - mat.setIdentity(); - } - else - { - RealScalar beta = ei_sqrt(ei_abs2(mat(0,1))+v1norm2); - RealScalar invBeta = RealScalar(1)/beta; - Scalar m01 = mat(0,1) * invBeta; - Scalar m02 = mat(0,2) * invBeta; - Scalar q = RealScalar(2)*m01*mat(1,2) + m02*(mat(2,2) - mat(1,1)); - diag[1] = ei_real(mat(1,1) + m02*q); - diag[2] = ei_real(mat(2,2) - m02*q); - subdiag[0] = beta; - subdiag[1] = ei_real(mat(1,2) - m01 * q); - if (extractQ) + diag[0] = ei_real(mat(0,0)); + RealScalar v1norm2 = ei_abs2(mat(2,0)); + if (ei_isMuchSmallerThan(v1norm2, RealScalar(1))) { - mat(0,0) = 1; - mat(0,1) = 0; - mat(0,2) = 0; - mat(1,0) = 0; - mat(1,1) = m01; - mat(1,2) = m02; - mat(2,0) = 0; - mat(2,1) = m02; - mat(2,2) = -m01; + diag[1] = ei_real(mat(1,1)); + diag[2] = ei_real(mat(2,2)); + subdiag[0] = ei_real(mat(1,0)); + subdiag[1] = ei_real(mat(2,1)); + if (extractQ) + mat.setIdentity(); + } + else + { + RealScalar beta = ei_sqrt(ei_abs2(mat(1,0)) + v1norm2); + RealScalar invBeta = RealScalar(1)/beta; + Scalar m01 = ei_conj(mat(1,0)) * invBeta; + Scalar m02 = ei_conj(mat(2,0)) * invBeta; + Scalar q = RealScalar(2)*m01*ei_conj(mat(2,1)) + m02*(mat(2,2) - mat(1,1)); + diag[1] = ei_real(mat(1,1) + m02*q); + diag[2] = ei_real(mat(2,2) - m02*q); + subdiag[0] = beta; + subdiag[1] = ei_real(ei_conj(mat(2,1)) - m01 * q); + if (extractQ) + { + mat << 1, 0, 0, + 0, m01, m02, + 0, m02, -m01; + } } } -} +}; +/** \internal + * Trivial specialization for 1x1 matrices + */ +template +struct ei_tridiagonalization_inplace_selector +{ + typedef typename MatrixType::Scalar Scalar; + + template + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType&, bool extractQ) + { + diag(0,0) = ei_real(mat(0,0)); + if(extractQ) + mat(0,0) = Scalar(1); + } +}; #endif // EIGEN_TRIDIAGONALIZATION_H diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 835fe6a1c..b33fe5eeb 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -160,18 +160,45 @@ template class HouseholderS template void evalTo(DestType& dst) const { Index vecs = m_actualVectors; - dst.setIdentity(rows(), rows()); + // FIXME find a way to pass this temporary if the user want to Matrix temp(rows()); - for(Index k = vecs-1; k >= 0; --k) + AutoAlign|ColMajor, DestType::MaxRowsAtCompileTime, 1> temp(rows()); + if( ei_is_same_type::type,DestType>::ret + && ei_extract_data(dst) == ei_extract_data(m_vectors)) { - Index cornerSize = rows() - k - m_shift; - if(m_trans) - dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); - else - dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + // in-place + dst.diagonal().setOnes(); + dst.template triangularView().setZero(); + for(Index k = vecs-1; k >= 0; --k) + { + Index cornerSize = rows() - k - m_shift; + if(m_trans) + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + else + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + + // clear the off diagonal vector + dst.col(k).tail(rows()-k-1).setZero(); + } + // clear the remaining columns if needed + for(Index k = 0; k= 0; --k) + { + Index cornerSize = rows() - k - m_shift; + if(m_trans) + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + else + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + } } } diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 4f81132e7..2c2d5c985 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -50,10 +50,12 @@ template void selfadjointeigensolver(const MatrixType& m) MatrixType a = MatrixType::Random(rows,cols); MatrixType a1 = MatrixType::Random(rows,cols); MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; + symmA.template triangularView().setZero(); MatrixType b = MatrixType::Random(rows,cols); MatrixType b1 = MatrixType::Random(rows,cols); MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1; + symmB.template triangularView().setZero(); SelfAdjointEigenSolver eiSymm(symmA); // generalized eigen pb @@ -62,6 +64,9 @@ template void selfadjointeigensolver(const MatrixType& m) #ifdef HAS_GSL if (ei_is_same_type::ret) { + // restore symmA and symmB. + symmA = MatrixType(symmA.template selfadjointView()); + symmB = MatrixType(symmB.template selfadjointView()); typedef GslTraits Gsl; typename Gsl::Matrix gEvec=0, gSymmA=0, gSymmB=0; typename GslTraits::Vector gEval=0; @@ -103,7 +108,7 @@ template void selfadjointeigensolver(const MatrixType& m) #endif VERIFY_IS_EQUAL(eiSymm.info(), Success); - VERIFY((symmA * eiSymm.eigenvectors()).isApprox( + VERIFY((symmA.template selfadjointView() * eiSymm.eigenvectors()).isApprox( eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); VERIFY_IS_APPROX(symmA.template selfadjointView().eigenvalues(), eiSymm.eigenvalues()); @@ -113,12 +118,12 @@ template void selfadjointeigensolver(const MatrixType& m) // generalized eigen problem Ax = lBx VERIFY_IS_EQUAL(eiSymmGen.info(), Success); - VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( - symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); + VERIFY((symmA.template selfadjointView() * eiSymmGen.eigenvectors()).isApprox( + symmB.template selfadjointView() * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); MatrixType sqrtSymmA = eiSymm.operatorSqrt(); - VERIFY_IS_APPROX(symmA, sqrtSymmA*sqrtSymmA); - VERIFY_IS_APPROX(sqrtSymmA, symmA*eiSymm.operatorInverseSqrt()); + VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView()), sqrtSymmA*sqrtSymmA); + VERIFY_IS_APPROX(sqrtSymmA, symmA.template selfadjointView()*eiSymm.operatorInverseSqrt()); MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.template selfadjointView().operatorNorm(), RealScalar(1)); From 54235879a9818d1a96a894f1af03cc4aa5631660 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 10 Jun 2010 19:18:19 +0100 Subject: [PATCH 61/67] Make test slightly fuzzy to account for effect of extended precision. --- test/basicstuff.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp index 53b503f46..ddddb5985 100644 --- a/test/basicstuff.cpp +++ b/test/basicstuff.cpp @@ -138,7 +138,8 @@ template void basicStuffComplex(const MatrixType& m) VERIFY(ei_imag(s1)==ei_imag_ref(s1)); ei_real_ref(s1) = ei_real(s2); ei_imag_ref(s1) = ei_imag(s2); - VERIFY(s1==s2); + VERIFY(ei_isApprox(s1, s2, NumTraits::epsilon())); + // extended precision in Intel FPUs means that s1 == s2 in the line above is not guaranteed. RealMatrixType rm1 = RealMatrixType::Random(rows,cols), rm2 = RealMatrixType::Random(rows,cols); From 842b54fe8051fb334da98652e9ea47533c646c33 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 22:11:31 +0200 Subject: [PATCH 62/67] make the cache size mechanism future proof by adding level 2 parameters --- .../Core/products/GeneralBlockPanelKernel.h | 142 ++++++++++++------ Eigen/src/Core/products/GeneralMatrixMatrix.h | 4 +- test/product_large.cpp | 17 +++ 3 files changed, 112 insertions(+), 51 deletions(-) diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index 12934b3b9..be20be833 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -26,53 +26,66 @@ #define EIGEN_GENERAL_BLOCK_PANEL_H /** \internal */ -inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptrdiff_t* b=0, int scalar_size = 0) +inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptrdiff_t* b=0, std::ptrdiff_t* c=0, int scalar_size = 0) { const int nbScalarSizes = 12; static std::ptrdiff_t m_maxK[nbScalarSizes]; static std::ptrdiff_t m_maxM[nbScalarSizes]; - static std::ptrdiff_t m_cpuCacheSize = 0; - if(m_cpuCacheSize==0) + static std::ptrdiff_t m_maxN[nbScalarSizes]; + static std::ptrdiff_t m_l1CacheSize = 0; + static std::ptrdiff_t m_l2CacheSize = 0; + if(m_l1CacheSize==0) { // initialization - m_cpuCacheSize = EIGEN_TUNE_FOR_CPU_CACHE_SIZE; - ei_manage_caching_sizes(SetAction,&m_cpuCacheSize); + m_l1CacheSize = EIGEN_TUNE_FOR_CPU_CACHE_SIZE; + m_l2CacheSize = 32*EIGEN_TUNE_FOR_CPU_CACHE_SIZE; + ei_manage_caching_sizes(SetAction,&m_l1CacheSize, &m_l2CacheSize); } if(action==SetAction && scalar_size==0) { // set the cpu cache size and cache all block sizes from a global cache size in byte - ei_internal_assert(a!=0 && b==0); - m_cpuCacheSize = *a; + ei_internal_assert(a!=0 && b!=0 && c==0); + m_l1CacheSize = *a; + m_l2CacheSize = *b; int ss = 4; for(int i=0; i(m_cpuCacheSize/(64*ss))); + // Round the block size such that it is a multiple of 64/ss. + // This is to make sure the block size are multiple of the register block sizes. + // And in the worst case we ensure an even number. + std::ptrdiff_t rb = 64/ss; + if(rb==0) rb = 1; + m_maxK[i] = 4 * std::ptrdiff_t(ei_sqrt(m_l1CacheSize/(64*ss))); m_maxM[i] = 2 * m_maxK[i]; + m_maxN[i] = ((m_l2CacheSize / (2 * m_maxK[i] * ss))/4)*4; } } else if(action==SetAction && scalar_size!=0) { // set the block sizes for the given scalar type (represented as its size) - ei_internal_assert(a!=0 && b!=0); + ei_internal_assert(a!=0 && b!=0 && c!=0); int i = std::max((scalar_size>>2)-1,0); if(i>2),1),nbScalarSizes)-1; *a = m_maxK[i]; *b = m_maxM[i]; + *c = m_maxN[i]; } else { @@ -80,53 +93,82 @@ inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptr } } -/** \returns the currently set cpu cache size (in bytes) used to estimate the ideal blocking size parameters. - * \sa setL1CacheSize */ +/** \returns the currently set level 1 cpu cache size (in bytes) used to estimate the ideal blocking size parameters. + * \sa setCpuCacheSize */ inline std::ptrdiff_t l1CacheSize() { - std::ptrdiff_t ret; - ei_manage_caching_sizes(GetAction, &ret); - return ret; + std::ptrdiff_t l1, l2; + ei_manage_caching_sizes(GetAction, &l1, &l2); + return l1; } -/** Set the cpu cache size (in bytes) for blocking. - * This function also automatically set the blocking size parameters - * for each scalar type using the following formula: - * \code - * max_k = 4 * sqrt(cache_size/(64*sizeof(Scalar))); - * max_m = 2 * k; - * \endcode - * overwriting custom values set using the ei_setBlockingSizes function. - * - * \b Explanations: \n - * Let A * B be a m x k times k x n matrix product. Then Eigen's product yield - * L2 blocking on B with panels of size max_k x n, and L1 blocking on A, - * with blocks of size max_m x max_k. - * - * \sa ei_setBlockingSizes */ -inline void setL1CacheSize(std::ptrdiff_t cache_size) { ei_manage_caching_sizes(SetAction,&cache_size); } - -/** Set the blocking size parameters \a maxK and \a maxM for the scalar type \a Scalar. - * Note that in practice there is no distinction between scalar types of same size. - * - * See ei_setCpuCacheSize for an explanation about the meaning of maxK and maxM. - * - * \sa setL1CacheSize */ -template -void setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM) +/** \returns the currently set level 2 cpu cache size (in bytes) used to estimate the ideal blocking size parameters. + * \sa setCpuCacheSize */ +inline std::ptrdiff_t l2CacheSize() { - ei_manage_caching_sizes(SetAction,&maxK,&maxM,sizeof(Scalar)); + std::ptrdiff_t l1, l2; + ei_manage_caching_sizes(GetAction, &l1, &l2); + return l2; } -/** \returns in \a makK, \a maxM the blocking size parameters for the scalar type \a Scalar. +/** Set the cpu L1 and L2 cache sizes (in bytes). + * These values are use to adjust the size of the blocks + * for the algorithms working per blocks. * - * See ei_setCpuCacheSize for an explanation about the meaning of maxK and maxM. - * - * \sa setL1CacheSize */ -template -void getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM) + * This function also automatically set the blocking size parameters + * for each scalar type using the following rules: + * \code + * max_k = 4 * sqrt(l1/(64*sizeof(Scalar))); + * max_m = 2 * k; + * max_n = l2/(2*max_k*sizeof(Scalar)); + * \endcode + * overwriting custom values set using the setBlockingSizes function. + * + * See setBlockingSizes() for an explanation about the meaning of these parameters. + * + * \sa setBlockingSizes */ +inline void setCpuCacheSizes(std::ptrdiff_t l1, std::ptrdiff_t l2) { - ei_manage_caching_sizes(GetAction,&maxK,&maxM,sizeof(Scalar)); + ei_manage_caching_sizes(SetAction, &l1, &l2); +} + +/** \brief Set the blocking size parameters \a maxK, \a maxM and \a maxN for the scalar type \a Scalar. + * + * \param[in] maxK the size of the L1 and L2 blocks along the k dimension + * \param[in] maxM the size of the L1 blocks along the m dimension + * \param[in] maxN the size of the L2 blocks along the n dimension + * + * This function sets the blocking size parameters for matrix products and related algorithms. + * More precisely, let A * B be a m x k by k x n matrix product. Then Eigen's product like + * algorithms perform L2 blocking on B with horizontal panels of size maxK x maxN, + * and L1 blocking on A with blocks of size maxM x maxK. + * + * Theoretically, for best performances maxM should be closed to maxK and maxM * maxK should + * note exceed half of the L1 cache. Likewise, maxK * maxM should be smaller than the L2 cache. + * + * Note that in practice there is no distinction between scalar types of same size. + * + * \sa setCpuCacheSizes */ +template +void setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM, std::ptrdiff_t maxN) +{ + std::ptrdiff_t k, m, n; + typedef ei_product_blocking_traits Traits; + k = ((maxK)/4)*4; + m = ((maxM)/Traits::mr)*Traits::mr; + n = ((maxN)/Traits::nr)*Traits::nr; + ei_manage_caching_sizes(SetAction,&k,&m,&n,sizeof(Scalar)); +} + +/** \returns in \a makK, \a maxM and \a maxN the blocking size parameters for the scalar type \a Scalar. + * + * See setBlockingSizes for an explanation about the meaning of these parameters. + * + * \sa setBlockingSizes */ +template +void getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM, std::ptrdiff_t& maxN) +{ + ei_manage_caching_sizes(GetAction,&maxK,&maxM,&maxN,sizeof(Scalar)); } #ifdef EIGEN_HAS_FUSE_CJMADD diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 07721145a..801ed2792 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -77,9 +77,11 @@ static void run(Index rows, Index cols, Index depth, Index kc; // cache block size along the K direction Index mc; // cache block size along the M direction - getBlockingSizes(kc, mc); + Index nc; // cache block size along the N direction + getBlockingSizes(kc, mc, nc); kc = std::min(kc,depth); mc = std::min(mc,rows); + nc = std::min(nc,cols); ei_gemm_pack_rhs pack_rhs; ei_gemm_pack_lhs pack_lhs; diff --git a/test/product_large.cpp b/test/product_large.cpp index 519213236..0351d134c 100644 --- a/test/product_large.cpp +++ b/test/product_large.cpp @@ -49,5 +49,22 @@ void test_product_large() MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a; VERIFY_IS_APPROX((a = a * b), (c * b).eval()); } + + { + // check the functions to setup blocking sizes compile and do not segfault + // FIXME check they do what they are supposed to do !! + std::ptrdiff_t l1 = ei_random(10000,20000); + std::ptrdiff_t l2 = ei_random(1000000,2000000); + setCpuCacheSizes(l1,l2); + VERIFY(l1==l1CacheSize()); + VERIFY(l2==l2CacheSize()); + std::ptrdiff_t k1 = ei_random(10,100)*16; + std::ptrdiff_t m1 = ei_random(10,100)*16; + std::ptrdiff_t n1 = ei_random(10,100)*16; + setBlockingSizes(k1,m1,n1); + std::ptrdiff_t k, m, n; + getBlockingSizes(k,m,n); + VERIFY(k==k1 && m==m1 && n==n1); + } #endif } From fcab4c951d9e97bab3a2ad907984996b1c430b20 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 10 Jun 2010 21:26:23 +0100 Subject: [PATCH 63/67] Add line to prevent compiler warning on unused variables. --- test/unalignedcount.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unalignedcount.cpp b/test/unalignedcount.cpp index feff870e5..74eab8c6a 100644 --- a/test/unalignedcount.cpp +++ b/test/unalignedcount.cpp @@ -52,5 +52,8 @@ void test_unalignedcount() VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) -= b.segment(0,40), 10, 10, 10, 0); VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) *= 3.5, 10, 0, 10, 0); VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) /= 3.5, 10, 0, 10, 0); + #else + // The following line is to eliminate "variable not used" warnings + nb_load = nb_loadu = nb_store = nb_storeu = 0; #endif } From 5b192930b613aad28cf61efb680a8a8601ad63b0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 10 Jun 2010 23:30:15 +0200 Subject: [PATCH 64/67] add runtime API to control multithreading --- Eigen/src/Core/products/GeneralMatrixMatrix.h | 4 +- Eigen/src/Core/products/Parallelizer.h | 48 ++++++++++++++++++- bench/bench_gemm.cpp | 3 +- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 801ed2792..3513d118e 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -241,8 +241,8 @@ struct ei_gemm_functor Index sharedBlockBSize() const { - int maxKc, maxMc; - getBlockingSizes(maxKc,maxMc); + Index maxKc, maxMc, maxNc; + getBlockingSizes(maxKc, maxMc, maxNc); return std::min(maxKc,m_rhs.rows()) * m_rhs.cols(); } diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h index f7bdceab7..588f78b4c 100644 --- a/Eigen/src/Core/products/Parallelizer.h +++ b/Eigen/src/Core/products/Parallelizer.h @@ -25,6 +25,50 @@ #ifndef EIGEN_PARALLELIZER_H #define EIGEN_PARALLELIZER_H +/** \internal */ +inline void ei_manage_multi_threading(Action action, int* v) +{ + static int m_maxThreads = -1; + + if(action==SetAction) + { + ei_internal_assert(v!=0); + m_maxThreads = *v; + } + else if(action==GetAction) + { + ei_internal_assert(v!=0); + #ifdef EIGEN_HAS_OPENMP + if(m_maxThreads>0) + *v = m_maxThreads; + else + *v = omp_get_max_threads(); + #else + *v = 1; + #endif + } + else + { + ei_internal_assert(false); + } +} + +/** \returns the max number of threads reserved for Eigen + * \sa setNbThreads */ +inline int nbThreads() +{ + int ret; + ei_manage_multi_threading(GetAction, &ret); + return ret; +} + +/** Sets the max number of threads reserved for Eigen + * \sa nbThreads */ +inline void setNbThreads(int v) +{ + ei_manage_multi_threading(SetAction, &v); +} + template struct GemmParallelInfo { GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0), blockB(0) {} @@ -57,10 +101,10 @@ void ei_parallelize_gemm(const Functor& func, Index rows, Index cols) // 2- compute the maximal number of threads from the size of the product: // FIXME this has to be fine tuned - Index max_threads = std::max(1,rows / 32); + Index max_threads = std::max(1,rows / 32); // 3 - compute the number of threads we are going to use - Index threads = std::min(omp_get_max_threads(), max_threads); + Index threads = std::min(nbThreads(), max_threads); if(threads==1) return func(0,rows, 0,cols); diff --git a/bench/bench_gemm.cpp b/bench/bench_gemm.cpp index 5c55d4b7c..77cc420f4 100644 --- a/bench/bench_gemm.cpp +++ b/bench/bench_gemm.cpp @@ -112,7 +112,8 @@ int main(int argc, char ** argv) if(procs>1) { BenchTimer tmono; - omp_set_num_threads(1); + //omp_set_num_threads(1); + Eigen::setNbThreads(1); BENCH(tmono, tries, rep, gemm(a,b,c)); std::cout << "eigen mono cpu " << tmono.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(CPU_TIMER) << "s)\n"; std::cout << "eigen mono real " << tmono.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(REAL_TIMER) << "s)\n"; From cedea2aba459a131459af9fd69d4c42eef7394da Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 11 Jun 2010 07:59:59 +0200 Subject: [PATCH 65/67] Fixed warnings regarding missing assignment operator. --- unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h | 2 ++ unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 5d47f2cec..a4d827746 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -323,6 +323,8 @@ template struct MatrixExponentialReturnValue protected: const Derived& m_src; + private: + MatrixExponentialReturnValue& operator=(const MatrixExponentialReturnValue&); }; template diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h index be27c5037..c16341b17 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h @@ -116,9 +116,10 @@ class MatrixFunction } private: - const MatrixType& m_A; /**< \brief Reference to argument of matrix function. */ StemFunction *m_f; /**< \brief Stem function for matrix function under consideration */ + + MatrixFunction& operator=(const MatrixFunction&); }; @@ -182,6 +183,8 @@ class MatrixFunction * separation constant is set to 0.1, a value taken from the * paper by Davies and Higham. */ static const RealScalar separation() { return static_cast(0.1); } + + MatrixFunction& operator=(const MatrixFunction&); }; /** \brief Constructor. @@ -526,6 +529,8 @@ template class MatrixFunctionReturnValue private: const Derived& m_A; StemFunction *m_f; + + MatrixFunctionReturnValue& operator=(const MatrixFunctionReturnValue&); }; template From f48af91c7e9f75a9fb70367a56211387e9cdaeec Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 11 Jun 2010 08:08:12 +0200 Subject: [PATCH 66/67] For 1x1 matrices we really need to check the abs diff of the determinants. --- test/inverse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/inverse.cpp b/test/inverse.cpp index b75232727..108ce7bcb 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -78,7 +78,7 @@ template void inverse(const MatrixType& m) MatrixType m3 = v3*v3.transpose(), m4(rows,cols); m3.computeInverseAndDetWithCheck(m4, det, invertible); VERIFY( rows==1 ? invertible : !invertible ); - VERIFY_IS_MUCH_SMALLER_THAN(m3.determinant(), RealScalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(det-m3.determinant()), RealScalar(1)); m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); #endif From 00267e3a471a10e842f771de474f0dca6407a693 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 11 Jun 2010 12:13:29 +0200 Subject: [PATCH 67/67] Added some verbosity on failures in order to get an idea of what is goind wrong on GCC 4.3. --- test/stdlist.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/stdlist.cpp b/test/stdlist.cpp index 451c7752d..c612e634a 100644 --- a/test/stdlist.cpp +++ b/test/stdlist.cpp @@ -48,8 +48,13 @@ void check_stdlist_matrix(const MatrixType& m) ++wi; } - v.resize(21); + v.resize(21); v.back() = x; + if (!test_ei_isApprox(v.back(),x)) + { + std::cout << x << std::endl; + std::cout << v.back() << std::endl; + } VERIFY_IS_APPROX(v.back(), x); v.resize(22,y); VERIFY_IS_APPROX(v.back(), y); @@ -112,6 +117,11 @@ void check_stdlist_quaternion(const QuaternionType&) v.resize(22,y); VERIFY_IS_APPROX(v.back(), y); v.push_back(x); + if (!test_ei_isApprox(v.back(),x)) + { + std::cout << x << std::endl; + std::cout << v.back() << std::endl; + } VERIFY_IS_APPROX(v.back(), x); }