From 9005eb07884ff850b8801cfcb78d3533bace4342 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 31 Aug 2009 09:32:46 +0200 Subject: [PATCH 01/66] compilation fix in AmbiVector --- Eigen/src/Sparse/AmbiVector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Sparse/AmbiVector.h b/Eigen/src/Sparse/AmbiVector.h index 974e5c6c4..474626848 100644 --- a/Eigen/src/Sparse/AmbiVector.h +++ b/Eigen/src/Sparse/AmbiVector.h @@ -41,7 +41,7 @@ template class AmbiVector resize(size); } - void init(RealScalar estimatedDensity); + void init(double estimatedDensity); void init(int mode); int nonZeros() const; @@ -143,7 +143,7 @@ int AmbiVector::nonZeros() const } template -void AmbiVector::init(RealScalar estimatedDensity) +void AmbiVector::init(double estimatedDensity) { if (estimatedDensity>0.1) init(IsDense); From 99bfab6dcfec005bc2bc9291716fb3a7c5e7c21d Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 31 Aug 2009 13:47:32 +0200 Subject: [PATCH 02/66] Removed redundant assignment operators. --- Eigen/src/Core/MapBase.h | 5 ----- Eigen/src/Core/util/Macros.h | 6 +----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 9cb085b61..a8fded4a0 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -166,11 +166,6 @@ template class MapBase && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); } - Derived& operator=(const MapBase& other) - { - return Base::operator=(other); - } - using Base::operator=; using Base::operator*=; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index dc3b3ee0a..7fb10a315 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -251,11 +251,7 @@ using Base::operator =; \ using Base::operator +=; \ using Base::operator -=; \ using Base::operator *=; \ -using Base::operator /=; \ -EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ -{ \ - return Base::operator=(other); \ -} +using Base::operator /=; #define _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ From 32a9aee2861bbdeabc2c12d03d7a3337d4e691cd Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 31 Aug 2009 14:40:53 +0200 Subject: [PATCH 03/66] Added MSVC guards to assignment operators. --- Eigen/src/Core/MapBase.h | 7 +++++++ Eigen/src/Core/util/Macros.h | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index a8fded4a0..a0311ffcf 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -166,6 +166,13 @@ template class MapBase && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); } +#ifndef _MSC_VER + Derived& operator=(const MapBase& other) + { + return Base::operator=(other); + } +#endif + using Base::operator=; using Base::operator*=; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 7fb10a315..4e00df759 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -246,12 +246,25 @@ using Eigen::ei_cos; // needed to define it here as escaping characters in CMake add_definition's argument seems very problematic. #define EIGEN_DOCS_IO_FORMAT IOFormat(3, 0, " ", "\n", "", "") +#ifdef _MSC_VER #define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ using Base::operator =; \ using Base::operator +=; \ using Base::operator -=; \ using Base::operator *=; \ using Base::operator /=; +#else +#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ +using Base::operator =; \ +using Base::operator +=; \ +using Base::operator -=; \ +using Base::operator *=; \ +using Base::operator /=; \ +EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ +{ \ + return Base::operator=(other); \ +} +#endif #define _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ From 0a0a805569402b1761fbe6f046c1f2699636a91f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 31 Aug 2009 15:34:57 +0200 Subject: [PATCH 04/66] Fixed a cast warning in scaleAndAddTo. Fixed lazyness in umeyama. Added a few missing casts. --- Eigen/src/Core/Product.h | 4 ++-- Eigen/src/Geometry/Umeyama.h | 10 +++++----- test/product_trsm.cpp | 4 ++-- test/umeyama.cpp | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 71203a362..f4c8af6ea 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -259,8 +259,8 @@ class GeneralProduct template void scaleAndAddTo(Dest& dst, Scalar alpha) const { ei_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - ei_gemv_selector::ActualAccess>::run(*this, dst, alpha); + ei_gemv_selector::ActualAccess)>::run(*this, dst, alpha); } }; diff --git a/Eigen/src/Geometry/Umeyama.h b/Eigen/src/Geometry/Umeyama.h index 64c06fe66..7652aa92e 100644 --- a/Eigen/src/Geometry/Umeyama.h +++ b/Eigen/src/Geometry/Umeyama.h @@ -144,7 +144,7 @@ umeyama(const MatrixBase& src, const MatrixBase& dst, boo // const Scalar dst_var = dst_demean.rowwise().squaredNorm().sum() * one_over_n; // Eq. (38) - const MatrixType sigma = (one_over_n * dst_demean * src_demean.transpose()).lazy(); + const MatrixType sigma = one_over_n * dst_demean * src_demean.transpose(); SVD svd(sigma); @@ -160,14 +160,14 @@ umeyama(const MatrixBase& src, const MatrixBase& dst, boo int rank = 0; for (int i=0; i 0 ) { - Rt.block(0,0,m,m) = (svd.matrixU()*svd.matrixV().transpose()).lazy(); + Rt.block(0,0,m,m).noalias() = svd.matrixU()*svd.matrixV().transpose(); } else { const Scalar s = S(m-1); S(m-1) = -1; - Rt.block(0,0,m,m) = (svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose()).lazy(); + Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose(); S(m-1) = s; } } else { - Rt.block(0,0,m,m) = (svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose()).lazy(); + Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose(); } // Eq. (42) @@ -177,7 +177,7 @@ umeyama(const MatrixBase& src, const MatrixBase& dst, boo // Note that we first assign dst_mean to the destination so that there no need // for a temporary. Rt.col(m).start(m) = dst_mean; - Rt.col(m).start(m) -= (c*Rt.corner(TopLeft,m,m)*src_mean).lazy(); + Rt.col(m).start(m).noalias() -= c*Rt.corner(TopLeft,m,m)*src_mean; if (with_scaling) Rt.block(0,0,m,m) *= c; diff --git a/test/product_trsm.cpp b/test/product_trsm.cpp index 9f372df91..756034df9 100644 --- a/test/product_trsm.cpp +++ b/test/product_trsm.cpp @@ -40,8 +40,8 @@ template void trsm(int size,int cols) Matrix cmRhs(size,cols), ref(size,cols); Matrix rmRhs(size,cols); - cmLhs.setRandom(); cmLhs *= 0.1; cmLhs.diagonal().cwise() += 1; - rmLhs.setRandom(); rmLhs *= 0.1; rmLhs.diagonal().cwise() += 1; + cmLhs.setRandom(); cmLhs *= static_cast(0.1); cmLhs.diagonal().cwise() += static_cast(1); + rmLhs.setRandom(); rmLhs *= static_cast(0.1); rmLhs.diagonal().cwise() += static_cast(1); VERIFY_TRSM(cmLhs.conjugate().template triangularView(), cmRhs); VERIFY_TRSM(cmLhs .template triangularView(), cmRhs); diff --git a/test/umeyama.cpp b/test/umeyama.cpp index b6d394883..0999c59c9 100644 --- a/test/umeyama.cpp +++ b/test/umeyama.cpp @@ -127,7 +127,7 @@ void run_test(int dim, int num_elements) MatrixX src = MatrixX::Random(dim+1, num_elements); src.row(dim) = Matrix::Constant(num_elements, Scalar(1)); - MatrixX dst = (cR_t*src).lazy(); + MatrixX dst = cR_t*src; MatrixX cR_t_umeyama = umeyama(src.block(0,0,dim,num_elements), dst.block(0,0,dim,num_elements)); @@ -160,7 +160,7 @@ void run_fixed_size_test(int num_elements) MatrixX src = MatrixX::Random(dim+1, num_elements); src.row(dim) = Matrix::Constant(num_elements, Scalar(1)); - MatrixX dst = (cR_t*src).lazy(); + MatrixX dst = cR_t*src; Block src_block(src,0,0,dim,num_elements); Block dst_block(dst,0,0,dim,num_elements); From 27c9ecc50f2d6514a0cc570edecb982162fdca37 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 31 Aug 2009 16:41:13 +0200 Subject: [PATCH 05/66] fix copy/paste issue --- Eigen/src/Core/CwiseUnaryView.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 4785f01f4..4b7d87953 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -53,8 +53,7 @@ struct ei_traits > }; template -class CwiseUnaryView : ei_no_assignment_operator, - public MatrixBase > +class CwiseUnaryView : public MatrixBase > { public: From 095809edda92cb149cf3f558f2263a8dd3881da8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 31 Aug 2009 17:07:54 +0200 Subject: [PATCH 06/66] fix issue #45 and document the .data() and .stride() functions --- Eigen/src/Core/Block.h | 16 +++++++++++++++- Eigen/src/Core/MapBase.h | 20 +++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index cf7730170..42d6bc3c3 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -201,6 +201,13 @@ template && startCol >= 0 && blockCols >= 0 && startCol + blockCols <= matrix.cols()); } - inline int stride(void) const { return m_matrix.stride(); } + /** \sa MapBase::stride() */ + inline int stride() const + { + return ((!Base::IsVectorAtCompileTime) + || (BlockRows==1 && ((Flags&RowMajorBit)==0)) + || (BlockCols==1 && ((Flags&RowMajorBit)==RowMajorBit))) + ? m_matrix.stride() : 1; + } #ifndef __SUNPRO_CC // FIXME sunstudio is not friendly with the above friend... diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index a0311ffcf..404fa176e 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -62,7 +62,21 @@ template class MapBase inline int rows() const { return m_rows.value(); } inline int cols() const { return m_cols.value(); } + /** Returns the leading dimension (for matrices) or the increment (for vectors) to be used with data(). + * + * More precisely: + * - for a column major matrix it returns the number of elements between two successive columns + * - for a row major matrix it returns the number of elements between two successive rows + * - for a vector it returns the number of elements between two successive coefficients + * This function has to be used together with the MapBase::data() function. + * + * \sa MapBase::data() */ inline int stride() const { return derived().stride(); } + + /** Returns a pointer to the first coefficient of the matrix or vector. + * This function has to be used together with the stride() function. + * + * \sa MapBase::stride() */ inline const Scalar* data() const { return m_data; } template struct force_aligned_impl { @@ -167,9 +181,9 @@ template class MapBase } #ifndef _MSC_VER - Derived& operator=(const MapBase& other) - { - return Base::operator=(other); + Derived& operator=(const MapBase& other) + { + return Base::operator=(other); } #endif From bc7aec0ef5475984edc39f43fcb099af44993081 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 31 Aug 2009 17:24:38 +0200 Subject: [PATCH 07/66] ifdef removed from MapBase and warning disabled --- Eigen/src/Core/MapBase.h | 2 -- Eigen/src/Core/util/DisableMSVCWarnings.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 404fa176e..88a3fac1e 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -180,12 +180,10 @@ template class MapBase && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); } -#ifndef _MSC_VER Derived& operator=(const MapBase& other) { return Base::operator=(other); } -#endif using Base::operator=; using Base::operator*=; diff --git a/Eigen/src/Core/util/DisableMSVCWarnings.h b/Eigen/src/Core/util/DisableMSVCWarnings.h index 765ddecc5..ca8e245b3 100644 --- a/Eigen/src/Core/util/DisableMSVCWarnings.h +++ b/Eigen/src/Core/util/DisableMSVCWarnings.h @@ -1,5 +1,5 @@ #ifdef _MSC_VER #pragma warning( push ) - #pragma warning( disable : 4181 4244 4127 4211 4717 ) + #pragma warning( disable : 4181 4244 4127 4211 4522 4717 ) #endif From ab6eb6a1a49124b41b2764be98ac5b07a74a2a41 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 31 Aug 2009 17:29:37 +0200 Subject: [PATCH 08/66] Adaptions from .lazy() towards .noalias(). Added missing casts. --- Eigen/src/Cholesky/LDLT.h | 4 +- Eigen/src/Cholesky/LLT.h | 2 +- Eigen/src/QR/EigenSolver.h | 12 ++--- test/bandmatrix.cpp | 12 ++--- test/product.h | 12 ++--- test/product_symm.cpp | 2 +- .../src/MatrixFunctions/MatrixExponential.h | 44 +++++++++---------- unsupported/test/matrixExponential.cpp | 18 ++++---- 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index adca9fe2e..c8d92f3c0 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -218,8 +218,8 @@ LDLT& LDLT::compute(const MatrixType& a) int endSize = size - j - 1; if (endSize > 0) { - _temporary.end(endSize) = ( m_matrix.block(j+1,0, endSize, j) - * m_matrix.col(j).start(j).conjugate() ).lazy(); + _temporary.end(endSize).noalias() = m_matrix.block(j+1,0, endSize, j) + * m_matrix.col(j).start(j).conjugate(); m_matrix.row(j).end(endSize) = m_matrix.row(j).end(endSize).conjugate() - _temporary.end(endSize).transpose(); diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 3ce85b2d9..ec7b8123c 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -141,7 +141,7 @@ template<> struct ei_llt_inplace if (x<=RealScalar(0)) return false; mat.coeffRef(k,k) = x = ei_sqrt(x); - if (k>0 && rs>0) A21 -= (A20 * A10.adjoint()).lazy(); + if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); if (rs>0) A21 *= RealScalar(1)/x; } return true; diff --git a/Eigen/src/QR/EigenSolver.h b/Eigen/src/QR/EigenSolver.h index bd7a76c49..79d73db7e 100644 --- a/Eigen/src/QR/EigenSolver.h +++ b/Eigen/src/QR/EigenSolver.h @@ -244,11 +244,11 @@ void EigenSolver::orthes(MatrixType& matH, RealVectorType& ort) // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) int bSize = high-m+1; - matH.block(m, m, bSize, n-m) -= ((ort.segment(m, bSize)/h) - * (ort.segment(m, bSize).transpose() * matH.block(m, m, bSize, n-m))).lazy(); + matH.block(m, m, bSize, n-m).noalias() -= ((ort.segment(m, bSize)/h) + * (ort.segment(m, bSize).transpose() * matH.block(m, m, bSize, n-m))); - matH.block(0, m, high+1, bSize) -= ((matH.block(0, m, high+1, bSize) * ort.segment(m, bSize)) - * (ort.segment(m, bSize)/h).transpose()).lazy(); + matH.block(0, m, high+1, bSize).noalias() -= ((matH.block(0, m, high+1, bSize) * ort.segment(m, bSize)) + * (ort.segment(m, bSize)/h).transpose()); ort.coeffRef(m) = scale*ort.coeff(m); matH.coeffRef(m,m-1) = scale*g; @@ -265,8 +265,8 @@ void EigenSolver::orthes(MatrixType& matH, RealVectorType& ort) ort.segment(m+1, high-m) = matH.col(m-1).segment(m+1, high-m); int bSize = high-m+1; - m_eivec.block(m, m, bSize, bSize) += ( (ort.segment(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m))) - * (ort.segment(m, bSize).transpose() * m_eivec.block(m, m, bSize, bSize)) ).lazy(); + m_eivec.block(m, m, bSize, bSize).noalias() += ( (ort.segment(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m))) + * (ort.segment(m, bSize).transpose() * m_eivec.block(m, m, bSize, bSize)) ); } } } diff --git a/test/bandmatrix.cpp b/test/bandmatrix.cpp index f677e7b85..2bdc67e28 100644 --- a/test/bandmatrix.cpp +++ b/test/bandmatrix.cpp @@ -44,21 +44,21 @@ template void bandmatrix(const MatrixType& _m) dm1.diagonal().setConstant(123); for (int i=1; i<=m.supers();++i) { - m.diagonal(i).setConstant(i); - dm1.diagonal(i).setConstant(i); + m.diagonal(i).setConstant(static_cast(i)); + dm1.diagonal(i).setConstant(static_cast(i)); } for (int i=1; i<=m.subs();++i) { - m.diagonal(-i).setConstant(-i); - dm1.diagonal(-i).setConstant(-i); + m.diagonal(-i).setConstant(-static_cast(i)); + dm1.diagonal(-i).setConstant(-static_cast(i)); } //std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n\n\n"; VERIFY_IS_APPROX(dm1,m.toDense()); for (int i=0; i(i+1)); + dm1.col(i).setConstant(static_cast(i+1)); } int d = std::min(rows,cols); int a = std::max(0,cols-d-supers); diff --git a/test/product.h b/test/product.h index 157f6262b..40773ad90 100644 --- a/test/product.h +++ b/test/product.h @@ -81,7 +81,7 @@ template void product(const MatrixType& m) m3 = m1; m3 *= m1.transpose() * m2; VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2)); - VERIFY_IS_APPROX(m3, m1.lazy() * (m1.transpose()*m2)); + VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2)); // continue testing Product.h: distributivity VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2); @@ -109,26 +109,26 @@ template void product(const MatrixType& m) // test optimized operator+= path res = square; - res += (m1 * m2.transpose()).lazy(); + res.noalias() += m1 * m2.transpose(); VERIFY_IS_APPROX(res, square + m1 * m2.transpose()); if (NumTraits::HasFloatingPoint && std::min(rows,cols)>1) { VERIFY(areNotApprox(res,square + m2 * m1.transpose())); } vcres = vc2; - vcres += (m1.transpose() * v1).lazy(); + vcres.noalias() += m1.transpose() * v1; VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1); // test optimized operator-= path res = square; - res -= (m1 * m2.transpose()).lazy(); + res.noalias() -= m1 * m2.transpose(); VERIFY_IS_APPROX(res, square - (m1 * m2.transpose())); if (NumTraits::HasFloatingPoint && std::min(rows,cols)>1) { VERIFY(areNotApprox(res,square - m2 * m1.transpose())); } vcres = vc2; - vcres -= (m1.transpose() * v1).lazy(); + vcres.noalias() -= m1.transpose() * v1; VERIFY_IS_APPROX(vcres, vc2 - m1.transpose() * v1); tm1 = m1; @@ -145,7 +145,7 @@ template void product(const MatrixType& m) VERIFY_IS_APPROX(res, m1 * m2.transpose()); res2 = square2; - res2 += (m1.transpose() * m2).lazy(); + res2.noalias() += m1.transpose() * m2; VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2); if (NumTraits::HasFloatingPoint && std::min(rows,cols)>1) { diff --git a/test/product_symm.cpp b/test/product_symm.cpp index 1300928a2..cf0299c64 100644 --- a/test/product_symm.cpp +++ b/test/product_symm.cpp @@ -96,7 +96,7 @@ template void symm(int size = Size, in m2 = m1.template triangularView(); rhs13 = rhs12; - VERIFY_IS_APPROX(rhs12 += (s1 * ((m2.adjoint()).template selfadjointView() * (s2*rhs3).conjugate())).lazy(), + VERIFY_IS_APPROX(rhs12.noalias() += s1 * ((m2.adjoint()).template selfadjointView() * (s2*rhs3).conjugate()), rhs13 += (s1*m1.adjoint()) * (s2*rhs3).conjugate()); // test matrix * selfadjoint diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index dd25d7f3d..7d8777de7 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -90,9 +90,9 @@ namespace MatrixExponentialInternal { { typedef typename ei_traits::Scalar Scalar; const Scalar b[] = {120., 60., 12., 1.}; - M2 = (M * M).lazy(); + M2.noalias() = M * M; tmp = b[3]*M2 + b[1]*Id; - U = (M * tmp).lazy(); + U.noalias() = M * tmp; V = b[2]*M2 + b[0]*Id; } @@ -115,10 +115,10 @@ namespace MatrixExponentialInternal { { typedef typename ei_traits::Scalar Scalar; const Scalar b[] = {30240., 15120., 3360., 420., 30., 1.}; - M2 = (M * M).lazy(); - MatrixType M4 = (M2 * M2).lazy(); + M2.noalias() = M * M; + MatrixType M4 = M2 * M2; tmp = b[5]*M4 + b[3]*M2 + b[1]*Id; - U = (M * tmp).lazy(); + U.noalias() = M * tmp; V = b[4]*M4 + b[2]*M2 + b[0]*Id; } @@ -141,11 +141,11 @@ namespace MatrixExponentialInternal { { typedef typename ei_traits::Scalar Scalar; const Scalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.}; - M2 = (M * M).lazy(); - MatrixType M4 = (M2 * M2).lazy(); - MatrixType M6 = (M4 * M2).lazy(); + M2.noalias() = M * M; + MatrixType M4 = M2 * M2; + MatrixType M6 = M4 * M2; tmp = b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U = (M * tmp).lazy(); + U.noalias() = M * tmp; V = b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; } @@ -169,12 +169,12 @@ namespace MatrixExponentialInternal { typedef typename ei_traits::Scalar Scalar; const Scalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240., 2162160., 110880., 3960., 90., 1.}; - M2 = (M * M).lazy(); - MatrixType M4 = (M2 * M2).lazy(); - MatrixType M6 = (M4 * M2).lazy(); - MatrixType M8 = (M6 * M2).lazy(); + M2.noalias() = M * M; + MatrixType M4 = M2 * M2; + MatrixType M6 = M4 * M2; + MatrixType M8 = M6 * M2; tmp = b[9]*M8 + b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U = (M * tmp).lazy(); + U.noalias() = M * tmp; V = b[8]*M8 + b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; } @@ -199,15 +199,15 @@ namespace MatrixExponentialInternal { const Scalar b[] = {64764752532480000., 32382376266240000., 7771770303897600., 1187353796428800., 129060195264000., 10559470521600., 670442572800., 33522128640., 1323241920., 40840800., 960960., 16380., 182., 1.}; - M2 = (M * M).lazy(); - MatrixType M4 = (M2 * M2).lazy(); - MatrixType M6 = (M4 * M2).lazy(); + M2.noalias() = M * M; + MatrixType M4 = M2 * M2; + MatrixType M6 = M4 * M2; V = b[13]*M6 + b[11]*M4 + b[9]*M2; - tmp = (M6 * V).lazy(); + tmp.noalias() = M6 * V; tmp += b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U = (M * tmp).lazy(); + U.noalias() = M * tmp; tmp = b[12]*M6 + b[10]*M4 + b[8]*M2; - V = (M6 * tmp).lazy(); + V.noalias() = M6 * tmp; V += b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; } @@ -252,7 +252,7 @@ namespace MatrixExponentialInternal { } else if (l1norm < 1.880152677804762e+000) { pade5(M, Id, tmp1, tmp2, U, V); } else { - const float maxnorm = 3.925724783138660; + const float maxnorm = 3.925724783138660f; *squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm))); MatrixType A = M / std::pow(typename ei_traits::Scalar(2), *squarings); pade7(A, Id, tmp1, tmp2, U, V); @@ -294,7 +294,7 @@ namespace MatrixExponentialInternal { { MatrixType num, den, U, V; MatrixType Id = MatrixType::Identity(M.rows(), M.cols()); - float l1norm = M.cwise().abs().colwise().sum().maxCoeff(); + float l1norm = static_cast(M.cwise().abs().colwise().sum().maxCoeff()); int squarings; computeUV_selector::run(M, Id, num, den, U, V, l1norm, &squarings); num = U + V; // numerator of Pade approximant diff --git a/unsupported/test/matrixExponential.cpp b/unsupported/test/matrixExponential.cpp index 9a6c335d8..7d65a701a 100644 --- a/unsupported/test/matrixExponential.cpp +++ b/unsupported/test/matrixExponential.cpp @@ -43,10 +43,10 @@ void test2dRotation(double tol) A << 0, 1, -1, 0; for (int i=0; i<=20; i++) { - angle = pow(10, i / 5. - 2); + angle = static_cast(pow(10, i / 5. - 2)); B << cos(angle), sin(angle), -sin(angle), cos(angle); ei_matrix_exponential(angle*A, &C); - VERIFY(C.isApprox(B, tol)); + VERIFY(C.isApprox(B, static_cast(tol))); } } @@ -59,13 +59,13 @@ void test2dHyperbolicRotation(double tol) for (int i=0; i<=20; i++) { - angle = (i-10) / 2.0; + angle = static_cast((i-10) / 2.0); ch = std::cosh(angle); sh = std::sinh(angle); A << 0, angle*imagUnit, -angle*imagUnit, 0; B << ch, sh*imagUnit, -sh*imagUnit, ch; ei_matrix_exponential(A, &C); - VERIFY(C.isApprox(B, tol)); + VERIFY(C.isApprox(B, static_cast(tol))); } } @@ -77,13 +77,13 @@ void testPascal(double tol) Matrix A(size,size), B(size,size), C(size,size); A.setZero(); for (int i=0; i(i+1); B.setZero(); for (int i=0; i(binom(i,j)); ei_matrix_exponential(A, &C); - VERIFY(C.isApprox(B, tol)); + VERIFY(C.isApprox(B, static_cast(tol))); } } @@ -98,11 +98,13 @@ void randomTest(const MatrixType& m, double tol) MatrixType m1(rows, cols), m2(rows, cols), m3(rows, cols), identity = MatrixType::Identity(rows, rows); + typedef typename NumTraits::Scalar>::Real RealScalar; + for(int i = 0; i < g_repeat; i++) { m1 = MatrixType::Random(rows, cols); ei_matrix_exponential(m1, &m2); ei_matrix_exponential(-m1, &m3); - VERIFY(identity.isApprox(m2 * m3, tol)); + VERIFY(identity.isApprox(m2 * m3, static_cast(tol))); } } From a16599751f42242a3cbb80a00cddc983a6bb2675 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 31 Aug 2009 17:39:56 +0200 Subject: [PATCH 09/66] fix Matrix::stride for vectors, add a unit test for Block::stride and make use of it where it was relevant --- Eigen/src/Core/Matrix.h | 17 +++++-- .../Core/products/SelfadjointMatrixVector.h | 12 ++--- test/submatrices.cpp | 45 +++++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index f58424ba2..d0603871a 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -142,12 +142,21 @@ class Matrix EIGEN_STRONG_INLINE int rows() const { return m_storage.rows(); } EIGEN_STRONG_INLINE int cols() const { return m_storage.cols(); } - EIGEN_STRONG_INLINE int stride(void) const + /** Returns the leading dimension (for matrices) or the increment (for vectors) to be used with data(). + * + * More precisely: + * - for a column major matrix it returns the number of elements between two successive columns + * - for a row major matrix it returns the number of elements between two successive rows + * - for a vector it returns the number of elements between two successive coefficients + * This function has to be used together with the MapBase::data() function. + * + * \sa Matrix::data() */ + EIGEN_STRONG_INLINE int stride() const { - if(Flags & RowMajorBit) - return m_storage.cols(); + if(IsVectorAtCompileTime) + return 1; else - return m_storage.rows(); + return (Flags & RowMajorBit) ? m_storage.cols() : m_storage.rows(); } EIGEN_STRONG_INLINE const Scalar& coeff(int row, int col) const diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index c2c33d5b8..d5927307d 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -185,14 +185,14 @@ struct SelfadjointProductMatrix Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) * RhsBlasTraits::extractScalarFactor(m_rhs); - ei_assert((&dst.coeff(1))-(&dst.coeff(0))==1 && "not implemented yet"); + ei_assert(dst.stride()==1 && "not implemented yet"); ei_product_selfadjoint_vector::Flags&RowMajorBit, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)> ( - lhs.rows(), // size - &lhs.coeff(0,0), lhs.stride(), // lhs info - &rhs.coeff(0), (&rhs.coeff(1))-(&rhs.coeff(0)), // rhs info - &dst.coeffRef(0), // result info - actualAlpha // scale factor + lhs.rows(), // size + &lhs.coeff(0,0), lhs.stride(), // lhs info + &rhs.coeff(0), rhs.stride(), // rhs info + &dst.coeffRef(0), // result info + actualAlpha // scale factor ); } }; diff --git a/test/submatrices.cpp b/test/submatrices.cpp index a819cadc2..6fe86c281 100644 --- a/test/submatrices.cpp +++ b/test/submatrices.cpp @@ -170,6 +170,48 @@ template void submatrices(const MatrixType& m) VERIFY(ei_real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols)); } + +template +void compare_using_data_and_stride(const MatrixType& m) +{ + int rows = m.rows(); + int cols = m.cols(); + int size = m.size(); + int stride = m.stride(); + const typename MatrixType::Scalar* data = m.data(); + + for(int j=0;j +void data_and_stride(const MatrixType& m) +{ + int rows = m.rows(); + int cols = m.cols(); + + int r1 = ei_random(0,rows-1); + int r2 = ei_random(r1,rows-1); + int c1 = ei_random(0,cols-1); + int c2 = ei_random(c1,cols-1); + + MatrixType m1 = MatrixType::Random(rows, cols); + compare_using_data_and_stride(m1.block(r1, c1, r2-r1+1, c2-c1+1)); + compare_using_data_and_stride(m1.transpose().block(c1, r1, c2-c1+1, r2-r1+1)); + compare_using_data_and_stride(m1.row(r1)); + compare_using_data_and_stride(m1.col(c1)); + compare_using_data_and_stride(m1.row(r1).transpose()); + compare_using_data_and_stride(m1.col(c1).transpose()); +} + void test_submatrices() { for(int i = 0; i < g_repeat; i++) { @@ -179,5 +221,8 @@ void test_submatrices() CALL_SUBTEST( submatrices(MatrixXi(8, 12)) ); CALL_SUBTEST( submatrices(MatrixXcd(20, 20)) ); CALL_SUBTEST( submatrices(MatrixXf(20, 20)) ); + + CALL_SUBTEST( data_and_stride(MatrixXf(ei_random(5,50), ei_random(5,50))) ); + CALL_SUBTEST( data_and_stride(Matrix(ei_random(5,50), ei_random(5,50))) ); } } From 5339db61645daa2c829898cbd2c3310b5f80f7a8 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 31 Aug 2009 22:08:43 -0400 Subject: [PATCH 10/66] add VERIFY_IS_UNITARY --- test/main.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/main.h b/test/main.h index e3866c68b..8c84e525c 100644 --- a/test/main.h +++ b/test/main.h @@ -153,6 +153,8 @@ namespace Eigen #define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b)) #define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b)) +#define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a)) + #define CALL_SUBTEST(FUNC) do { \ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \ FUNC; \ @@ -227,6 +229,12 @@ inline bool test_ei_isMuchSmallerThan(const MatrixBase& m, return m.isMuchSmallerThan(s, test_precision::Scalar>()); } +template +inline bool test_isUnitary(const MatrixBase& m) +{ + return m.isUnitary(test_precision::Scalar>()); +} + template void createRandomMatrixOfRank(int desired_rank, int rows, int cols, MatrixType& m) { From 29c6b2452dbe82cd49aa701921f2fa5a20017cc0 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 31 Aug 2009 22:09:44 -0400 Subject: [PATCH 11/66] simplifications --- test/svd.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/svd.cpp b/test/svd.cpp index 2ccd94764..e6a32bd3f 100644 --- a/test/svd.cpp +++ b/test/svd.cpp @@ -41,15 +41,11 @@ template void svd(const MatrixType& m) Matrix::Random(rows,1); Matrix x(cols,1), x2(cols,1); - RealScalar largerEps = test_precision(); - if (ei_is_same_type::ret) - largerEps = 1e-3f; - { SVD svd(a); MatrixType sigma = MatrixType::Zero(rows,cols); MatrixType matU = MatrixType::Zero(rows,rows); - sigma.block(0,0,cols,cols) = svd.singularValues().asDiagonal(); + sigma.diagonal() = svd.singularValues(); matU = svd.matrixU(); VERIFY_IS_APPROX(a, matU * sigma * svd.matrixV().transpose()); } From 6e4e94ff3266f8d85adbfe6556e612a2ff9a7e68 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 31 Aug 2009 22:26:15 -0400 Subject: [PATCH 12/66] * JacobiSVD: - support complex numbers - big rewrite of the 2x2 kernel, much more robust * Jacobi: - fix weirdness in initial design, e.g. applyJacobiOnTheRight actually did the inverse transformation - fully support complex numbers - fix logic to decide whether to vectorize - remove several clumsy methods fix for complex numbers --- Eigen/SVD | 2 +- Eigen/src/Core/MatrixBase.h | 8 +- Eigen/src/Core/util/ForwardDeclarations.h | 1 + Eigen/src/Jacobi/Jacobi.h | 113 ++++------ Eigen/src/SVD/JacobiSVD.h | 258 ++++++++++++++++++++++ Eigen/src/SVD/JacobiSquareSVD.h | 169 -------------- test/CMakeLists.txt | 1 + test/jacobisvd.cpp | 105 +++++++++ 8 files changed, 416 insertions(+), 241 deletions(-) create mode 100644 Eigen/src/SVD/JacobiSVD.h delete mode 100644 Eigen/src/SVD/JacobiSquareSVD.h create mode 100644 test/jacobisvd.cpp diff --git a/Eigen/SVD b/Eigen/SVD index 625071a75..01582310c 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -23,7 +23,7 @@ namespace Eigen { */ #include "src/SVD/SVD.h" -#include "src/SVD/JacobiSquareSVD.h" +#include "src/SVD/JacobiSVD.h" } // namespace Eigen diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 7cb8853e6..9b1bf9e19 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -803,11 +803,11 @@ template class MatrixBase ///////// Jacobi module ///////// - void applyJacobiOnTheLeft(int p, int q, Scalar c, Scalar s); - void applyJacobiOnTheRight(int p, int q, Scalar c, Scalar s); + template + void applyJacobiOnTheLeft(int p, int q, JacobiScalar c, JacobiScalar s); + template + void applyJacobiOnTheRight(int p, int q, JacobiScalar c, JacobiScalar s); bool makeJacobi(int p, int q, Scalar *c, Scalar *s) const; - bool makeJacobiForAtA(int p, int q, Scalar *c, Scalar *s) const; - bool makeJacobiForAAt(int p, int q, Scalar *c, Scalar *s) const; #ifdef EIGEN_MATRIXBASE_PLUGIN #include EIGEN_MATRIXBASE_PLUGIN diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 414aaceca..d7dc61e73 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -120,6 +120,7 @@ template class HouseholderQR; template class ColPivotingHouseholderQR; template class FullPivotingHouseholderQR; template class SVD; +template class JacobiSVD; template class LLT; template class LDLT; diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 76f0800fe..96f08d54a 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -33,19 +33,20 @@ * * \sa MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() */ -template -void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, typename VectorX::Scalar c, typename VectorY::Scalar s); +template +void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, JacobiScalar c, JacobiScalar s); /** Applies a rotation in the plane defined by \a c, \a s to the rows \a p and \a q of \c *this. * More precisely, it computes B = J' * B, with J = [c s ; -s' c] and B = [ *this.row(p) ; *this.row(q) ] * \sa MatrixBase::applyJacobiOnTheRight(), ei_apply_rotation_in_the_plane() */ template -inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, Scalar c, Scalar s) +template +inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, JacobiScalar c, JacobiScalar s) { RowXpr x(row(p)); RowXpr y(row(q)); - ei_apply_rotation_in_the_plane(x, y, ei_conj(c), ei_conj(s)); + ei_apply_rotation_in_the_plane(x, y, c, s); } /** Applies a rotation in the plane defined by \a c, \a s to the columns \a p and \a q of \c *this. @@ -53,23 +54,25 @@ inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, Scalar c, Sc * \sa MatrixBase::applyJacobiOnTheLeft(), ei_apply_rotation_in_the_plane() */ template -inline void MatrixBase::applyJacobiOnTheRight(int p, int q, Scalar c, Scalar s) +template +inline void MatrixBase::applyJacobiOnTheRight(int p, int q, JacobiScalar c, JacobiScalar s) { ColXpr x(col(p)); ColXpr y(col(q)); - ei_apply_rotation_in_the_plane(x, y, c, s); + ei_apply_rotation_in_the_plane(x, y, c, -ei_conj(s)); } /** Computes the cosine-sine pair (\a c, \a s) such that its associated - * rotation \f$ J = ( \begin{array}{cc} c & s \\ -s' c \end{array} )\f$ + * rotation \f$ J = ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} )\f$ * applied to both the right and left of the 2x2 matrix * \f$ B = ( \begin{array}{cc} x & y \\ * & z \end{array} )\f$ yields - * a diagonal matrix A: \f$ A = J' B J \f$ + * a diagonal matrix A: \f$ A = J^* B J \f$ */ template -bool ei_makeJacobi(Scalar x, Scalar y, Scalar z, Scalar *c, Scalar *s) +bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTraits::Real z, Scalar *c, Scalar *s) { - if(y == 0) + typedef typename NumTraits::Real RealScalar; + if(y == Scalar(0)) { *c = Scalar(1); *s = Scalar(0); @@ -77,15 +80,21 @@ bool ei_makeJacobi(Scalar x, Scalar y, Scalar z, Scalar *c, Scalar *s) } else { - Scalar tau = (z - x) / (2 * y); - Scalar w = ei_sqrt(1 + ei_abs2(tau)); - Scalar t; + RealScalar tau = (x-z)/(RealScalar(2)*ei_abs(y)); + RealScalar w = ei_sqrt(ei_abs2(tau) + 1); + RealScalar t; if(tau>0) - t = Scalar(1) / (tau + w); + { + t = RealScalar(1) / (tau + w); + } else - t = Scalar(1) / (tau - w); - *c = Scalar(1) / ei_sqrt(1 + ei_abs2(t)); - *s = *c * t; + { + t = RealScalar(1) / (tau - w); + } + RealScalar sign_t = t > 0 ? 1 : -1; + RealScalar n = RealScalar(1) / ei_sqrt(ei_abs2(t)+1); + *s = - sign_t * (ei_conj(y) / ei_abs(y)) * ei_abs(t) * n; + *c = n; return true; } } @@ -93,41 +102,11 @@ bool ei_makeJacobi(Scalar x, Scalar y, Scalar z, Scalar *c, Scalar *s) template inline bool MatrixBase::makeJacobi(int p, int q, Scalar *c, Scalar *s) const { - return ei_makeJacobi(coeff(p,p), coeff(p,q), coeff(q,q), c, s); + return ei_makeJacobi(ei_real(coeff(p,p)), coeff(p,q), ei_real(coeff(q,q)), c, s); } -template -inline bool MatrixBase::makeJacobiForAtA(int p, int q, Scalar *c, Scalar *s) const -{ - return ei_makeJacobi(ei_abs2(coeff(p,p)) + ei_abs2(coeff(q,p)), - ei_conj(coeff(p,p))*coeff(p,q) + ei_conj(coeff(q,p))*coeff(q,q), - ei_abs2(coeff(p,q)) + ei_abs2(coeff(q,q)), - c,s); -} - -template -inline bool MatrixBase::makeJacobiForAAt(int p, int q, Scalar *c, Scalar *s) const -{ - return ei_makeJacobi(ei_abs2(coeff(p,p)) + ei_abs2(coeff(p,q)), - ei_conj(coeff(q,p))*coeff(p,p) + ei_conj(coeff(q,q))*coeff(p,q), - ei_abs2(coeff(q,p)) + ei_abs2(coeff(q,q)), - c,s); -} - -template -inline void ei_normalizeJacobi(Scalar *c, Scalar *s, const Scalar& x, const Scalar& y) -{ - Scalar a = x * *c - y * *s; - Scalar b = x * *s + y * *c; - if(ei_abs(b)>ei_abs(a)) { - Scalar x = *c; - *c = -*s; - *s = x; - } -} - -template -void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, typename VectorX::Scalar c, typename VectorY::Scalar s) +template +void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, JacobiScalar c, JacobiScalar s) { typedef typename VectorX::Scalar Scalar; ei_assert(_x.size() == _y.size()); @@ -138,7 +117,7 @@ void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& Scalar* EIGEN_RESTRICT x = &_x.coeffRef(0); Scalar* EIGEN_RESTRICT y = &_y.coeffRef(0); - if (incrx==1 && incry==1) + if((VectorX::Flags & VectorY::Flags & PacketAccessBit) && incrx==1 && incry==1) { // both vectors are sequentially stored in memory => vectorization typedef typename ei_packet_traits::type Packet; @@ -147,16 +126,16 @@ void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& int alignedStart = ei_alignmentOffset(y, size); int alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize; - const Packet pc = ei_pset1(c); - const Packet ps = ei_pset1(s); + const Packet pc = ei_pset1(Scalar(c)); + const Packet ps = ei_pset1(Scalar(s)); ei_conj_helper::IsComplex,false> cj; for(int i=0; i +// +// 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_JACOBISVD_H +#define EIGEN_JACOBISVD_H + +/** \ingroup SVD_Module + * \nonstableyet + * + * \class JacobiSVD + * + * \brief Jacobi SVD decomposition of a square matrix + * + * \param MatrixType the type of the matrix of which we are computing the SVD decomposition + * \param ComputeU whether the U matrix should be computed + * \param ComputeV whether the V matrix should be computed + * + * \sa MatrixBase::jacobiSvd() + */ +template class JacobiSVD +{ + private: + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + enum { + ComputeU = 1, + ComputeV = 1, + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + DiagSizeAtCompileTime = EIGEN_ENUM_MIN(RowsAtCompileTime,ColsAtCompileTime), + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + MaxDiagSizeAtCompileTime = EIGEN_ENUM_MIN(MaxRowsAtCompileTime,MaxColsAtCompileTime), + MatrixOptions = MatrixType::Options + }; + + typedef Matrix DummyMatrixType; + typedef typename ei_meta_if, + DummyMatrixType>::ret MatrixUType; + typedef typename ei_meta_if, + DummyMatrixType>::ret MatrixVType; + typedef Matrix SingularValuesType; + typedef Matrix RowType; + typedef Matrix ColType; + + public: + + JacobiSVD() : m_isInitialized(false) {} + + JacobiSVD(const MatrixType& matrix) : m_isInitialized(false) + { + compute(matrix); + } + + JacobiSVD& compute(const MatrixType& matrix); + + const MatrixUType& matrixU() const + { + ei_assert(m_isInitialized && "JacobiSVD is not initialized."); + return m_matrixU; + } + + const SingularValuesType& singularValues() const + { + ei_assert(m_isInitialized && "JacobiSVD is not initialized."); + return m_singularValues; + } + + const MatrixUType& matrixV() const + { + ei_assert(m_isInitialized && "JacobiSVD is not initialized."); + return m_matrixV; + } + + protected: + MatrixUType m_matrixU; + MatrixVType m_matrixV; + SingularValuesType m_singularValues; + bool m_isInitialized; + + template + friend struct ei_svd_precondition_2x2_block_to_be_real; +}; + +template::IsComplex> +struct ei_svd_precondition_2x2_block_to_be_real +{ + static void run(MatrixType&, JacobiSVD&, int, int) {} +}; + +template +struct ei_svd_precondition_2x2_block_to_be_real +{ + typedef JacobiSVD SVD; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + enum { ComputeU = SVD::ComputeU, ComputeV = SVD::ComputeV }; + static void run(MatrixType& work_matrix, JacobiSVD& svd, int p, int q) + { + Scalar c, s, z; + RealScalar n = ei_sqrt(ei_abs2(work_matrix.coeff(p,p)) + ei_abs2(work_matrix.coeff(q,p))); + if(n==0) + { + z = ei_abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); + work_matrix.row(p) *= z; + if(ComputeU) svd.m_matrixU.col(p) *= ei_conj(z); + z = ei_abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); + work_matrix.row(q) *= z; + if(ComputeU) svd.m_matrixU.col(q) *= ei_conj(z); + } + else + { + c = ei_conj(work_matrix.coeff(p,p)) / n; + s = work_matrix.coeff(q,p) / n; + work_matrix.applyJacobiOnTheLeft(p,q,c,s); + if(ComputeU) svd.m_matrixU.applyJacobiOnTheRight(p,q,ei_conj(c),-s); + if(work_matrix.coeff(p,q) != Scalar(0)) + { + Scalar z = ei_abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); + work_matrix.col(q) *= z; + if(ComputeV) svd.m_matrixV.col(q) *= z; + } + if(work_matrix.coeff(q,q) != Scalar(0)) + { + z = ei_abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); + work_matrix.row(q) *= z; + if(ComputeU) svd.m_matrixU.col(q) *= ei_conj(z); + } + } + } +}; + +template +void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, + RealScalar *c_left, RealScalar *s_left, + RealScalar *c_right, RealScalar *s_right) +{ + Matrix m; + m << ei_real(matrix.coeff(p,p)), ei_real(matrix.coeff(p,q)), + ei_real(matrix.coeff(q,p)), ei_real(matrix.coeff(q,q)); + RealScalar c1, s1; + RealScalar t = m.coeff(0,0) + m.coeff(1,1); + RealScalar d = m.coeff(1,0) - m.coeff(0,1); + if(t == RealScalar(0)) + { + c1 = 0; + s1 = d > 0 ? 1 : -1; + } + else + { + RealScalar u = d / t; + c1 = RealScalar(1) / ei_sqrt(1 + ei_abs2(u)); + s1 = c1 * u; + } + m.applyJacobiOnTheLeft(0,1,c1,s1); + RealScalar c2, s2; + m.makeJacobi(0,1,&c2,&s2); + *c_left = c1*c2 + s1*s2; + *s_left = s1*c2 - c1*s2; + *c_right = c2; + *s_right = s2; +} + +template +JacobiSVD& JacobiSVD::compute(const MatrixType& matrix) +{ + MatrixType work_matrix(matrix); + int size = matrix.rows(); + if(ComputeU) m_matrixU = MatrixUType::Identity(size,size); + if(ComputeV) m_matrixV = MatrixUType::Identity(size,size); + m_singularValues.resize(size); + const RealScalar precision = 2 * epsilon(); + +sweep_again: + for(int p = 1; p < size; ++p) + { + for(int q = 0; q < p; ++q) + { + if(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p))) + > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision) + { + ei_svd_precondition_2x2_block_to_be_real::run(work_matrix, *this, p, q); + + RealScalar c_left, s_left, c_right, s_right; + ei_real_2x2_jacobi_svd(work_matrix, p, q, &c_left, &s_left, &c_right, &s_right); + + work_matrix.applyJacobiOnTheLeft(p,q,c_left,s_left); + if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,c_left,-s_left); + + work_matrix.applyJacobiOnTheRight(p,q,c_right,s_right); + if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,c_right,s_right); + } + } + } + + RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff(); + RealScalar maxAllowedOffDiag = biggestOnDiag * precision; + for(int p = 0; p < size; ++p) + { + for(int q = 0; q < p; ++q) + if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) + goto sweep_again; + for(int q = p+1; q < size; ++q) + if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) + goto sweep_again; + } + + for(int i = 0; i < size; ++i) + { + RealScalar a = ei_abs(work_matrix.coeff(i,i)); + m_singularValues.coeffRef(i) = a; + if(ComputeU && (a!=RealScalar(0))) m_matrixU.col(i) *= work_matrix.coeff(i,i)/a; + } + + for(int i = 0; i < size; i++) + { + int pos; + m_singularValues.end(size-i).maxCoeff(&pos); + if(pos) + { + pos += i; + std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos)); + if(ComputeU) m_matrixU.col(pos).swap(m_matrixU.col(i)); + if(ComputeV) m_matrixV.col(pos).swap(m_matrixV.col(i)); + } + } + + m_isInitialized = true; + return *this; +} +#endif // EIGEN_JACOBISVD_H diff --git a/Eigen/src/SVD/JacobiSquareSVD.h b/Eigen/src/SVD/JacobiSquareSVD.h deleted file mode 100644 index f21c9edca..000000000 --- a/Eigen/src/SVD/JacobiSquareSVD.h +++ /dev/null @@ -1,169 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// 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_JACOBISQUARESVD_H -#define EIGEN_JACOBISQUARESVD_H - -/** \ingroup SVD_Module - * \nonstableyet - * - * \class JacobiSquareSVD - * - * \brief Jacobi SVD decomposition of a square matrix - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * \param ComputeU whether the U matrix should be computed - * \param ComputeV whether the V matrix should be computed - * - * \sa MatrixBase::jacobiSvd() - */ -template class JacobiSquareSVD -{ - private: - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - Options = MatrixType::Options - }; - - typedef Matrix DummyMatrixType; - typedef typename ei_meta_if, - DummyMatrixType>::ret MatrixUType; - typedef typename Diagonal::PlainMatrixType SingularValuesType; - typedef Matrix RowType; - typedef Matrix ColType; - - public: - - JacobiSquareSVD() : m_isInitialized(false) {} - - JacobiSquareSVD(const MatrixType& matrix) : m_isInitialized(false) - { - compute(matrix); - } - - JacobiSquareSVD& compute(const MatrixType& matrix); - - const MatrixUType& matrixU() const - { - ei_assert(m_isInitialized && "SVD is not initialized."); - return m_matrixU; - } - - const SingularValuesType& singularValues() const - { - ei_assert(m_isInitialized && "SVD is not initialized."); - return m_singularValues; - } - - const MatrixUType& matrixV() const - { - ei_assert(m_isInitialized && "SVD is not initialized."); - return m_matrixV; - } - - protected: - MatrixUType m_matrixU; - MatrixUType m_matrixV; - SingularValuesType m_singularValues; - bool m_isInitialized; -}; - -template -JacobiSquareSVD& JacobiSquareSVD::compute(const MatrixType& matrix) -{ - MatrixType work_matrix(matrix); - int size = matrix.rows(); - if(ComputeU) m_matrixU = MatrixUType::Identity(size,size); - if(ComputeV) m_matrixV = MatrixUType::Identity(size,size); - m_singularValues.resize(size); - const RealScalar precision = 2 * epsilon(); - -sweep_again: - for(int p = 1; p < size; ++p) - { - for(int q = 0; q < p; ++q) - { - Scalar c, s; - while(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p))) - > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision) - { - if(work_matrix.makeJacobiForAtA(p,q,&c,&s)) - { - work_matrix.applyJacobiOnTheRight(p,q,c,s); - if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,c,s); - } - if(work_matrix.makeJacobiForAAt(p,q,&c,&s)) - { - ei_normalizeJacobi(&c, &s, work_matrix.coeff(p,p), work_matrix.coeff(q,p)), - work_matrix.applyJacobiOnTheLeft(p,q,c,s); - if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,c,s); - } - } - } - } - - RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff(); - RealScalar maxAllowedOffDiag = biggestOnDiag * precision; - for(int p = 0; p < size; ++p) - { - for(int q = 0; q < p; ++q) - if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) - goto sweep_again; - for(int q = p+1; q < size; ++q) - if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) - goto sweep_again; - } - - m_singularValues = work_matrix.diagonal().cwise().abs(); - RealScalar biggestSingularValue = m_singularValues.maxCoeff(); - - for(int i = 0; i < size; ++i) - { - RealScalar a = ei_abs(work_matrix.coeff(i,i)); - m_singularValues.coeffRef(i) = a; - if(ComputeU && !ei_isMuchSmallerThan(a, biggestSingularValue)) m_matrixU.col(i) *= work_matrix.coeff(i,i)/a; - } - - for(int i = 0; i < size; i++) - { - int pos; - m_singularValues.end(size-i).maxCoeff(&pos); - if(pos) - { - pos += i; - std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos)); - if(ComputeU) m_matrixU.col(pos).swap(m_matrixU.col(i)); - if(ComputeV) m_matrixV.col(pos).swap(m_matrixV.col(i)); - } - } - - m_isInitialized = true; - return *this; -} -#endif // EIGEN_JACOBISQUARESVD_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fc43bbb1d..896392188 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -126,6 +126,7 @@ ei_add_test(qr_fullpivoting) ei_add_test(eigensolver_selfadjoint " " "${GSL_LIBRARIES}") ei_add_test(eigensolver_generic " " "${GSL_LIBRARIES}") ei_add_test(svd) +ei_add_test(jacobisvd ${EI_OFLAG}) ei_add_test(geo_orthomethods) ei_add_test(geo_homogeneous) ei_add_test(geo_quaternion) diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp new file mode 100644 index 000000000..9a4d79e45 --- /dev/null +++ b/test/jacobisvd.cpp @@ -0,0 +1,105 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2009 Benoit Jacob +// +// 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 . + +#include "main.h" +#include +#include + +template void svd(const MatrixType& m, bool pickrandom = true) +{ + int rows = m.rows(); + int cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix MatrixUType; + typedef Matrix MatrixVType; + typedef Matrix ColVectorType; + typedef Matrix InputVectorType; + + MatrixType a; + if(pickrandom) a = MatrixType::Random(rows,cols); + else a = m; + + JacobiSVD svd(a); + MatrixType sigma = MatrixType::Zero(rows,cols); + sigma.diagonal() = svd.singularValues().template cast(); + MatrixUType u = svd.matrixU(); + MatrixVType v = svd.matrixV(); + + VERIFY_IS_APPROX(a, u * sigma * v.adjoint()); + VERIFY_IS_UNITARY(u); + VERIFY_IS_UNITARY(v); +} + +template void svd_verify_assert() +{ + MatrixType tmp; + + SVD svd; + //VERIFY_RAISES_ASSERT(svd.solve(tmp, &tmp)) + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.singularValues()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + /*VERIFY_RAISES_ASSERT(svd.computeUnitaryPositive(&tmp,&tmp)) + VERIFY_RAISES_ASSERT(svd.computePositiveUnitary(&tmp,&tmp)) + VERIFY_RAISES_ASSERT(svd.computeRotationScaling(&tmp,&tmp)) + VERIFY_RAISES_ASSERT(svd.computeScalingRotation(&tmp,&tmp))*/ +} + +void test_jacobisvd() +{ + for(int i = 0; i < g_repeat; i++) { + Matrix2cd m; + m << 0, 1, + 0, 1; + CALL_SUBTEST( svd(m, false) ); + m << 1, 0, + 1, 0; + CALL_SUBTEST( svd(m, false) ); + Matrix2d n; + n << 1, 1, + 1, -1; + CALL_SUBTEST( svd(n, false) ); + CALL_SUBTEST( svd(Matrix3f()) ); + CALL_SUBTEST( svd(Matrix4d()) ); + CALL_SUBTEST( svd(MatrixXf(50,50)) ); +// CALL_SUBTEST( svd(MatrixXd(14,7)) ); + CALL_SUBTEST( svd(MatrixXcf(3,3)) ); + CALL_SUBTEST( svd(MatrixXd(30,30)) ); + } + CALL_SUBTEST( svd(MatrixXf(200,200)) ); + CALL_SUBTEST( svd(MatrixXcd(100,100)) ); + + CALL_SUBTEST( svd_verify_assert() ); + CALL_SUBTEST( svd_verify_assert() ); + CALL_SUBTEST( svd_verify_assert() ); + CALL_SUBTEST( svd_verify_assert() ); +} From 32f95ec2670a287234d7f614a20062e7d8499906 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 1 Sep 2009 10:50:54 +0100 Subject: [PATCH 13/66] Bug fix in MatrixExponential.h Initialize matrices for intermediate results to correct dimension --- unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 7d8777de7..bf5b79955 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -292,7 +292,10 @@ namespace MatrixExponentialInternal { template void compute(const MatrixType &M, MatrixType* result) { - MatrixType num, den, U, V; + MatrixType num(M.rows(), M.cols()); + MatrixType den(M.rows(), M.cols()); + MatrixType U(M.rows(), M.cols()); + MatrixType V(M.rows(), M.cols()); MatrixType Id = MatrixType::Identity(M.rows(), M.cols()); float l1norm = static_cast(M.cwise().abs().colwise().sum().maxCoeff()); int squarings; From 8392373d960c088b076b125775ccfc6a91f7d25e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Sep 2009 13:18:03 +0200 Subject: [PATCH 14/66] add a JacobiRotation class wrapping the cosine-sine pair with some convenient features (transpose, adjoint, product) --- Eigen/src/Core/MatrixBase.h | 6 +- Eigen/src/Core/util/ForwardDeclarations.h | 1 + Eigen/src/Jacobi/Jacobi.h | 120 +++++++++++++++------- Eigen/src/SVD/JacobiSVD.h | 73 +++++++------ 4 files changed, 123 insertions(+), 77 deletions(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 9b1bf9e19..c2945ab46 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -804,10 +804,10 @@ template class MatrixBase ///////// Jacobi module ///////// template - void applyJacobiOnTheLeft(int p, int q, JacobiScalar c, JacobiScalar s); + void applyJacobiOnTheLeft(int p, int q, const JacobiRotation& j); template - void applyJacobiOnTheRight(int p, int q, JacobiScalar c, JacobiScalar s); - bool makeJacobi(int p, int q, Scalar *c, Scalar *s) const; + void applyJacobiOnTheRight(int p, int q, const JacobiRotation& j); + bool makeJacobi(int p, int q, JacobiRotation *j) const; #ifdef EIGEN_MATRIXBASE_PLUGIN #include EIGEN_MATRIXBASE_PLUGIN diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index d7dc61e73..18d3af7c5 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -123,6 +123,7 @@ template class SVD; template class JacobiSVD; template class LLT; template class LDLT; +template class JacobiRotation; // Geometry module: template class RotationBase; diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 96f08d54a..24fb7e782 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -26,56 +26,98 @@ #ifndef EIGEN_JACOBI_H #define EIGEN_JACOBI_H -/** Applies the counter clock wise 2D rotation of angle \c theta given by its - * cosine \a c and sine \a s to the set of 2D vectors of cordinates \a x and \a y: - * \f$ x = c x - s' y \f$ - * \f$ y = s x + c y \f$ +/** \ingroup Jacobi + * \class JacobiRotation + * \brief Represents a rotation in the plane from a cosine-sine pair. + * + * This class represents a Jacobi rotation which is also known as a Givens rotation. + * This is a 2D clock-wise rotation in the plane \c J of angle \f$ \theta \f$ defined by + * its cosine \c c and sine \c s as follow: + * \f$ J = \left ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} \right ) \f$ + * + * \sa MatrixBase::makeJacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() + */ +template class JacobiRotation +{ + public: + /** Default constructor without any initialization. */ + JacobiRotation() {} + + /** Construct a Jacobi rotation from a cosine-sine pair (\a c, \c s). */ + JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {} + + Scalar& c() { return m_c; } + Scalar c() const { return m_c; } + Scalar& s() { return m_s; } + Scalar s() const { return m_s; } + + /** Concatenates two Jacobi rotation */ + JacobiRotation operator*(const JacobiRotation& other) + { + return JacobiRotation(m_c * other.m_c - ei_conj(m_s) * other.m_s, + ei_conj(m_c * ei_conj(other.m_s) + ei_conj(m_s) * ei_conj(other.m_c))); + } + + /** Returns the transposed transformation */ + JacobiRotation transpose() const { return JacobiRotation(m_c, -ei_conj(m_s)); } + + /** Returns the adjoint transformation */ + JacobiRotation adjoint() const { return JacobiRotation(ei_conj(m_c), -m_s); } + + protected: + Scalar m_c, m_s; +}; + +/** Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: + * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$ * * \sa MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() */ template -void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, JacobiScalar c, JacobiScalar s); +void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation& j); -/** Applies a rotation in the plane defined by \a c, \a s to the rows \a p and \a q of \c *this. - * More precisely, it computes B = J' * B, with J = [c s ; -s' c] and B = [ *this.row(p) ; *this.row(q) ] - * \sa MatrixBase::applyJacobiOnTheRight(), ei_apply_rotation_in_the_plane() +/** Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B, + * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$. + * + * \sa class JacobiRotation, MatrixBase::applyJacobiOnTheRight(), ei_apply_rotation_in_the_plane() */ template template -inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, JacobiScalar c, JacobiScalar s) +inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, const JacobiRotation& j) { RowXpr x(row(p)); RowXpr y(row(q)); - ei_apply_rotation_in_the_plane(x, y, c, s); + ei_apply_rotation_in_the_plane(x, y, j); } -/** Applies a rotation in the plane defined by \a c, \a s to the columns \a p and \a q of \c *this. - * More precisely, it computes B = B * J, with J = [c s ; -s' c] and B = [ *this.col(p) ; *this.col(q) ] - * \sa MatrixBase::applyJacobiOnTheLeft(), ei_apply_rotation_in_the_plane() +/** Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J + * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$. + * + * \sa class JacobiRotation, MatrixBase::applyJacobiOnTheLeft(), ei_apply_rotation_in_the_plane() */ template template -inline void MatrixBase::applyJacobiOnTheRight(int p, int q, JacobiScalar c, JacobiScalar s) +inline void MatrixBase::applyJacobiOnTheRight(int p, int q, const JacobiRotation& j) { ColXpr x(col(p)); ColXpr y(col(q)); - ei_apply_rotation_in_the_plane(x, y, c, -ei_conj(s)); + ei_apply_rotation_in_the_plane(x, y, j.transpose()); } -/** Computes the cosine-sine pair (\a c, \a s) such that its associated - * rotation \f$ J = ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} )\f$ - * applied to both the right and left of the 2x2 matrix - * \f$ B = ( \begin{array}{cc} x & y \\ * & z \end{array} )\f$ yields - * a diagonal matrix A: \f$ A = J^* B J \f$ +/** Computes the Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix + * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields + * a diagonal matrix \f$ A = J^* B J \f$ + * + * \sa MatrixBase::makeJacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() */ template -bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTraits::Real z, Scalar *c, Scalar *s) +bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTraits::Real z, JacobiRotation *j) { typedef typename NumTraits::Real RealScalar; if(y == Scalar(0)) { - *c = Scalar(1); - *s = Scalar(0); + j->c() = Scalar(1); + j->s() = Scalar(0); return false; } else @@ -93,20 +135,26 @@ bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTra } RealScalar sign_t = t > 0 ? 1 : -1; RealScalar n = RealScalar(1) / ei_sqrt(ei_abs2(t)+1); - *s = - sign_t * (ei_conj(y) / ei_abs(y)) * ei_abs(t) * n; - *c = n; + j->s() = - sign_t * (ei_conj(y) / ei_abs(y)) * ei_abs(t) * n; + j->c() = n; return true; } } +/** Computes the Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix + * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ * & \text{this}_{qq} \end{array} \right )\f$ yields + * a diagonal matrix \f$ A = J^* B J \f$ + * + * \sa MatrixBase::ei_make_jacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() + */ template -inline bool MatrixBase::makeJacobi(int p, int q, Scalar *c, Scalar *s) const +inline bool MatrixBase::makeJacobi(int p, int q, JacobiRotation *j) const { - return ei_makeJacobi(ei_real(coeff(p,p)), coeff(p,q), ei_real(coeff(q,q)), c, s); + return ei_makeJacobi(ei_real(coeff(p,p)), coeff(p,q), ei_real(coeff(q,q)), j); } template -void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, JacobiScalar c, JacobiScalar s) +void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation& j) { typedef typename VectorX::Scalar Scalar; ei_assert(_x.size() == _y.size()); @@ -126,16 +174,16 @@ void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& int alignedStart = ei_alignmentOffset(y, size); int alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize; - const Packet pc = ei_pset1(Scalar(c)); - const Packet ps = ei_pset1(Scalar(s)); + const Packet pc = ei_pset1(Scalar(j.c())); + const Packet ps = ei_pset1(Scalar(j.s())); ei_conj_helper::IsComplex,false> cj; for(int i=0; i class JacobiSVD MaxDiagSizeAtCompileTime = EIGEN_ENUM_MIN(MaxRowsAtCompileTime,MaxColsAtCompileTime), MatrixOptions = MatrixType::Options }; - + typedef Matrix DummyMatrixType; typedef typename ei_meta_if class JacobiSVD JacobiSVD() : m_isInitialized(false) {} - JacobiSVD(const MatrixType& matrix) : m_isInitialized(false) + JacobiSVD(const MatrixType& matrix) : m_isInitialized(false) { compute(matrix); } - + JacobiSVD& compute(const MatrixType& matrix); - + const MatrixUType& matrixU() const { ei_assert(m_isInitialized && "JacobiSVD is not initialized."); @@ -103,7 +103,7 @@ template class JacobiSVD MatrixVType m_matrixV; SingularValuesType m_singularValues; bool m_isInitialized; - + template friend struct ei_svd_precondition_2x2_block_to_be_real; }; @@ -120,11 +120,12 @@ struct ei_svd_precondition_2x2_block_to_be_real typedef JacobiSVD SVD; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - + enum { ComputeU = SVD::ComputeU, ComputeV = SVD::ComputeV }; static void run(MatrixType& work_matrix, JacobiSVD& svd, int p, int q) { - Scalar c, s, z; + Scalar z; + JacobiRotation rot; RealScalar n = ei_sqrt(ei_abs2(work_matrix.coeff(p,p)) + ei_abs2(work_matrix.coeff(q,p))); if(n==0) { @@ -137,10 +138,10 @@ struct ei_svd_precondition_2x2_block_to_be_real } else { - c = ei_conj(work_matrix.coeff(p,p)) / n; - s = work_matrix.coeff(q,p) / n; - work_matrix.applyJacobiOnTheLeft(p,q,c,s); - if(ComputeU) svd.m_matrixU.applyJacobiOnTheRight(p,q,ei_conj(c),-s); + rot.c() = ei_conj(work_matrix.coeff(p,p)) / n; + rot.s() = work_matrix.coeff(q,p) / n; + work_matrix.applyJacobiOnTheLeft(p,q,rot); + if(ComputeU) svd.m_matrixU.applyJacobiOnTheRight(p,q,rot.adjoint()); if(work_matrix.coeff(p,q) != Scalar(0)) { Scalar z = ei_abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); @@ -154,38 +155,34 @@ struct ei_svd_precondition_2x2_block_to_be_real if(ComputeU) svd.m_matrixU.col(q) *= ei_conj(z); } } - } + } }; template void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, - RealScalar *c_left, RealScalar *s_left, - RealScalar *c_right, RealScalar *s_right) + JacobiRotation *j_left, + JacobiRotation *j_right) { Matrix m; m << ei_real(matrix.coeff(p,p)), ei_real(matrix.coeff(p,q)), - ei_real(matrix.coeff(q,p)), ei_real(matrix.coeff(q,q)); - RealScalar c1, s1; + ei_real(matrix.coeff(q,p)), ei_real(matrix.coeff(q,q)); + JacobiRotation rot1; RealScalar t = m.coeff(0,0) + m.coeff(1,1); RealScalar d = m.coeff(1,0) - m.coeff(0,1); if(t == RealScalar(0)) { - c1 = 0; - s1 = d > 0 ? 1 : -1; + rot1.c() = 0; + rot1.s() = d > 0 ? 1 : -1; } else { RealScalar u = d / t; - c1 = RealScalar(1) / ei_sqrt(1 + ei_abs2(u)); - s1 = c1 * u; + rot1.c() = RealScalar(1) / ei_sqrt(1 + ei_abs2(u)); + rot1.s() = rot1.c() * u; } - m.applyJacobiOnTheLeft(0,1,c1,s1); - RealScalar c2, s2; - m.makeJacobi(0,1,&c2,&s2); - *c_left = c1*c2 + s1*s2; - *s_left = s1*c2 - c1*s2; - *c_right = c2; - *s_right = s2; + m.applyJacobiOnTheLeft(0,1,rot1); + m.makeJacobi(0,1,j_right); + *j_left = rot1 * j_right->transpose(); } template @@ -208,18 +205,18 @@ sweep_again: { ei_svd_precondition_2x2_block_to_be_real::run(work_matrix, *this, p, q); - RealScalar c_left, s_left, c_right, s_right; - ei_real_2x2_jacobi_svd(work_matrix, p, q, &c_left, &s_left, &c_right, &s_right); - - work_matrix.applyJacobiOnTheLeft(p,q,c_left,s_left); - if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,c_left,-s_left); - - work_matrix.applyJacobiOnTheRight(p,q,c_right,s_right); - if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,c_right,s_right); + JacobiRotation j_left, j_right; + ei_real_2x2_jacobi_svd(work_matrix, p, q, &j_left, &j_right); + + work_matrix.applyJacobiOnTheLeft(p,q,j_left); + if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,j_left.transpose()); + + work_matrix.applyJacobiOnTheRight(p,q,j_right); + if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,j_right); } } } - + RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff(); RealScalar maxAllowedOffDiag = biggestOnDiag * precision; for(int p = 0; p < size; ++p) @@ -231,7 +228,7 @@ sweep_again: if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) goto sweep_again; } - + for(int i = 0; i < size; ++i) { RealScalar a = ei_abs(work_matrix.coeff(i,i)); @@ -251,7 +248,7 @@ sweep_again: if(ComputeV) m_matrixV.col(pos).swap(m_matrixV.col(i)); } } - + m_isInitialized = true; return *this; } From 1e7a9ea70a35a2a375d9f1283f62a4e7feb7f933 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Sep 2009 13:35:44 +0200 Subject: [PATCH 15/66] fix issue #47: now m.noalias() = XXX properly resize m if needed --- Eigen/src/Core/Matrix.h | 10 +++++++++- test/product_extra.cpp | 21 +++++++------------- test/product_notemporary.cpp | 37 ++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index d0603871a..53d10fd31 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -338,7 +338,15 @@ class Matrix */ EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { - return _set(other); + return _set(other); + } + + /** \sa MatrixBase::lazyAssign() */ + template + EIGEN_STRONG_INLINE Matrix& lazyAssign(const MatrixBase& other) + { + _resize_to_match(other); + return Base::lazyAssign(other.derived()); } template diff --git a/test/product_extra.cpp b/test/product_extra.cpp index 213dbced6..2eae73231 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -59,16 +59,13 @@ template void product_extra(const MatrixType& m) // r0 = ei_random(0,rows/2-1), // r1 = ei_random(rows/2,rows); - // all the expressions in this test should be compiled as a single matrix product - // TODO: add internal checks to verify that - - VERIFY_IS_APPROX(m3 = (m1 * m2.adjoint()).lazy(), m1 * m2.adjoint().eval()); - VERIFY_IS_APPROX(m3 = (m1.adjoint() * square.adjoint()).lazy(), m1.adjoint().eval() * square.adjoint().eval()); - VERIFY_IS_APPROX(m3 = (m1.adjoint() * m2).lazy(), m1.adjoint().eval() * m2); - VERIFY_IS_APPROX(m3 = ((s1 * m1.adjoint()) * m2).lazy(), (s1 * m1.adjoint()).eval() * m2); - VERIFY_IS_APPROX(m3 = ((- m1.adjoint() * s1) * (s3 * m2)).lazy(), (- m1.adjoint() * s1).eval() * (s3 * m2).eval()); - VERIFY_IS_APPROX(m3 = ((s2 * m1.adjoint() * s1) * m2).lazy(), (s2 * m1.adjoint() * s1).eval() * m2); - VERIFY_IS_APPROX(m3 = ((-m1*s2) * s1*m2.adjoint()).lazy(), (-m1*s2).eval() * (s1*m2.adjoint()).eval()); + VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval()); + VERIFY_IS_APPROX(m3.noalias() = (m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval()); + VERIFY_IS_APPROX(m3.noalias() = (m1.adjoint() * m2, m1.adjoint().eval() * m2); + VERIFY_IS_APPROX(m3.noalias() = (s1 * m1.adjoint()) * m2, (s1 * m1.adjoint()).eval() * m2); + VERIFY_IS_APPROX(m3.noalias() = (- m1.adjoint() * s1) * (s3 * m2), (- m1.adjoint() * s1).eval() * (s3 * m2).eval()); + VERIFY_IS_APPROX(m3.noalias() = (s2 * m1.adjoint() * s1) * m2, (s2 * m1.adjoint() * s1).eval() * m2); + VERIFY_IS_APPROX(m3.noalias() = (-m1*s2) * s1*m2.adjoint(), (-m1*s2).eval() * (s1*m2.adjoint()).eval()); // a very tricky case where a scale factor has to be automatically conjugated: VERIFY_IS_APPROX( m1.adjoint() * (s1*m2).conjugate(), (m1.adjoint()).eval() * ((s1*m2).conjugate()).eval()); @@ -76,7 +73,6 @@ template void product_extra(const MatrixType& m) // test all possible conjugate combinations for the four matrix-vector product cases: -// std::cerr << "a\n"; VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2), (-m1.conjugate()*s2).eval() * (s1 * vc2).eval()); VERIFY_IS_APPROX((-m1 * s2) * (s1 * vc2.conjugate()), @@ -84,7 +80,6 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2.conjugate()), (-m1.conjugate()*s2).eval() * (s1 * vc2.conjugate()).eval()); -// std::cerr << "b\n"; VERIFY_IS_APPROX((s1 * vc2.transpose()) * (-m1.adjoint() * s2), (s1 * vc2.transpose()).eval() * (-m1.adjoint()*s2).eval()); VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.transpose() * s2), @@ -92,7 +87,6 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.adjoint() * s2), (s1 * vc2.adjoint()).eval() * (-m1.adjoint()*s2).eval()); -// std::cerr << "c\n"; VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.transpose()), (-m1.adjoint()*s2).eval() * (s1 * v1.transpose()).eval()); VERIFY_IS_APPROX((-m1.transpose() * s2) * (s1 * v1.adjoint()), @@ -100,7 +94,6 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()), (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval()); -// std::cerr << "d\n"; VERIFY_IS_APPROX((s1 * v1) * (-m1.conjugate() * s2), (s1 * v1).eval() * (-m1.conjugate()*s2).eval()); VERIFY_IS_APPROX((s1 * v1.conjugate()) * (-m1 * s2), diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index f6e8f4101..36a5a66ed 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -70,52 +70,51 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1); VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0); // NOTE in this case the slow product is used: // FIXME: VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0); - VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * m2.adjoint()).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * (m1*s3+m2*s2).adjoint()).lazy(), 1); - VERIFY_EVALUATION_COUNT( m3 = ((s1 * m1).adjoint() * s2 * m2).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * (m1*s3+m2*s2).adjoint(), 1); + VERIFY_EVALUATION_COUNT( m3.noalias() = (s1 * m1).adjoint() * s2 * m2, 0); VERIFY_EVALUATION_COUNT( m3 += (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0); VERIFY_EVALUATION_COUNT( m3 -= (s1 * (m1.transpose() * m2)).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0); - VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) += (-m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint()).lazy() ), 0); - VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) -= (s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1)).lazy() ), 0); + VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() += -m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint() ), 0); + VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() -= s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1) ), 0); // NOTE this is because the Block expression is not handled yet by our expression analyser VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) = (s1 * m1.block(r0,c0,r1,c1) * (s1*m2).block(c0,r0,c1,r1)).lazy() ), 1); - VERIFY_EVALUATION_COUNT( m3 -= ((s1 * m1).template triangularView() * m2).lazy(), 0); - VERIFY_EVALUATION_COUNT( rm3 = ((s1 * m1.adjoint()).template triangularView() * (m2+m2)).lazy(), 1); - VERIFY_EVALUATION_COUNT( rm3 = ((s1 * m1.adjoint()).template triangularView() * m2.adjoint()).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).template triangularView() * m2, 0); + VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView() * (m2+m2), 1); + VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView() * m2.adjoint(), 0); - VERIFY_EVALUATION_COUNT( rm3.col(c0) = ((s1 * m1.adjoint()).template triangularView() * (s2*m2.row(c0)).adjoint()).lazy(), 0); + VERIFY_EVALUATION_COUNT( rm3.col(c0).noalias() = (s1 * m1.adjoint()).template triangularView() * (s2*m2.row(c0)).adjoint(), 0); VERIFY_EVALUATION_COUNT( m1.template triangularView().solveInPlace(m3), 0); VERIFY_EVALUATION_COUNT( m1.adjoint().template triangularView().solveInPlace(m3.transpose()), 0); - VERIFY_EVALUATION_COUNT( m3 -= ((s1 * m1).adjoint().template selfadjointView() * (-m2*s3).adjoint()).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3 = (s2 * m2.adjoint() * (s1 * m1.adjoint()).template selfadjointView()).lazy(), 0); - VERIFY_EVALUATION_COUNT( rm3 = ((s1 * m1.adjoint()).template selfadjointView() * m2.adjoint()).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).adjoint().template selfadjointView() * (-m2*s3).adjoint(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = s2 * m2.adjoint() * (s1 * m1.adjoint()).template selfadjointView(), 0); + VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template selfadjointView() * m2.adjoint(), 0); - VERIFY_EVALUATION_COUNT( m3.col(c0) = ((s1 * m1).adjoint().template selfadjointView() * (-m2.row(c0)*s3).adjoint()).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3.col(c0) -= ((s1 * m1).adjoint().template selfadjointView() * (-m2.row(c0)*s3).adjoint()).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() = (s1 * m1).adjoint().template selfadjointView() * (-m2.row(c0)*s3).adjoint(), 0); + VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() -= (s1 * m1).adjoint().template selfadjointView() * (-m2.row(c0)*s3).adjoint(), 0); - VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1) += ((m1.block(r0,r0,r1,r1).template selfadjointView() * (s1*m2.block(r0,c0,r1,c1)) )).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1) = ((m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1) )).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() += m1.block(r0,r0,r1,r1).template selfadjointView() * (s1*m2.block(r0,c0,r1,c1)), 0); + VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() = m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1), 0); VERIFY_EVALUATION_COUNT( m3.template selfadjointView().rankUpdate(m2.adjoint()), 0); m3.resize(1,1); - VERIFY_EVALUATION_COUNT( m3 = ((m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1) )).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1), 0); m3.resize(1,1); - VERIFY_EVALUATION_COUNT( m3 = ((m1.block(r0,r0,r1,r1).template triangularView() * m2.block(r0,c0,r1,c1) )).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView() * m2.block(r0,c0,r1,c1), 0); } void test_product_notemporary() From 67ccc6b85167895924bc0a854da3b800dea68727 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Sep 2009 13:44:21 +0200 Subject: [PATCH 16/66] I've been too fast (again) --- test/product_extra.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/product_extra.cpp b/test/product_extra.cpp index 2eae73231..526dd210e 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -60,8 +60,8 @@ template void product_extra(const MatrixType& m) // r1 = ei_random(rows/2,rows); VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval()); - VERIFY_IS_APPROX(m3.noalias() = (m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval()); - VERIFY_IS_APPROX(m3.noalias() = (m1.adjoint() * m2, m1.adjoint().eval() * m2); + VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval()); + VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * m2, m1.adjoint().eval() * m2); VERIFY_IS_APPROX(m3.noalias() = (s1 * m1.adjoint()) * m2, (s1 * m1.adjoint()).eval() * m2); VERIFY_IS_APPROX(m3.noalias() = (- m1.adjoint() * s1) * (s3 * m2), (- m1.adjoint() * s1).eval() * (s3 * m2).eval()); VERIFY_IS_APPROX(m3.noalias() = (s2 * m1.adjoint() * s1) * m2, (s2 * m1.adjoint() * s1).eval() * m2); From 4d91229bdce3ab91ef25d853126989e4cd235b9f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Sep 2009 16:20:56 +0200 Subject: [PATCH 17/66] [mq]: eigensolver --- Eigen/QR | 2 + Eigen/src/QR/ComplexEigenSolver.h | 138 +++++++++++++++ Eigen/src/QR/ComplexSchur.h | 273 ++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/eigensolver_complex.cpp | 70 ++++++++ 5 files changed, 484 insertions(+) create mode 100644 Eigen/src/QR/ComplexEigenSolver.h create mode 100644 Eigen/src/QR/ComplexSchur.h create mode 100644 test/eigensolver_complex.cpp diff --git a/Eigen/QR b/Eigen/QR index 1cc94d8eb..4b49004c3 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -42,6 +42,8 @@ namespace Eigen { #include "src/QR/EigenSolver.h" #include "src/QR/SelfAdjointEigenSolver.h" #include "src/QR/HessenbergDecomposition.h" +#include "src/QR/ComplexSchur.h" +#include "src/QR/ComplexEigenSolver.h" // declare all classes for a given matrix type #define EIGEN_QR_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ diff --git a/Eigen/src/QR/ComplexEigenSolver.h b/Eigen/src/QR/ComplexEigenSolver.h new file mode 100644 index 000000000..af47c2195 --- /dev/null +++ b/Eigen/src/QR/ComplexEigenSolver.h @@ -0,0 +1,138 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Claire Maurice +// 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 +// 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_COMPLEX_EIGEN_SOLVER_H +#define EIGEN_COMPLEX_EIGEN_SOLVER_H + +#define MAXITER 30 + +template class ComplexEigenSolver +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef std::complex Complex; + typedef Matrix EigenvalueType; + typedef Matrix EigenvectorType; + + /** + * \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via ComplexEigenSolver::compute(const MatrixType&). + */ + ComplexEigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) + {} + + ComplexEigenSolver(const MatrixType& matrix) + : m_eivec(matrix.rows(),matrix.cols()), + m_eivalues(matrix.cols()), + m_isInitialized(false) + { + compute(matrix); + } + + EigenvectorType eigenvectors(void) const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_eivec; + } + + EigenvalueType eigenvalues() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_eivalues; + } + + void compute(const MatrixType& matrix); + + protected: + MatrixType m_eivec; + EigenvalueType m_eivalues; + bool m_isInitialized; +}; + + +template +void ComplexEigenSolver::compute(const MatrixType& matrix) +{ + assert(matrix.cols() == matrix.rows()); + int n = matrix.cols(); + m_eivalues.resize(n,1); + + RealScalar eps = epsilon(); + + // Reduce to complex Schur form + ComplexSchur schur(matrix); + + m_eivalues = schur.matrixT().diagonal(); + + m_eivec.setZero(); + + Scalar d2, z; + RealScalar norm = matrix.norm(); + + // compute the (normalized) eigenvectors + for(int k=n-1 ; k>=0 ; k--) + { + d2 = schur.matrixT().coeff(k,k); + m_eivec.coeffRef(k,k) = Scalar(1.0,0.0); + for(int i=k-1 ; i>=0 ; i--) + { + m_eivec.coeffRef(i,k) = -schur.matrixT().coeff(i,k); + if(k-i-1>0) + m_eivec.coeffRef(i,k) -= (schur.matrixT().row(i).segment(i+1,k-i-1) * m_eivec.col(k).segment(i+1,k-i-1)).value(); + z = schur.matrixT().coeff(i,i) - d2; + if(z==Scalar(0)) + z.real() = eps * norm; + m_eivec.coeffRef(i,k) = m_eivec.coeff(i,k) / z; + + } + m_eivec.col(k).normalize(); + } + + m_eivec = schur.matrixU() * m_eivec; + m_isInitialized = true; + + // sort the eigenvalues + { + for (int i=0; i +// +// 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_COMPLEX_SCHUR_H +#define EIGEN_COMPLEX_SCHUR_H + +#define MAXITER 30 + +/** \ingroup QR + * + * \class ComplexShur + * + * \brief Performs a complex Shur decomposition of a real or complex square matrix + * + */ +template class ComplexSchur +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef std::complex Complex; + typedef Matrix ComplexMatrixType; + + /** + * \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via ComplexSchur::compute(const MatrixType&). + */ + ComplexSchur() : m_matT(), m_matU(), m_isInitialized(false) + {} + + ComplexSchur(const MatrixType& matrix) + : m_matT(matrix.rows(),matrix.cols()), + m_matU(matrix.rows(),matrix.cols()), + m_isInitialized(false) + { + compute(matrix); + } + + ComplexMatrixType matrixU() const + { + ei_assert(m_isInitialized && "ComplexSchur is not initialized."); + return m_matU; + } + + ComplexMatrixType matrixT() const + { + ei_assert(m_isInitialized && "ComplexShur is not initialized."); + return m_matT; + } + + void compute(const MatrixType& matrix); + + protected: + ComplexMatrixType m_matT, m_matU; + bool m_isInitialized; +}; + +// computes the plane rotation G such that G' x |p| = | c s' |' |p| = |z| +// |q| |-s c' | |q| |0| +// and returns z if requested. Note that the returned c is real. +template void ei_make_givens(const std::complex& p, const std::complex& q, + JacobiRotation >& rot, std::complex* z=0) +{ + typedef std::complex Complex; + T scale, absx, absxy; + if(p==Complex(0)) + { + // return identity + rot.c() = Complex(1,0); + rot.s() = Complex(0,0); + if(z) *z = p; + } + else + { + scale = cnorm1(p); + absx = scale * ei_sqrt(ei_abs2(p/scale)); + scale = ei_abs(scale) + cnorm1(q); + absxy = scale * ei_sqrt((absx/scale)*(absx/scale) + ei_abs2(q/scale)); + rot.c() = Complex(absx / absxy); + Complex np = p/absx; + rot.s() = -ei_conj(np) * q / absxy; + if(z) *z = np * absxy; + } +} + +template +void ComplexSchur::compute(const MatrixType& matrix) +{ + assert(matrix.cols() == matrix.rows()); + int n = matrix.cols(); + + // Reduce to Hessenberg form + HessenbergDecomposition hess(matrix); + + m_matT = hess.matrixH(); + m_matU = hess.matrixQ(); + + int iu = m_matT.cols() - 1; + int il; + RealScalar d,sd,sf; + Complex c,b,disc,r1,r2,kappa; + + RealScalar eps = epsilon(); + + int iter = 0; + while(true) + { + //locate the range in which to iterate + while(iu > 0) + { + d = cnorm1(m_matT.coeffRef(iu,iu)) + cnorm1(m_matT.coeffRef(iu-1,iu-1)); + sd = cnorm1(m_matT.coeffRef(iu,iu-1)); + + if(sd >= eps * d) break; // FIXME : precision criterion ?? + + m_matT.coeffRef(iu,iu-1) = Complex(0); + iter = 0; + --iu; + } + if(iu==0) break; + iter++; + + if(iter >= MAXITER) + { + // FIXME : what to do when iter==MAXITER ?? + std::cerr << "MAXITER" << std::endl; + return; + } + + il = iu-1; + while( il > 0 ) + { + // check if the current 2x2 block on the diagonal is upper triangular + d = cnorm1(m_matT.coeffRef(il,il)) + cnorm1(m_matT.coeffRef(il-1,il-1)); + sd = cnorm1(m_matT.coeffRef(il,il-1)); + + if(sd < eps * d) break; // FIXME : precision criterion ?? + + --il; + } + + if( il != 0 ) m_matT.coeffRef(il,il-1) = Complex(0); + + // compute the shift (the normalization by sf is to avoid under/overflow) + Matrix t = m_matT.template block<2,2>(iu-1,iu-1); + sf = t.cwise().abs().sum(); + t /= sf; + + c = t.determinant(); + b = t.diagonal().sum(); + + disc = csqrt(b*b - RealScalar(4)*c); + + r1 = (b+disc)/RealScalar(2); + r2 = (b-disc)/RealScalar(2); + + if(cnorm1(r1) > cnorm1(r2)) + r2 = c/r1; + else + r1 = c/r2; + + if(cnorm1(r1-t.coeff(1,1)) < cnorm1(r2-t.coeff(1,1))) + kappa = sf * r1; + else + kappa = sf * r2; + + // perform the QR step using Givens rotations + JacobiRotation rot; + ei_make_givens(m_matT.coeff(il,il) - kappa, m_matT.coeff(il+1,il), rot); + + for(int i=il ; i +T cnorm1(const std::complex &Z) +{ + return(ei_abs(Z.real()) + ei_abs(Z.imag())); +} + +/** + * Computes the principal value of the square root of the complex \a z. + */ +template +std::complex csqrt(const std::complex &z) +{ + RealScalar t, tre, tim; + + t = ei_abs(z); + + if (ei_abs(z.real()) <= ei_abs(z.imag())) + { + // No cancellation in these formulas + tre = ei_sqrt(0.5*(t+z.real())); + tim = ei_sqrt(0.5*(t-z.real())); + } + else + { + // Stable computation of the above formulas + if (z.real() > 0) + { + tre = t + z.real(); + tim = ei_abs(z.imag())*ei_sqrt(0.5/tre); + tre = ei_sqrt(0.5*tre); + } + else + { + tim = t - z.real(); + tre = ei_abs(z.imag())*ei_sqrt(0.5/tim); + tim = ei_sqrt(0.5*tim); + } + } + if(z.imag() < 0) + tim = -tim; + + return (std::complex(tre,tim)); + +} + + +#endif // EIGEN_COMPLEX_SCHUR_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 896392188..56d36aa70 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -125,6 +125,7 @@ ei_add_test(qr_colpivoting) ei_add_test(qr_fullpivoting) ei_add_test(eigensolver_selfadjoint " " "${GSL_LIBRARIES}") ei_add_test(eigensolver_generic " " "${GSL_LIBRARIES}") +ei_add_test(eigensolver_complex) ei_add_test(svd) ei_add_test(jacobisvd ${EI_OFLAG}) ei_add_test(geo_orthomethods) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp new file mode 100644 index 000000000..32de327dd --- /dev/null +++ b/test/eigensolver_complex.cpp @@ -0,0 +1,70 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2008-2009 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 . + +#include "main.h" +#include +#include + +template void eigensolver(const MatrixType& m) +{ + /* this test covers the following files: + ComplexEigenSolver.h + */ + int rows = m.rows(); + int cols = m.cols(); + + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix VectorType; + 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; + +// ComplexEigenSolver ei0(symmA); + +// VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal()); + +// a.imag().setZero(); +// std::cerr << a << "\n\n"; + ComplexEigenSolver ei1(a); +// exit(1); + VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); + +} + +void test_eigensolver_complex() +{ + for(int i = 0; i < g_repeat; i++) { +// CALL_SUBTEST( eigensolver(Matrix4cf()) ); +// CALL_SUBTEST( eigensolver(MatrixXcd(4,4)) ); + CALL_SUBTEST( eigensolver(MatrixXcd(6,6)) ); +// CALL_SUBTEST( eigensolver(MatrixXd(14,14)) ); + } +} + From 5b8ffa4d46958d691042f2537cba4dd52f795bdc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Sep 2009 16:35:23 +0200 Subject: [PATCH 18/66] clean a bit the previous commit which came from a patch queue, and since it was my first try of the patch queue feature I did not managed to apply it with a good commit message, so here you go: * Add a ComplexSchur decomposition class built on top of HessenbergDecomposition * Add a ComplexEigenSolver built on top of ComplexSchur There are still a couple of FIXME but at least they work for any reasonable matrices, still have to extend the unit tests to stress them with nasty matrices... --- test/eigensolver_complex.cpp | 21 ++++++--------------- test/product_extra.cpp | 2 +- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 32de327dd..dad5a69f8 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -29,7 +29,7 @@ template void eigensolver(const MatrixType& m) { /* this test covers the following files: - ComplexEigenSolver.h + ComplexEigenSolver.h, and indirectly ComplexSchur.h */ int rows = m.rows(); int cols = m.cols(); @@ -40,20 +40,13 @@ 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; + MatrixType symmA = a.adjoint() * a; -// ComplexEigenSolver ei0(symmA); + ComplexEigenSolver ei0(symmA); + VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal()); -// VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal()); - -// a.imag().setZero(); -// std::cerr << a << "\n\n"; ComplexEigenSolver ei1(a); -// exit(1); VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); } @@ -61,10 +54,8 @@ template void eigensolver(const MatrixType& m) void test_eigensolver_complex() { for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST( eigensolver(Matrix4cf()) ); -// CALL_SUBTEST( eigensolver(MatrixXcd(4,4)) ); - CALL_SUBTEST( eigensolver(MatrixXcd(6,6)) ); -// CALL_SUBTEST( eigensolver(MatrixXd(14,14)) ); + CALL_SUBTEST( eigensolver(Matrix4cf()) ); + CALL_SUBTEST( eigensolver(MatrixXcd(14,14)) ); } } diff --git a/test/product_extra.cpp b/test/product_extra.cpp index 526dd210e..fcec362a5 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -59,7 +59,7 @@ template void product_extra(const MatrixType& m) // r0 = ei_random(0,rows/2-1), // r1 = ei_random(rows/2,rows); - VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval()); + VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval()); VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval()); VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * m2, m1.adjoint().eval() * m2); VERIFY_IS_APPROX(m3.noalias() = (s1 * m1.adjoint()) * m2, (s1 * m1.adjoint()).eval() * m2); From 05ddd328490582d726b24a443ceabce336343eab Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 1 Sep 2009 23:12:40 +0200 Subject: [PATCH 19/66] added missing JacobiRotation's ... --- Eigen/src/QR/SelfAdjointEigenSolver.h | 2 +- Eigen/src/SVD/SVD.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/QR/SelfAdjointEigenSolver.h b/Eigen/src/QR/SelfAdjointEigenSolver.h index 809a717b9..dd1736e28 100644 --- a/Eigen/src/QR/SelfAdjointEigenSolver.h +++ b/Eigen/src/QR/SelfAdjointEigenSolver.h @@ -380,7 +380,7 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int st if (matrixQ) { Map > q(matrixQ,n,n); - q.applyJacobiOnTheRight(k,k+1,c,s); + q.applyJacobiOnTheRight(k,k+1,JacobiRotation(c,s)); } } } diff --git a/Eigen/src/SVD/SVD.h b/Eigen/src/SVD/SVD.h index 1a7e6c49a..095e18b3e 100644 --- a/Eigen/src/SVD/SVD.h +++ b/Eigen/src/SVD/SVD.h @@ -309,7 +309,7 @@ SVD& SVD::compute(const MatrixType& matrix) h = Scalar(1.0)/h; c = g*h; s = -f*h; - V.applyJacobiOnTheRight(i,nm,c,s); + V.applyJacobiOnTheRight(i,nm,JacobiRotation(c,s)); } } z = W[k]; @@ -351,7 +351,7 @@ SVD& SVD::compute(const MatrixType& matrix) g = g*c - x*s; h = y*s; y *= c; - V.applyJacobiOnTheRight(i,j,c,s); + V.applyJacobiOnTheRight(i,j,JacobiRotation(c,s)); z = pythag(f,h); W[j] = z; @@ -364,7 +364,7 @@ SVD& SVD::compute(const MatrixType& matrix) } f = c*g + s*y; x = c*y - s*g; - A.applyJacobiOnTheRight(i,j,c,s); + A.applyJacobiOnTheRight(i,j,JacobiRotation(c,s)); } rv1[l] = 0.0; rv1[k] = f; From 59f5bce41c5c32eebb75c51d92c9730f3ab9d350 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 1 Sep 2009 23:15:30 +0200 Subject: [PATCH 20/66] fix issue #49 --- test/main.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/main.h b/test/main.h index 8c84e525c..619fc9e06 100644 --- a/test/main.h +++ b/test/main.h @@ -30,6 +30,10 @@ #include #include +#ifdef NDEBUG +#undef NDEBUG +#endif + #ifndef EIGEN_TEST_FUNC #error EIGEN_TEST_FUNC must be defined #endif From c16d65f01585b51f41b715a22c43983faab4299a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 2 Sep 2009 06:35:01 -0400 Subject: [PATCH 21/66] fix compilation errors in swap (could not swap with anything else than the exact same Matrix type) --- Eigen/src/Core/Matrix.h | 42 ++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 53d10fd31..2fc38c812 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -139,6 +139,9 @@ class Matrix && SizeAtCompileTime!=Dynamic && ((sizeof(Scalar)*SizeAtCompileTime)%16)==0 }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + Base& base() { return *static_cast(this); } + const Base& base() const { return *static_cast(this); } + EIGEN_STRONG_INLINE int rows() const { return m_storage.rows(); } EIGEN_STRONG_INLINE int cols() const { return m_storage.cols(); } @@ -487,13 +490,8 @@ class Matrix /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the * data pointers. */ - inline void swap(Matrix& other) - { - if (Base::SizeAtCompileTime==Dynamic) - m_storage.swap(other.m_storage); - else - this->Base::swap(other); - } + template + void swap(const MatrixBase& other); /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, @@ -652,8 +650,38 @@ class Matrix m_storage.data()[0] = x; m_storage.data()[1] = y; } + + template + friend struct ei_matrix_swap_impl; }; +template::ret, + bool IsDynamicSize = MatrixType::SizeAtCompileTime==Dynamic> +struct ei_matrix_swap_impl +{ + static inline void run(MatrixType& matrix, MatrixBase& other) + { + matrix.base().swap(other); + } +}; + +template +struct ei_matrix_swap_impl +{ + static inline void run(MatrixType& matrix, MatrixBase& other) + { + matrix.m_storage.swap(other.derived().m_storage); + } +}; + +template +template +inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) +{ + ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); +} + /** \defgroup matrixtypedefs Global matrix typedefs * * \ingroup Core_Module From e6b77bcc6bc915ec38640ecf414726fa2ba56fba Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 2 Sep 2009 06:36:55 -0400 Subject: [PATCH 22/66] JacobiSVD: implement general R-SVD using full-pivoting QR, so we now support any rectangular matrix size by reducing to the smaller of the two dimensions (which is also an optimization) --- Eigen/SVD | 2 +- Eigen/src/QR/FullPivotingHouseholderQR.h | 2 +- Eigen/src/SVD/JacobiSVD.h | 49 ++++++++++++++++++------ test/jacobisvd.cpp | 8 ++-- 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/Eigen/SVD b/Eigen/SVD index 01582310c..8d66d0736 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -1,7 +1,7 @@ #ifndef EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H -#include "Core" +#include "QR" #include "Householder" #include "Jacobi" diff --git a/Eigen/src/QR/FullPivotingHouseholderQR.h b/Eigen/src/QR/FullPivotingHouseholderQR.h index cee41b152..52405170b 100644 --- a/Eigen/src/QR/FullPivotingHouseholderQR.h +++ b/Eigen/src/QR/FullPivotingHouseholderQR.h @@ -286,7 +286,7 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co m_cols_permutation.resize(matrix.cols()); int number_of_transpositions = 0; - RealScalar biggest; + RealScalar biggest(0); for (int k = 0; k < size; ++k) { diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index b3d289706..654f8981a 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -188,15 +188,42 @@ void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, template JacobiSVD& JacobiSVD::compute(const MatrixType& matrix) { - MatrixType work_matrix(matrix); - int size = matrix.rows(); - if(ComputeU) m_matrixU = MatrixUType::Identity(size,size); - if(ComputeV) m_matrixV = MatrixUType::Identity(size,size); - m_singularValues.resize(size); + MatrixType work_matrix; + int rows = matrix.rows(); + int cols = matrix.cols(); + int diagSize = std::min(rows, cols); + if(ComputeU) m_matrixU = MatrixUType::Zero(rows,rows); + if(ComputeV) m_matrixV = MatrixVType::Zero(cols,cols); + m_singularValues.resize(diagSize); const RealScalar precision = 2 * epsilon(); + if(rows > cols) + { + FullPivotingHouseholderQR qr(matrix); + work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView(); + if(ComputeU) m_matrixU = qr.matrixQ(); + if(ComputeV) + for(int i = 0; i < cols; i++) + m_matrixV.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); + } + else if(rows < cols) + { + FullPivotingHouseholderQR qr(MatrixType(matrix.adjoint())); + work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView().adjoint(); + if(ComputeV) m_matrixV = qr.matrixQ(); + if(ComputeU) + for(int i = 0; i < rows; i++) + m_matrixU.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); + + } + else + { + work_matrix = matrix; + if(ComputeU) m_matrixU.diagonal().setOnes(); + if(ComputeV) m_matrixV.diagonal().setOnes(); + } sweep_again: - for(int p = 1; p < size; ++p) + for(int p = 1; p < diagSize; ++p) { for(int q = 0; q < p; ++q) { @@ -219,27 +246,27 @@ sweep_again: RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff(); RealScalar maxAllowedOffDiag = biggestOnDiag * precision; - for(int p = 0; p < size; ++p) + for(int p = 0; p < diagSize; ++p) { for(int q = 0; q < p; ++q) if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) goto sweep_again; - for(int q = p+1; q < size; ++q) + for(int q = p+1; q < diagSize; ++q) if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) goto sweep_again; } - for(int i = 0; i < size; ++i) + for(int i = 0; i < diagSize; ++i) { RealScalar a = ei_abs(work_matrix.coeff(i,i)); m_singularValues.coeffRef(i) = a; if(ComputeU && (a!=RealScalar(0))) m_matrixU.col(i) *= work_matrix.coeff(i,i)/a; } - for(int i = 0; i < size; i++) + for(int i = 0; i < diagSize; i++) { int pos; - m_singularValues.end(size-i).maxCoeff(&pos); + m_singularValues.end(diagSize-i).maxCoeff(&pos); if(pos) { pos += i; diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 9a4d79e45..8b4c7584e 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -91,12 +91,14 @@ void test_jacobisvd() CALL_SUBTEST( svd(Matrix3f()) ); CALL_SUBTEST( svd(Matrix4d()) ); CALL_SUBTEST( svd(MatrixXf(50,50)) ); -// CALL_SUBTEST( svd(MatrixXd(14,7)) ); + CALL_SUBTEST( svd(MatrixXcd(14,7)) ); + CALL_SUBTEST( svd(MatrixXd(10,50)) ); + CALL_SUBTEST( svd(MatrixXcf(3,3)) ); CALL_SUBTEST( svd(MatrixXd(30,30)) ); } - CALL_SUBTEST( svd(MatrixXf(200,200)) ); - CALL_SUBTEST( svd(MatrixXcd(100,100)) ); + CALL_SUBTEST( svd(MatrixXf(300,200)) ); + CALL_SUBTEST( svd(MatrixXcd(100,150)) ); CALL_SUBTEST( svd_verify_assert() ); CALL_SUBTEST( svd_verify_assert() ); From ec20d583179bb2f01686c1c6fc0079ddee8ae4e2 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 2 Sep 2009 16:56:48 -0400 Subject: [PATCH 23/66] * add serious unit test for swap * fix my stupidity in Matrix::swap() --- Eigen/src/Core/Matrix.h | 9 ++-- test/CMakeLists.txt | 1 + test/basicstuff.cpp | 9 ---- test/swap.cpp | 98 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 test/swap.cpp diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 2fc38c812..cdc76c120 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -651,13 +651,12 @@ class Matrix m_storage.data()[1] = y; } - template + template friend struct ei_matrix_swap_impl; }; template::ret, - bool IsDynamicSize = MatrixType::SizeAtCompileTime==Dynamic> + bool IsSameType = ei_is_same_type::ret> struct ei_matrix_swap_impl { static inline void run(MatrixType& matrix, MatrixBase& other) @@ -667,10 +666,11 @@ struct ei_matrix_swap_impl }; template -struct ei_matrix_swap_impl +struct ei_matrix_swap_impl { static inline void run(MatrixType& matrix, MatrixBase& other) { + ei_assert(matrix.rows() == other.rows() && matrix.cols() == other.cols()); matrix.m_storage.swap(other.derived().m_storage); } }; @@ -679,6 +679,7 @@ template inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) { + ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 56d36aa70..6bbf82144 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -148,6 +148,7 @@ ei_add_test(sparse_product) ei_add_test(sparse_solvers " " "${SPARSE_LIBS}") ei_add_test(umeyama) ei_add_test(householder) +ei_add_test(swap) ei_add_property(EIGEN_TESTING_SUMMARY "CXX: ${CMAKE_CXX_COMPILER}\n") if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp index 52aff93ee..29df99f9e 100644 --- a/test/basicstuff.cpp +++ b/test/basicstuff.cpp @@ -99,15 +99,6 @@ template void basicStuff(const MatrixType& m) MatrixType m4; VERIFY_IS_APPROX(m4 = m1,m1); - // test swap - m3 = m1; - m1.swap(m2); - VERIFY_IS_APPROX(m3, m2); - if(rows*cols>=3) - { - VERIFY_IS_NOT_APPROX(m3, m1); - } - m3.real() = m1.real(); VERIFY_IS_APPROX(static_cast(m3).real(), static_cast(m1).real()); VERIFY_IS_APPROX(static_cast(m3).real(), m1.real()); diff --git a/test/swap.cpp b/test/swap.cpp new file mode 100644 index 000000000..8b325992c --- /dev/null +++ b/test/swap.cpp @@ -0,0 +1,98 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// +// 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 . + +#define EIGEN_NO_STATIC_ASSERT +#include "main.h" + +template +struct other_matrix_type +{ + typedef int type; +}; + +template +struct other_matrix_type > +{ + typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type; +}; + +template void swap(const MatrixType& m) +{ + typedef typename other_matrix_type::type OtherMatrixType; + typedef typename MatrixType::Scalar Scalar; + + ei_assert((!ei_is_same_type::ret)); + int rows = m.rows(); + int cols = m.cols(); + + // construct 3 matrix guaranteed to be distinct + MatrixType m1 = MatrixType::Random(rows,cols); + MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols); + OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols); + + MatrixType m1_copy = m1; + MatrixType m2_copy = m2; + OtherMatrixType m3_copy = m3; + + // test swapping 2 matrices of same type + m1.swap(m2); + VERIFY_IS_APPROX(m1,m2_copy); + VERIFY_IS_APPROX(m2,m1_copy); + m1 = m1_copy; + m2 = m2_copy; + + // test swapping 2 matrices of different types + m1.swap(m3); + VERIFY_IS_APPROX(m1,m3_copy); + VERIFY_IS_APPROX(m3,m1_copy); + m1 = m1_copy; + m3 = m3_copy; + + // test swapping matrix with expression + m1.swap(m2.block(0,0,rows,cols)); + VERIFY_IS_APPROX(m1,m2_copy); + VERIFY_IS_APPROX(m2,m1_copy); + m1 = m1_copy; + m2 = m2_copy; + + // test swapping two expressions of different types + m1.transpose().swap(m3.transpose()); + VERIFY_IS_APPROX(m1,m3_copy); + VERIFY_IS_APPROX(m3,m1_copy); + m1 = m1_copy; + m3 = m3_copy; + + // test assertion on mismatching size -- matrix case + VERIFY_RAISES_ASSERT(m1.swap(m1.row(0))); + // test assertion on mismatching size -- xpr case + VERIFY_RAISES_ASSERT(m1.row(0).swap(m1)); +} + +void test_swap() +{ + CALL_SUBTEST( swap(Matrix3f()) ); // fixed size, no vectorization + CALL_SUBTEST( swap(Matrix4d()) ); // fixed size, possible vectorization + CALL_SUBTEST( swap(MatrixXd(3,3)) ); // dyn size, no vectorization + CALL_SUBTEST( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization +} From 4a8258369a28eb340a1789bc05322475c7ace8f9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Sep 2009 13:37:15 +0200 Subject: [PATCH 24/66] much simpler fix for Matrix::swap --- Eigen/src/Core/Matrix.h | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index cdc76c120..16c0ee4ac 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -490,8 +490,13 @@ class Matrix /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the * data pointers. */ - template - void swap(const MatrixBase& other); + using Base::swap; + inline void swap(Matrix& other) + { + ei_assert(matrix.rows() == other.rows() && matrix.cols() == other.cols()); + m_storage.swap(other.m_storage); + // FIXME what about using this->Base::swap(other); for fixed size ? + } /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, @@ -650,38 +655,8 @@ class Matrix m_storage.data()[0] = x; m_storage.data()[1] = y; } - - template - friend struct ei_matrix_swap_impl; }; -template::ret> -struct ei_matrix_swap_impl -{ - static inline void run(MatrixType& matrix, MatrixBase& other) - { - matrix.base().swap(other); - } -}; - -template -struct ei_matrix_swap_impl -{ - static inline void run(MatrixType& matrix, MatrixBase& other) - { - ei_assert(matrix.rows() == other.rows() && matrix.cols() == other.cols()); - matrix.m_storage.swap(other.derived().m_storage); - } -}; - -template -template -inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) -{ - - ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); -} /** \defgroup matrixtypedefs Global matrix typedefs * From 496ea63972f15c5bc7d43a7a4dc987b6cd33d176 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Sep 2009 14:08:33 +0200 Subject: [PATCH 25/66] fix wrong assert --- Eigen/src/Core/Matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 16c0ee4ac..caa8d4be6 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -493,7 +493,7 @@ class Matrix using Base::swap; inline void swap(Matrix& other) { - ei_assert(matrix.rows() == other.rows() && matrix.cols() == other.cols()); + ei_assert(rows() == other.rows() && cols() == other.cols()); m_storage.swap(other.m_storage); // FIXME what about using this->Base::swap(other); for fixed size ? } From b83654b5d01155c4ea875090f0779b99241a91a4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Sep 2009 15:04:10 +0200 Subject: [PATCH 26/66] * rename JacobiRotation => PlanarRotation * move the makeJacobi and make_givens_* to PlanarRotation * rename applyJacobi* => apply* --- Eigen/src/Core/MathFunctions.h | 4 + Eigen/src/Core/MatrixBase.h | 9 +- Eigen/src/Core/util/ForwardDeclarations.h | 2 +- Eigen/src/Jacobi/Jacobi.h | 205 +++++++++++++++------- Eigen/src/QR/ComplexSchur.h | 59 ++----- Eigen/src/QR/SelfAdjointEigenSolver.h | 45 ++--- Eigen/src/SVD/JacobiSVD.h | 28 +-- Eigen/src/SVD/SVD.h | 10 +- 8 files changed, 194 insertions(+), 168 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 1570f01e0..40edf4a3c 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -116,6 +116,7 @@ inline float ei_imag(float) { return 0.f; } inline float ei_conj(float x) { return x; } inline float ei_abs(float x) { return std::abs(x); } inline float ei_abs2(float x) { return x*x; } +inline float ei_norm1(float x) { return ei_abs(x); } inline float ei_sqrt(float x) { return std::sqrt(x); } inline float ei_exp(float x) { return std::exp(x); } inline float ei_log(float x) { return std::log(x); } @@ -164,6 +165,7 @@ inline double ei_imag(double) { return 0.; } inline double ei_conj(double x) { return x; } inline double ei_abs(double x) { return std::abs(x); } inline double ei_abs2(double x) { return x*x; } +inline double ei_norm1(double x) { return ei_abs(x); } inline double ei_sqrt(double x) { return std::sqrt(x); } inline double ei_exp(double x) { return std::exp(x); } inline double ei_log(double x) { return std::log(x); } @@ -212,6 +214,7 @@ inline float& ei_imag_ref(std::complex& x) { return reinterpret_cast ei_conj(const std::complex& x) { return std::conj(x); } inline float ei_abs(const std::complex& x) { return std::abs(x); } inline float ei_abs2(const std::complex& x) { return std::norm(x); } +inline float ei_norm1(const std::complex &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } inline std::complex ei_exp(std::complex x) { return std::exp(x); } inline std::complex ei_sin(std::complex x) { return std::sin(x); } inline std::complex ei_cos(std::complex x) { return std::cos(x); } @@ -248,6 +251,7 @@ inline double& ei_imag_ref(std::complex& x) { return reinterpret_cast ei_conj(const std::complex& x) { return std::conj(x); } inline double ei_abs(const std::complex& x) { return std::abs(x); } inline double ei_abs2(const std::complex& x) { return std::norm(x); } +inline double ei_norm1(const std::complex &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } inline std::complex ei_exp(std::complex x) { return std::exp(x); } inline std::complex ei_sin(std::complex x) { return std::sin(x); } inline std::complex ei_cos(std::complex x) { return std::cos(x); } diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index c2945ab46..9ac964168 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -803,11 +803,10 @@ template class MatrixBase ///////// Jacobi module ///////// - template - void applyJacobiOnTheLeft(int p, int q, const JacobiRotation& j); - template - void applyJacobiOnTheRight(int p, int q, const JacobiRotation& j); - bool makeJacobi(int p, int q, JacobiRotation *j) const; + template + void applyOnTheLeft(int p, int q, const PlanarRotation& j); + template + void applyOnTheRight(int p, int q, const PlanarRotation& j); #ifdef EIGEN_MATRIXBASE_PLUGIN #include EIGEN_MATRIXBASE_PLUGIN diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 18d3af7c5..c5f27d80b 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -123,7 +123,7 @@ template class SVD; template class JacobiSVD; template class LLT; template class LDLT; -template class JacobiRotation; +template class PlanarRotation; // Geometry module: template class RotationBase; diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 24fb7e782..c38d4583f 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -27,97 +27,72 @@ #define EIGEN_JACOBI_H /** \ingroup Jacobi - * \class JacobiRotation + * \class PlanarRotation * \brief Represents a rotation in the plane from a cosine-sine pair. * - * This class represents a Jacobi rotation which is also known as a Givens rotation. + * This class represents a Jacobi or Givens rotation. * This is a 2D clock-wise rotation in the plane \c J of angle \f$ \theta \f$ defined by * its cosine \c c and sine \c s as follow: * \f$ J = \left ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} \right ) \f$ * - * \sa MatrixBase::makeJacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() + * \sa MatrixBase::makeJacobi(), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ -template class JacobiRotation +template class PlanarRotation { public: - /** Default constructor without any initialization. */ - JacobiRotation() {} + typedef typename NumTraits::Real RealScalar; - /** Construct a Jacobi rotation from a cosine-sine pair (\a c, \c s). */ - JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {} + /** Default constructor without any initialization. */ + PlanarRotation() {} + + /** Construct a planar rotation from a cosine-sine pair (\a c, \c s). */ + PlanarRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {} Scalar& c() { return m_c; } Scalar c() const { return m_c; } Scalar& s() { return m_s; } Scalar s() const { return m_s; } - /** Concatenates two Jacobi rotation */ - JacobiRotation operator*(const JacobiRotation& other) + /** Concatenates two planar rotation */ + PlanarRotation operator*(const PlanarRotation& other) { - return JacobiRotation(m_c * other.m_c - ei_conj(m_s) * other.m_s, + return PlanarRotation(m_c * other.m_c - ei_conj(m_s) * other.m_s, ei_conj(m_c * ei_conj(other.m_s) + ei_conj(m_s) * ei_conj(other.m_c))); } /** Returns the transposed transformation */ - JacobiRotation transpose() const { return JacobiRotation(m_c, -ei_conj(m_s)); } + PlanarRotation transpose() const { return PlanarRotation(m_c, -ei_conj(m_s)); } /** Returns the adjoint transformation */ - JacobiRotation adjoint() const { return JacobiRotation(ei_conj(m_c), -m_s); } + PlanarRotation adjoint() const { return PlanarRotation(ei_conj(m_c), -m_s); } + + template + bool makeJacobi(const MatrixBase&, int p, int q); + bool makeJacobi(RealScalar x, Scalar y, RealScalar z); + + void makeGivens(const Scalar& p, const Scalar& q, Scalar* z=0); protected: + void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_true); + void makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false); + Scalar m_c, m_s; }; -/** Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: - * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$ - * - * \sa MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() - */ -template -void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation& j); - -/** Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B, - * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$. - * - * \sa class JacobiRotation, MatrixBase::applyJacobiOnTheRight(), ei_apply_rotation_in_the_plane() - */ -template -template -inline void MatrixBase::applyJacobiOnTheLeft(int p, int q, const JacobiRotation& j) -{ - RowXpr x(row(p)); - RowXpr y(row(q)); - ei_apply_rotation_in_the_plane(x, y, j); -} - -/** Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J - * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$. - * - * \sa class JacobiRotation, MatrixBase::applyJacobiOnTheLeft(), ei_apply_rotation_in_the_plane() - */ -template -template -inline void MatrixBase::applyJacobiOnTheRight(int p, int q, const JacobiRotation& j) -{ - ColXpr x(col(p)); - ColXpr y(col(q)); - ei_apply_rotation_in_the_plane(x, y, j.transpose()); -} - -/** Computes the Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix +/** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * - * \sa MatrixBase::makeJacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() + * \sa MatrixBase::makeJacobi(), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template -bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTraits::Real z, JacobiRotation *j) +bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) { typedef typename NumTraits::Real RealScalar; if(y == Scalar(0)) { - j->c() = Scalar(1); - j->s() = Scalar(0); + m_c = Scalar(1); + m_s = Scalar(0); return false; } else @@ -135,26 +110,132 @@ bool ei_makeJacobi(typename NumTraits::Real x, Scalar y, typename NumTra } RealScalar sign_t = t > 0 ? 1 : -1; RealScalar n = RealScalar(1) / ei_sqrt(ei_abs2(t)+1); - j->s() = - sign_t * (ei_conj(y) / ei_abs(y)) * ei_abs(t) * n; - j->c() = n; + m_s = - sign_t * (ei_conj(y) / ei_abs(y)) * ei_abs(t) * n; + m_c = n; return true; } } -/** Computes the Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix +/** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 matrix * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ * & \text{this}_{qq} \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * - * \sa MatrixBase::ei_make_jacobi(), MatrixBase::applyJacobiOnTheLeft(), MatrixBase::applyJacobiOnTheRight() + * \sa PlanarRotation::makeJacobi(RealScalar, Scalar, RealScalar), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ +template template -inline bool MatrixBase::makeJacobi(int p, int q, JacobiRotation *j) const +inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int p, int q) { - return ei_makeJacobi(ei_real(coeff(p,p)), coeff(p,q), ei_real(coeff(q,q)), j); + return makeJacobi(ei_real(m.coeff(p,p)), m.coeff(p,q), ei_real(m.coeff(q,q))); } -template -void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const JacobiRotation& j) +/** Makes \c *this as a Givens rotation \c G such that applying \f$ G^* \f$ to the left of the vector + * \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields: + * \f$ G^* V = \left ( \begin{array}{c} z \\ 0 \end{array} \right )\f$. + * + * The value of \a z is returned if \a z is not null (the default is null). + * Also note that G is built such that the cosine is always real. + * + * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() + */ +template +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z) +{ + makeGivens(p, q, z, typename ei_meta_if::IsComplex, ei_meta_true, ei_meta_false>::ret()); +} + + +// specialization for complexes +template +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_true) +{ + RealScalar scale, absx, absxy; + if(q==Scalar(0)) + { + // return identity + m_c = Scalar(1); + m_s = Scalar(0); + if(z) *z = p; + } + else + { + scale = ei_norm1(p); + absx = scale * ei_sqrt(ei_abs2(p/scale)); + scale = ei_abs(scale) + ei_norm1(q); + absxy = scale * ei_sqrt((absx/scale)*(absx/scale) + ei_abs2(q/scale)); + m_c = Scalar(absx / absxy); + Scalar np = p/absx; + m_s = -ei_conj(np) * q / absxy; + if(z) *z = np * absxy; + } +} + +// specialization for reals +template +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false) +{ + // from Golub's "Matrix Computations", algorithm 5.1.3 + if(q==0) + { + m_c = 1; m_s = 0; + } + else if(ei_abs(q)>ei_abs(p)) + { + Scalar t = -p/q; + m_s = Scalar(1)/ei_sqrt(1+t*t); + m_c = m_s * t; + } + else + { + Scalar t = -q/p; + m_c = Scalar(1)/ei_sqrt(1+t*t); + m_s = m_c * t; + } +} + +/**************************************************************************************** +* Implementation of MatrixBase methods +/***************************************************************************************/ + +/** Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: + * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$ + * + * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() + */ +template +void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const PlanarRotation& j); + +/** Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B, + * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$. + * + * \sa class PlanarRotation, MatrixBase::applyOnTheRight(), ei_apply_rotation_in_the_plane() + */ +template +template +inline void MatrixBase::applyOnTheLeft(int p, int q, const PlanarRotation& j) +{ + RowXpr x(row(p)); + RowXpr y(row(q)); + ei_apply_rotation_in_the_plane(x, y, j); +} + +/** Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J + * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$. + * + * \sa class PlanarRotation, MatrixBase::applyOnTheLeft(), ei_apply_rotation_in_the_plane() + */ +template +template +inline void MatrixBase::applyOnTheRight(int p, int q, const PlanarRotation& j) +{ + ColXpr x(col(p)); + ColXpr y(col(q)); + ei_apply_rotation_in_the_plane(x, y, j.transpose()); +} + + +template +void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const PlanarRotation& j) { typedef typename VectorX::Scalar Scalar; ei_assert(_x.size() == _y.size()); diff --git a/Eigen/src/QR/ComplexSchur.h b/Eigen/src/QR/ComplexSchur.h index a0b954d49..153826811 100644 --- a/Eigen/src/QR/ComplexSchur.h +++ b/Eigen/src/QR/ComplexSchur.h @@ -80,34 +80,6 @@ template class ComplexSchur bool m_isInitialized; }; -// computes the plane rotation G such that G' x |p| = | c s' |' |p| = |z| -// |q| |-s c' | |q| |0| -// and returns z if requested. Note that the returned c is real. -template void ei_make_givens(const std::complex& p, const std::complex& q, - JacobiRotation >& rot, std::complex* z=0) -{ - typedef std::complex Complex; - T scale, absx, absxy; - if(p==Complex(0)) - { - // return identity - rot.c() = Complex(1,0); - rot.s() = Complex(0,0); - if(z) *z = p; - } - else - { - scale = cnorm1(p); - absx = scale * ei_sqrt(ei_abs2(p/scale)); - scale = ei_abs(scale) + cnorm1(q); - absxy = scale * ei_sqrt((absx/scale)*(absx/scale) + ei_abs2(q/scale)); - rot.c() = Complex(absx / absxy); - Complex np = p/absx; - rot.s() = -ei_conj(np) * q / absxy; - if(z) *z = np * absxy; - } -} - template void ComplexSchur::compute(const MatrixType& matrix) { @@ -133,8 +105,8 @@ void ComplexSchur::compute(const MatrixType& matrix) //locate the range in which to iterate while(iu > 0) { - d = cnorm1(m_matT.coeffRef(iu,iu)) + cnorm1(m_matT.coeffRef(iu-1,iu-1)); - sd = cnorm1(m_matT.coeffRef(iu,iu-1)); + d = ei_norm1(m_matT.coeffRef(iu,iu)) + ei_norm1(m_matT.coeffRef(iu-1,iu-1)); + sd = ei_norm1(m_matT.coeffRef(iu,iu-1)); if(sd >= eps * d) break; // FIXME : precision criterion ?? @@ -156,8 +128,8 @@ void ComplexSchur::compute(const MatrixType& matrix) while( il > 0 ) { // check if the current 2x2 block on the diagonal is upper triangular - d = cnorm1(m_matT.coeffRef(il,il)) + cnorm1(m_matT.coeffRef(il-1,il-1)); - sd = cnorm1(m_matT.coeffRef(il,il-1)); + d = ei_norm1(m_matT.coeffRef(il,il)) + ei_norm1(m_matT.coeffRef(il-1,il-1)); + sd = ei_norm1(m_matT.coeffRef(il,il-1)); if(sd < eps * d) break; // FIXME : precision criterion ?? @@ -179,32 +151,32 @@ void ComplexSchur::compute(const MatrixType& matrix) r1 = (b+disc)/RealScalar(2); r2 = (b-disc)/RealScalar(2); - if(cnorm1(r1) > cnorm1(r2)) + if(ei_norm1(r1) > ei_norm1(r2)) r2 = c/r1; else r1 = c/r2; - if(cnorm1(r1-t.coeff(1,1)) < cnorm1(r2-t.coeff(1,1))) + if(ei_norm1(r1-t.coeff(1,1)) < ei_norm1(r2-t.coeff(1,1))) kappa = sf * r1; else kappa = sf * r2; // perform the QR step using Givens rotations - JacobiRotation rot; - ei_make_givens(m_matT.coeff(il,il) - kappa, m_matT.coeff(il+1,il), rot); + PlanarRotation rot; + rot.makeGivens(m_matT.coeff(il,il) - kappa, m_matT.coeff(il+1,il)); for(int i=il ; i::compute(const MatrixType& matrix) m_isInitialized = true; } -// norm1 of complex numbers -template -T cnorm1(const std::complex &Z) -{ - return(ei_abs(Z.real()) + ei_abs(Z.imag())); -} - /** * Computes the principal value of the square root of the complex \a z. */ diff --git a/Eigen/src/QR/SelfAdjointEigenSolver.h b/Eigen/src/QR/SelfAdjointEigenSolver.h index dd1736e28..580b042f6 100644 --- a/Eigen/src/QR/SelfAdjointEigenSolver.h +++ b/Eigen/src/QR/SelfAdjointEigenSolver.h @@ -135,28 +135,6 @@ template class SelfAdjointEigenSolver #ifndef EIGEN_HIDE_HEAVY_CODE -// from Golub's "Matrix Computations", algorithm 5.1.3 -template -static void ei_givens_rotation(Scalar a, Scalar b, Scalar& c, Scalar& s) -{ - if (b==0) - { - c = 1; s = 0; - } - else if (ei_abs(b)>ei_abs(a)) - { - Scalar t = -a/b; - s = Scalar(1)/ei_sqrt(1+t*t); - c = s * t; - } - else - { - Scalar t = -b/a; - c = Scalar(1)/ei_sqrt(1+t*t); - s = c * t; - } -} - /** \internal * * \qr_module @@ -353,34 +331,33 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int st for (int k = start; k < end; ++k) { - RealScalar c, s; - ei_givens_rotation(x, z, c, s); + PlanarRotation rot; + rot.makeGivens(x, z); // do T = G' T G - RealScalar sdk = s * diag[k] + c * subdiag[k]; - RealScalar dkp1 = s * subdiag[k] + c * diag[k+1]; + RealScalar sdk = rot.s() * diag[k] + rot.c() * subdiag[k]; + RealScalar dkp1 = rot.s() * subdiag[k] + rot.c() * diag[k+1]; - diag[k] = c * (c * diag[k] - s * subdiag[k]) - s * (c * subdiag[k] - s * diag[k+1]); - diag[k+1] = s * sdk + c * dkp1; - subdiag[k] = c * sdk - s * dkp1; + diag[k] = rot.c() * (rot.c() * diag[k] - rot.s() * subdiag[k]) - rot.s() * (rot.c() * subdiag[k] - rot.s() * diag[k+1]); + diag[k+1] = rot.s() * sdk + rot.c() * dkp1; + subdiag[k] = rot.c() * sdk - rot.s() * dkp1; if (k > start) - subdiag[k - 1] = c * subdiag[k-1] - s * z; + subdiag[k - 1] = rot.c() * subdiag[k-1] - rot.s() * z; x = subdiag[k]; if (k < end - 1) { - z = -s * subdiag[k+1]; - subdiag[k + 1] = c * subdiag[k+1]; + z = -rot.s() * subdiag[k+1]; + subdiag[k + 1] = rot.c() * subdiag[k+1]; } // apply the givens rotation to the unit matrix Q = Q * G - // G only modifies the two columns k and k+1 if (matrixQ) { Map > q(matrixQ,n,n); - q.applyJacobiOnTheRight(k,k+1,JacobiRotation(c,s)); + q.applyOnTheRight(k,k+1,rot); } } } diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 654f8981a..ca359832b 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -125,7 +125,7 @@ struct ei_svd_precondition_2x2_block_to_be_real static void run(MatrixType& work_matrix, JacobiSVD& svd, int p, int q) { Scalar z; - JacobiRotation rot; + PlanarRotation rot; RealScalar n = ei_sqrt(ei_abs2(work_matrix.coeff(p,p)) + ei_abs2(work_matrix.coeff(q,p))); if(n==0) { @@ -140,8 +140,8 @@ struct ei_svd_precondition_2x2_block_to_be_real { rot.c() = ei_conj(work_matrix.coeff(p,p)) / n; rot.s() = work_matrix.coeff(q,p) / n; - work_matrix.applyJacobiOnTheLeft(p,q,rot); - if(ComputeU) svd.m_matrixU.applyJacobiOnTheRight(p,q,rot.adjoint()); + work_matrix.applyOnTheLeft(p,q,rot); + if(ComputeU) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint()); if(work_matrix.coeff(p,q) != Scalar(0)) { Scalar z = ei_abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); @@ -160,13 +160,13 @@ struct ei_svd_precondition_2x2_block_to_be_real template void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, - JacobiRotation *j_left, - JacobiRotation *j_right) + PlanarRotation *j_left, + PlanarRotation *j_right) { Matrix m; m << ei_real(matrix.coeff(p,p)), ei_real(matrix.coeff(p,q)), ei_real(matrix.coeff(q,p)), ei_real(matrix.coeff(q,q)); - JacobiRotation rot1; + PlanarRotation rot1; RealScalar t = m.coeff(0,0) + m.coeff(1,1); RealScalar d = m.coeff(1,0) - m.coeff(0,1); if(t == RealScalar(0)) @@ -180,8 +180,8 @@ void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, rot1.c() = RealScalar(1) / ei_sqrt(1 + ei_abs2(u)); rot1.s() = rot1.c() * u; } - m.applyJacobiOnTheLeft(0,1,rot1); - m.makeJacobi(0,1,j_right); + m.applyOnTheLeft(0,1,rot1); + j_right->makeJacobi(m,0,1); *j_left = rot1 * j_right->transpose(); } @@ -214,7 +214,7 @@ JacobiSVD& JacobiSVD::compute(const Ma if(ComputeU) for(int i = 0; i < rows; i++) m_matrixU.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); - + } else { @@ -232,14 +232,14 @@ sweep_again: { ei_svd_precondition_2x2_block_to_be_real::run(work_matrix, *this, p, q); - JacobiRotation j_left, j_right; + PlanarRotation j_left, j_right; ei_real_2x2_jacobi_svd(work_matrix, p, q, &j_left, &j_right); - work_matrix.applyJacobiOnTheLeft(p,q,j_left); - if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,j_left.transpose()); + work_matrix.applyOnTheLeft(p,q,j_left); + if(ComputeU) m_matrixU.applyOnTheRight(p,q,j_left.transpose()); - work_matrix.applyJacobiOnTheRight(p,q,j_right); - if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,j_right); + work_matrix.applyOnTheRight(p,q,j_right); + if(ComputeV) m_matrixV.applyOnTheRight(p,q,j_right); } } } diff --git a/Eigen/src/SVD/SVD.h b/Eigen/src/SVD/SVD.h index 095e18b3e..da01cf396 100644 --- a/Eigen/src/SVD/SVD.h +++ b/Eigen/src/SVD/SVD.h @@ -309,7 +309,7 @@ SVD& SVD::compute(const MatrixType& matrix) h = Scalar(1.0)/h; c = g*h; s = -f*h; - V.applyJacobiOnTheRight(i,nm,JacobiRotation(c,s)); + V.applyOnTheRight(i,nm,PlanarRotation(c,s)); } } z = W[k]; @@ -342,7 +342,7 @@ SVD& SVD::compute(const MatrixType& matrix) y = W[i]; h = s*g; g = c*g; - + z = pythag(f,h); rv1[j] = z; c = f/z; @@ -351,8 +351,8 @@ SVD& SVD::compute(const MatrixType& matrix) g = g*c - x*s; h = y*s; y *= c; - V.applyJacobiOnTheRight(i,j,JacobiRotation(c,s)); - + V.applyOnTheRight(i,j,PlanarRotation(c,s)); + z = pythag(f,h); W[j] = z; // Rotation can be arbitrary if z = 0. @@ -364,7 +364,7 @@ SVD& SVD::compute(const MatrixType& matrix) } f = c*g + s*y; x = c*y - s*g; - A.applyJacobiOnTheRight(i,j,JacobiRotation(c,s)); + A.applyOnTheRight(i,j,PlanarRotation(c,s)); } rv1[l] = 0.0; rv1[k] = f; From 7586f7f706dbeeeed431d63e6d5990f8cb773caa Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 2 Sep 2009 15:18:11 +0200 Subject: [PATCH 27/66] fix #51 (bad use of std::complex::real) --- Eigen/src/Jacobi/Jacobi.h | 2 +- Eigen/src/QR/ComplexEigenSolver.h | 2 +- Eigen/src/QR/ComplexSchur.h | 89 +++++++++++++++---------------- 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index c38d4583f..66ba06b19 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -195,7 +195,7 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar /**************************************************************************************** * Implementation of MatrixBase methods -/***************************************************************************************/ +****************************************************************************************/ /** Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$ diff --git a/Eigen/src/QR/ComplexEigenSolver.h b/Eigen/src/QR/ComplexEigenSolver.h index af47c2195..6caa6bc2d 100644 --- a/Eigen/src/QR/ComplexEigenSolver.h +++ b/Eigen/src/QR/ComplexEigenSolver.h @@ -107,7 +107,7 @@ void ComplexEigenSolver::compute(const MatrixType& matrix) m_eivec.coeffRef(i,k) -= (schur.matrixT().row(i).segment(i+1,k-i-1) * m_eivec.col(k).segment(i+1,k-i-1)).value(); z = schur.matrixT().coeff(i,i) - d2; if(z==Scalar(0)) - z.real() = eps * norm; + ei_real_ref(z) = eps * norm; m_eivec.coeffRef(i,k) = m_eivec.coeff(i,k) / z; } diff --git a/Eigen/src/QR/ComplexSchur.h b/Eigen/src/QR/ComplexSchur.h index 153826811..b60be5430 100644 --- a/Eigen/src/QR/ComplexSchur.h +++ b/Eigen/src/QR/ComplexSchur.h @@ -80,6 +80,43 @@ template class ComplexSchur bool m_isInitialized; }; +/** Computes the principal value of the square root of the complex \a z. */ +template +std::complex ei_sqrt(const std::complex &z) +{ + RealScalar t, tre, tim; + + t = ei_abs(z); + + if (ei_abs(ei_real(z)) <= ei_abs(ei_real(z))) + { + // No cancellation in these formulas + tre = ei_sqrt(0.5*(t + ei_real(z))); + tim = ei_sqrt(0.5*(t - ei_real(z))); + } + else + { + // Stable computation of the above formulas + if (z.real() > 0) + { + tre = t + z.real(); + tim = ei_abs(ei_imag(z))*ei_sqrt(0.5/tre); + tre = ei_sqrt(0.5*tre); + } + else + { + tim = t - z.real(); + tre = ei_abs(ei_imag(z))*ei_sqrt(0.5/tim); + tim = ei_sqrt(0.5*tim); + } + } + if(z.imag() < 0) + tim = -tim; + + return (std::complex(tre,tim)); + +} + template void ComplexSchur::compute(const MatrixType& matrix) { @@ -146,7 +183,7 @@ void ComplexSchur::compute(const MatrixType& matrix) c = t.determinant(); b = t.diagonal().sum(); - disc = csqrt(b*b - RealScalar(4)*c); + disc = ei_sqrt(b*b - RealScalar(4)*c); r1 = (b+disc)/RealScalar(2); r2 = (b-disc)/RealScalar(2); @@ -183,56 +220,18 @@ void ComplexSchur::compute(const MatrixType& matrix) } // FIXME : is it necessary ? + /* for(int i=0 ; i -std::complex csqrt(const std::complex &z) -{ - RealScalar t, tre, tim; - - t = ei_abs(z); - - if (ei_abs(z.real()) <= ei_abs(z.imag())) - { - // No cancellation in these formulas - tre = ei_sqrt(0.5*(t+z.real())); - tim = ei_sqrt(0.5*(t-z.real())); - } - else - { - // Stable computation of the above formulas - if (z.real() > 0) - { - tre = t + z.real(); - tim = ei_abs(z.imag())*ei_sqrt(0.5/tre); - tre = ei_sqrt(0.5*tre); - } - else - { - tim = t - z.real(); - tre = ei_abs(z.imag())*ei_sqrt(0.5/tim); - tim = ei_sqrt(0.5*tim); - } - } - if(z.imag() < 0) - tim = -tim; - - return (std::complex(tre,tim)); - -} - - #endif // EIGEN_COMPLEX_SCHUR_H From 7d18c30641a57cde5246614e3f7dd88fe867a7b0 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 3 Sep 2009 01:25:40 -0400 Subject: [PATCH 28/66] finally the first version was the good one... --- Eigen/src/Core/Matrix.h | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index caa8d4be6..2fc38c812 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -490,13 +490,8 @@ class Matrix /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the * data pointers. */ - using Base::swap; - inline void swap(Matrix& other) - { - ei_assert(rows() == other.rows() && cols() == other.cols()); - m_storage.swap(other.m_storage); - // FIXME what about using this->Base::swap(other); for fixed size ? - } + template + void swap(const MatrixBase& other); /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, @@ -655,8 +650,37 @@ class Matrix m_storage.data()[0] = x; m_storage.data()[1] = y; } + + template + friend struct ei_matrix_swap_impl; }; +template::ret, + bool IsDynamicSize = MatrixType::SizeAtCompileTime==Dynamic> +struct ei_matrix_swap_impl +{ + static inline void run(MatrixType& matrix, MatrixBase& other) + { + matrix.base().swap(other); + } +}; + +template +struct ei_matrix_swap_impl +{ + static inline void run(MatrixType& matrix, MatrixBase& other) + { + matrix.m_storage.swap(other.derived().m_storage); + } +}; + +template +template +inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) +{ + ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); +} /** \defgroup matrixtypedefs Global matrix typedefs * From 89557ac41d50196f17d48ada5137fcf435abe73a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 3 Sep 2009 02:50:42 -0400 Subject: [PATCH 29/66] introduce EIGEN_SIZE_MIN now we should check if some EIGEN_ENUM_MIN usage needs to be replaced by that... potential bug when using mixed-size matrice --- Eigen/src/Core/util/Macros.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 4e00df759..ec8337e33 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -260,11 +260,11 @@ using Base::operator +=; \ using Base::operator -=; \ using Base::operator *=; \ using Base::operator /=; \ -EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ -{ \ - return Base::operator=(other); \ -} -#endif +EIGEN_STRONG_INLINE Derived& operator=(const Derived& other) \ +{ \ + return Base::operator=(other); \ +} +#endif #define _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ @@ -287,6 +287,9 @@ enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived, Eigen::MatrixBase) #define EIGEN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b) +#define EIGEN_SIZE_MIN(a,b) (((int)a == 1 || (int)b == 1) ? 1 \ + : ((int)a == Dynamic || (int)b == Dynamic) ? Dynamic \ + : ((int)a <= (int)b) ? (int)a : (int)b) #define EIGEN_ENUM_MAX(a,b) (((int)a >= (int)b) ? (int)a : (int)b) #define EIGEN_LOGICAL_XOR(a,b) (((a) || (b)) && !((a) && (b))) From 7aa6fd362558718304937ddfd60232c9802d69be Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 3 Sep 2009 02:53:51 -0400 Subject: [PATCH 30/66] big reorganization in JacobiSVD: - R-SVD preconditioning now done with meta selectors to avoid compiling useless code - SVD options now honored, with options to hint "at least as many rows as cols" etc... - fix compilation in bad cases (rectangular and fixed-size) - the check for termination is now done on the fly, no more goto (should have done that earlier!) --- Eigen/src/Core/util/Constants.h | 9 ++ Eigen/src/QR/FullPivotingHouseholderQR.h | 6 +- Eigen/src/SVD/JacobiSVD.h | 184 ++++++++++++++++------- test/jacobisvd.cpp | 37 +++-- 4 files changed, 156 insertions(+), 80 deletions(-) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 21e7f62c3..affc1d478 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -238,6 +238,15 @@ enum { OnTheRight = 2 }; +// options for SVD decomposition +enum { + SkipU = 0x1, + SkipV = 0x2, + AtLeastAsManyRowsAsCols = 0x4, + AtLeastAsManyColsAsRows = 0x8, + Square = AtLeastAsManyRowsAsCols | AtLeastAsManyColsAsRows +}; + /* the following could as well be written: * enum NoChange_t { NoChange }; * but it feels dangerous to disambiguate overloaded functions on enum/integer types. diff --git a/Eigen/src/QR/FullPivotingHouseholderQR.h b/Eigen/src/QR/FullPivotingHouseholderQR.h index 52405170b..0d542cf7a 100644 --- a/Eigen/src/QR/FullPivotingHouseholderQR.h +++ b/Eigen/src/QR/FullPivotingHouseholderQR.h @@ -67,12 +67,10 @@ template class FullPivotingHouseholderQR * The default constructor is useful in cases in which the user intends to * perform decompositions via FullPivotingHouseholderQR::compute(const MatrixType&). */ - FullPivotingHouseholderQR() : m_qr(), m_hCoeffs(), m_isInitialized(false) {} + FullPivotingHouseholderQR() : m_isInitialized(false) {} FullPivotingHouseholderQR(const MatrixType& matrix) - : m_qr(matrix.rows(), matrix.cols()), - m_hCoeffs(std::min(matrix.rows(),matrix.cols())), - m_isInitialized(false) + : m_isInitialized(false) { compute(matrix); } diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index ca359832b..2801ee077 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -33,8 +33,11 @@ * \brief Jacobi SVD decomposition of a square matrix * * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * \param ComputeU whether the U matrix should be computed - * \param ComputeV whether the V matrix should be computed + * \param Options a bit field of flags offering the following options: \c SkipU and \c SkipV allow to skip the computation of + * the unitaries \a U and \a V respectively; \c AtLeastAsManyRowsAsCols and \c AtLeastAsManyRowsAsCols allows + * to hint the compiler to only generate the corresponding code paths; \c Square is equivantent to the combination of + * the latter two bits and is useful when you know that the matrix is square. Note that when this information can + * be automatically deduced from the matrix type (e.g. a Matrix3f is always square), Eigen does it for you. * * \sa MatrixBase::jacobiSvd() */ @@ -44,14 +47,14 @@ template class JacobiSVD typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; enum { - ComputeU = 1, - ComputeV = 1, + ComputeU = (Options & SkipU) == 0, + ComputeV = (Options & SkipV) == 0, RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, - DiagSizeAtCompileTime = EIGEN_ENUM_MIN(RowsAtCompileTime,ColsAtCompileTime), + DiagSizeAtCompileTime = EIGEN_SIZE_MIN(RowsAtCompileTime,ColsAtCompileTime), MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - MaxDiagSizeAtCompileTime = EIGEN_ENUM_MIN(MaxRowsAtCompileTime,MaxColsAtCompileTime), + MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN(MaxRowsAtCompileTime,MaxColsAtCompileTime), MatrixOptions = MatrixType::Options }; @@ -65,9 +68,12 @@ template class JacobiSVD MatrixOptions, MaxColsAtCompileTime, MaxColsAtCompileTime>, DummyMatrixType>::ret MatrixVType; typedef Matrix SingularValuesType; + MatrixOptions, MaxDiagSizeAtCompileTime, 1> SingularValuesType; typedef Matrix RowType; typedef Matrix ColType; + typedef Matrix + WorkMatrixType; public: @@ -92,7 +98,7 @@ template class JacobiSVD return m_singularValues; } - const MatrixUType& matrixV() const + const MatrixVType& matrixV() const { ei_assert(m_isInitialized && "JacobiSVD is not initialized."); return m_matrixV; @@ -106,12 +112,17 @@ template class JacobiSVD template friend struct ei_svd_precondition_2x2_block_to_be_real; + template + friend struct ei_svd_precondition_if_more_rows_than_cols; + template + friend struct ei_svd_precondition_if_more_cols_than_rows; }; template::IsComplex> struct ei_svd_precondition_2x2_block_to_be_real { - static void run(MatrixType&, JacobiSVD&, int, int) {} + typedef JacobiSVD SVD; + static void run(typename SVD::WorkMatrixType&, JacobiSVD&, int, int) {} }; template @@ -120,9 +131,8 @@ struct ei_svd_precondition_2x2_block_to_be_real typedef JacobiSVD SVD; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - enum { ComputeU = SVD::ComputeU, ComputeV = SVD::ComputeV }; - static void run(MatrixType& work_matrix, JacobiSVD& svd, int p, int q) + static void run(typename SVD::WorkMatrixType& work_matrix, JacobiSVD& svd, int p, int q) { Scalar z; PlanarRotation rot; @@ -185,10 +195,94 @@ void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, *j_left = rot1 * j_right->transpose(); } +templateMatrixType::ColsAtCompileTime)> +struct ei_svd_precondition_if_more_rows_than_cols +{ + typedef JacobiSVD SVD; + static bool run(const MatrixType&, typename SVD::WorkMatrixType&, JacobiSVD&) { return false; } +}; + +template +struct ei_svd_precondition_if_more_rows_than_cols +{ + typedef JacobiSVD SVD; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + enum { ComputeU = SVD::ComputeU, ComputeV = SVD::ComputeV }; + static bool run(const MatrixType& matrix, typename SVD::WorkMatrixType& work_matrix, SVD& svd) + { + int rows = matrix.rows(); + int cols = matrix.cols(); + int diagSize = cols; + if(rows > cols) + { + FullPivotingHouseholderQR qr(matrix); + work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView(); + if(ComputeU) svd.m_matrixU = qr.matrixQ(); + if(ComputeV) + for(int i = 0; i < cols; i++) + svd.m_matrixV.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); + return true; + } + else return false; + } +}; + +templateMatrixType::RowsAtCompileTime)> +struct ei_svd_precondition_if_more_cols_than_rows +{ + typedef JacobiSVD SVD; + static bool run(const MatrixType&, typename SVD::WorkMatrixType&, JacobiSVD&) { return false; } +}; + +template +struct ei_svd_precondition_if_more_cols_than_rows +{ + typedef JacobiSVD SVD; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + enum { + ComputeU = SVD::ComputeU, + ComputeV = SVD::ComputeV, + RowsAtCompileTime = SVD::RowsAtCompileTime, + ColsAtCompileTime = SVD::ColsAtCompileTime, + MaxRowsAtCompileTime = SVD::MaxRowsAtCompileTime, + MaxColsAtCompileTime = SVD::MaxColsAtCompileTime, + MatrixOptions = SVD::MatrixOptions + }; + + static bool run(const MatrixType& matrix, typename SVD::WorkMatrixType& work_matrix, SVD& svd) + { + int rows = matrix.rows(); + int cols = matrix.cols(); + int diagSize = rows; + if(cols > rows) + { + typedef Matrix + TransposeTypeWithSameStorageOrder; + FullPivotingHouseholderQR qr(matrix.adjoint()); + work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView().adjoint(); + if(ComputeV) svd.m_matrixV = qr.matrixQ(); + if(ComputeU) + for(int i = 0; i < rows; i++) + svd.m_matrixU.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); + return true; + } + else return false; + } +}; + template JacobiSVD& JacobiSVD::compute(const MatrixType& matrix) { - MatrixType work_matrix; + WorkMatrixType work_matrix; int rows = matrix.rows(); int cols = matrix.cols(); int diagSize = std::min(rows, cols); @@ -197,65 +291,41 @@ JacobiSVD& JacobiSVD::compute(const Ma m_singularValues.resize(diagSize); const RealScalar precision = 2 * epsilon(); - if(rows > cols) + if(!ei_svd_precondition_if_more_rows_than_cols::run(matrix, work_matrix, *this) + && !ei_svd_precondition_if_more_cols_than_rows::run(matrix, work_matrix, *this)) { - FullPivotingHouseholderQR qr(matrix); - work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView(); - if(ComputeU) m_matrixU = qr.matrixQ(); - if(ComputeV) - for(int i = 0; i < cols; i++) - m_matrixV.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); - } - else if(rows < cols) - { - FullPivotingHouseholderQR qr(MatrixType(matrix.adjoint())); - work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView().adjoint(); - if(ComputeV) m_matrixV = qr.matrixQ(); - if(ComputeU) - for(int i = 0; i < rows; i++) - m_matrixU.coeffRef(qr.colsPermutation().coeff(i),i) = Scalar(1); - - } - else - { - work_matrix = matrix; + work_matrix = matrix.block(0,0,diagSize,diagSize); if(ComputeU) m_matrixU.diagonal().setOnes(); if(ComputeV) m_matrixV.diagonal().setOnes(); } -sweep_again: - for(int p = 1; p < diagSize; ++p) + + bool finished = false; + while(!finished) { - for(int q = 0; q < p; ++q) + finished = true; + for(int p = 1; p < diagSize; ++p) { - if(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p))) - > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision) + for(int q = 0; q < p; ++q) { - ei_svd_precondition_2x2_block_to_be_real::run(work_matrix, *this, p, q); + if(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p))) + > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision) + { + finished = false; + ei_svd_precondition_2x2_block_to_be_real::run(work_matrix, *this, p, q); - PlanarRotation j_left, j_right; - ei_real_2x2_jacobi_svd(work_matrix, p, q, &j_left, &j_right); + PlanarRotation j_left, j_right; + ei_real_2x2_jacobi_svd(work_matrix, p, q, &j_left, &j_right); - work_matrix.applyOnTheLeft(p,q,j_left); - if(ComputeU) m_matrixU.applyOnTheRight(p,q,j_left.transpose()); + work_matrix.applyOnTheLeft(p,q,j_left); + if(ComputeU) m_matrixU.applyOnTheRight(p,q,j_left.transpose()); - work_matrix.applyOnTheRight(p,q,j_right); - if(ComputeV) m_matrixV.applyOnTheRight(p,q,j_right); + work_matrix.applyOnTheRight(p,q,j_right); + if(ComputeV) m_matrixV.applyOnTheRight(p,q,j_right); + } } } } - RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff(); - RealScalar maxAllowedOffDiag = biggestOnDiag * precision; - for(int p = 0; p < diagSize; ++p) - { - for(int q = 0; q < p; ++q) - if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) - goto sweep_again; - for(int q = p+1; q < diagSize; ++q) - if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag) - goto sweep_again; - } - for(int i = 0; i < diagSize; ++i) { RealScalar a = ei_abs(work_matrix.coeff(i,i)); diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 8b4c7584e..5940b8497 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -27,7 +27,7 @@ #include #include -template void svd(const MatrixType& m, bool pickrandom = true) +template void svd(const MatrixType& m = MatrixType(), bool pickrandom = true) { int rows = m.rows(); int cols = m.cols(); @@ -48,7 +48,7 @@ template void svd(const MatrixType& m, bool pickrandom = tr if(pickrandom) a = MatrixType::Random(rows,cols); else a = m; - JacobiSVD svd(a); + JacobiSVD svd(a); MatrixType sigma = MatrixType::Zero(rows,cols); sigma.diagonal() = svd.singularValues().template cast(); MatrixUType u = svd.matrixU(); @@ -80,28 +80,27 @@ void test_jacobisvd() Matrix2cd m; m << 0, 1, 0, 1; - CALL_SUBTEST( svd(m, false) ); + CALL_SUBTEST(( svd(m, false) )); m << 1, 0, 1, 0; - CALL_SUBTEST( svd(m, false) ); + CALL_SUBTEST(( svd(m, false) )); Matrix2d n; n << 1, 1, 1, -1; - CALL_SUBTEST( svd(n, false) ); - CALL_SUBTEST( svd(Matrix3f()) ); - CALL_SUBTEST( svd(Matrix4d()) ); - CALL_SUBTEST( svd(MatrixXf(50,50)) ); - CALL_SUBTEST( svd(MatrixXcd(14,7)) ); - CALL_SUBTEST( svd(MatrixXd(10,50)) ); - - CALL_SUBTEST( svd(MatrixXcf(3,3)) ); - CALL_SUBTEST( svd(MatrixXd(30,30)) ); + CALL_SUBTEST(( svd(n, false) )); + CALL_SUBTEST(( svd() )); + CALL_SUBTEST(( svd() )); + CALL_SUBTEST(( svd , AtLeastAsManyColsAsRows>() )); + CALL_SUBTEST(( svd , AtLeastAsManyRowsAsCols>(Matrix(10,2)) )); + + CALL_SUBTEST(( svd(MatrixXf(50,50)) )); + CALL_SUBTEST(( svd(MatrixXcd(14,7)) )); } - CALL_SUBTEST( svd(MatrixXf(300,200)) ); - CALL_SUBTEST( svd(MatrixXcd(100,150)) ); + CALL_SUBTEST(( svd(MatrixXf(300,200)) )); + CALL_SUBTEST(( svd(MatrixXcd(100,150)) )); - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); + CALL_SUBTEST(( svd_verify_assert() )); + CALL_SUBTEST(( svd_verify_assert() )); + CALL_SUBTEST(( svd_verify_assert() )); + CALL_SUBTEST(( svd_verify_assert() )); } From 2abd5eeffd61523ad87f6b44bcebdd083a5324b8 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 2 Sep 2009 20:57:41 +0200 Subject: [PATCH 31/66] Added support to overwrite the generator type. Eigen'fied the new variables. --- test/testsuite.cmake | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/test/testsuite.cmake b/test/testsuite.cmake index 6a44ce239..37ee87565 100644 --- a/test/testsuite.cmake +++ b/test/testsuite.cmake @@ -27,6 +27,13 @@ # - EIGEN_WORK_DIR: directory used to download the source files and make the builds # default: folder which contains this script # - EIGEN_CMAKE_ARGS: additional arguments passed to cmake +# - EIGEN_GENERATOR_TYPE: allows to overwrite the generator type +# default: nmake (windows +# See http://www.cmake.org/cmake/help/cmake2.6docs.html#section_Generators for a complete +# list of supported generators. +# - EIGEN_NO_UPDATE: allows to submit dash boards from local repositories +# This might be interesting in case you want to submit dashboards +# including local changes. # - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on) # default: /src # - CTEST_BINARY_DIRECTORY: build directory @@ -132,11 +139,11 @@ endif(NOT EIGEN_MODE) ## mandatory variables (the default should be ok in most cases): -if(NOT IGNORE_CVS) +if(NOT EIGEN_NO_UPDATE) SET (CTEST_CVS_COMMAND "hg") SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone http://bitbucket.org/eigen/eigen2 \"${CTEST_SOURCE_DIRECTORY}\"") SET(CTEST_BACKUP_AND_RESTORE TRUE) # the backup is CVS related ... -endif(NOT IGNORE_CVS) +endif(NOT EIGEN_NO_UPDATE) # which ctest command to use for running the dashboard SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}") @@ -158,15 +165,24 @@ SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE) # any quotes inside of this string if you use it if(WIN32 AND NOT UNIX) #message(SEND_ERROR "win32") - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake") - SET (CTEST_INITIAL_CACHE " - MAKECOMMAND:STRING=nmake -i - CMAKE_MAKE_PROGRAM:FILEPATH=nmake - CMAKE_GENERATOR:INTERNAL=NMake Makefiles - CMAKE_BUILD_TYPE:STRING=Release - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") + if(EIGEN_GENERATOR_TYPE) + set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"${EIGEN_GENERATOR_TYPE}\"") + SET (CTEST_INITIAL_CACHE " + CMAKE_BUILD_TYPE:STRING=Release + BUILDNAME:STRING=${EIGEN_BUILD_STRING} + SITE:STRING=${EIGEN_SITE} + ") + else(EIGEN_GENERATOR_TYPE) + set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake") + SET (CTEST_INITIAL_CACHE " + MAKECOMMAND:STRING=nmake -i + CMAKE_MAKE_PROGRAM:FILEPATH=nmake + CMAKE_GENERATOR:INTERNAL=NMake Makefiles + CMAKE_BUILD_TYPE:STRING=Release + BUILDNAME:STRING=${EIGEN_BUILD_STRING} + SITE:STRING=${EIGEN_SITE} + ") + endif(EIGEN_GENERATOR_TYPE) else(WIN32 AND NOT UNIX) SET (CTEST_INITIAL_CACHE " BUILDNAME:STRING=${EIGEN_BUILD_STRING} From e6c9d6c5285d0dd1ab8b72bb9ce9901d8078fc8f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 2 Sep 2009 20:59:57 +0200 Subject: [PATCH 32/66] Remove last lazyness warnings. --- test/product_notemporary.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 36a5a66ed..3b0329f43 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -69,7 +69,6 @@ template void product_notemporary(const MatrixType& m) r1 = ei_random(8,rows-r0); VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1); - VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0); // NOTE in this case the slow product is used: @@ -79,16 +78,14 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * (m1*s3+m2*s2).adjoint(), 1); VERIFY_EVALUATION_COUNT( m3.noalias() = (s1 * m1).adjoint() * s2 * m2, 0); - VERIFY_EVALUATION_COUNT( m3 += (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0); - VERIFY_EVALUATION_COUNT( m3 -= (s1 * (m1.transpose() * m2)).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() += -m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint() ), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() -= s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1) ), 0); // NOTE this is because the Block expression is not handled yet by our expression analyser - VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) = (s1 * m1.block(r0,c0,r1,c1) * (s1*m2).block(c0,r0,c1,r1)).lazy() ), 1); + VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() = s1 * m1.block(r0,c0,r1,c1) * (s1*m2).block(c0,r0,c1,r1) ), 1); VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).template triangularView() * m2, 0); VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView() * (m2+m2), 1); From 8d449bd80e6e34506dae1be31478dc46a87f663b Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 2 Sep 2009 21:23:09 +0200 Subject: [PATCH 33/66] Removed debug cout. Disabled MSVC inconsistent DLL linkage. --- Eigen/QtAlignedMalloc | 6 +++++- Eigen/src/Core/util/DisableMSVCWarnings.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Eigen/QtAlignedMalloc b/Eigen/QtAlignedMalloc index de4da752c..fce7edf9b 100644 --- a/Eigen/QtAlignedMalloc +++ b/Eigen/QtAlignedMalloc @@ -6,8 +6,10 @@ #if (!EIGEN_MALLOC_ALREADY_ALIGNED) +#include "src/Core/util/DisableMSVCWarnings.h" + void *qMalloc(size_t size) -{std::cerr << "ok\n"; +{ return Eigen::ei_aligned_malloc(size); } @@ -24,6 +26,8 @@ void *qRealloc(void *ptr, size_t size) return newPtr; } +#include "src/Core/util/EnableMSVCWarnings.h" + #endif #endif // EIGEN_QTMALLOC_MODULE_H diff --git a/Eigen/src/Core/util/DisableMSVCWarnings.h b/Eigen/src/Core/util/DisableMSVCWarnings.h index ca8e245b3..c08d0389f 100644 --- a/Eigen/src/Core/util/DisableMSVCWarnings.h +++ b/Eigen/src/Core/util/DisableMSVCWarnings.h @@ -1,5 +1,6 @@ #ifdef _MSC_VER + // 4273 - QtAlignedMalloc, inconsistent dll linkage #pragma warning( push ) - #pragma warning( disable : 4181 4244 4127 4211 4522 4717 ) + #pragma warning( disable : 4181 4244 4127 4211 4273 4522 4717 ) #endif From c893917d65724aee15cad8c2d5d711d991c361c9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 10:45:32 +0200 Subject: [PATCH 34/66] Fix serious bug discovered with gcc 4.2 --- Eigen/src/Core/Product.h | 12 ++++++------ Eigen/src/Core/SolveTriangular.h | 4 ++-- Eigen/src/Core/products/GeneralMatrixMatrix.h | 6 +++--- Eigen/src/Core/products/SelfadjointMatrixVector.h | 4 ++-- Eigen/src/Core/products/SelfadjointProduct.h | 2 +- Eigen/src/Core/products/SelfadjointRank2Update.h | 2 +- Eigen/src/Core/products/TriangularMatrixVector.h | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index f4c8af6ea..5c6cee426 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -63,7 +63,7 @@ template struct ei_product_type Cols = Rhs::ColsAtCompileTime, Depth = EIGEN_ENUM_MIN(Lhs::ColsAtCompileTime,Rhs::RowsAtCompileTime) }; - + // the splitting into different lines of code here, introducing the _select enums and the typedef below, // is to work around an internal compiler error with gcc 4.1 and 4.2. private: @@ -73,7 +73,7 @@ private: depth_select = Depth>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ? Large : (Depth==1 ? 1 : Small) }; typedef ei_product_type_selector product_type_selector; - + public: enum { value = product_type_selector::ret @@ -144,7 +144,7 @@ struct ProductReturnType ***********************************************************************/ // FIXME : maybe the "inner product" could return a Scalar -// instead of a 1x1 matrix ?? +// instead of a 1x1 matrix ?? // Pro: more natural for the user // Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix // product ends up to a row-vector times col-vector product... To tackle this use @@ -201,7 +201,7 @@ class GeneralProduct template void scaleAndAddTo(Dest& dest, Scalar alpha) const { - ei_outer_product_selector::run(*this, dest, alpha); + ei_outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); } }; @@ -259,7 +259,7 @@ class GeneralProduct template void scaleAndAddTo(Dest& dst, Scalar alpha) const { ei_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - ei_gemv_selector::ActualAccess)>::run(*this, dst, alpha); } }; @@ -339,7 +339,7 @@ template<> struct ei_gemv_selector Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) * RhsBlasTraits::extractScalarFactor(prod.rhs()); - + enum { DirectlyUseRhs = ((ei_packet_traits::size==1) || (_ActualRhsType::Flags&ActualPacketAccessBit)) && (!(_ActualRhsType::Flags & RowMajorBit)) diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h index 810b08240..c7f0cd227 100644 --- a/Eigen/src/Core/SolveTriangular.h +++ b/Eigen/src/Core/SolveTriangular.h @@ -30,7 +30,7 @@ template struct ei_triangular_solver_selector; @@ -157,7 +157,7 @@ struct ei_triangular_solver_selector + (Rhs::Flags&RowMajorBit) ? RowMajor : ColMajor> ::run(lhs.rows(), Side==OnTheLeft? rhs.cols() : rhs.rows(), &actualLhs.coeff(0,0), actualLhs.stride(), &rhs.coeffRef(0,0), rhs.stride()); } }; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 8b3b13266..c4692b872 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -149,9 +149,9 @@ class GeneralProduct ei_general_matrix_matrix_product< Scalar, - (_ActualLhsType::Flags&RowMajorBit)?RowMajor:ColMajor, bool(LhsBlasTraits::NeedToConjugate), - (_ActualRhsType::Flags&RowMajorBit)?RowMajor:ColMajor, bool(RhsBlasTraits::NeedToConjugate), - (Dest::Flags&RowMajorBit)?RowMajor:ColMajor> + (_ActualLhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), + (_ActualRhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), + (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor> ::run( this->rows(), this->cols(), lhs.cols(), (const Scalar*)&(lhs.const_cast_derived().coeffRef(0,0)), lhs.stride(), diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index d5927307d..c27454bee 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -41,7 +41,7 @@ static EIGEN_DONT_INLINE void ei_product_selfadjoint_vector( const int PacketSize = sizeof(Packet)/sizeof(Scalar); enum { - IsRowMajor = StorageOrder==RowMajorBit ? 1 : 0, + IsRowMajor = StorageOrder==RowMajor ? 1 : 0, IsLower = UpLo == LowerTriangularBit ? 1 : 0, FirstTriangular = IsRowMajor == IsLower }; @@ -186,7 +186,7 @@ struct SelfadjointProductMatrix * RhsBlasTraits::extractScalarFactor(m_rhs); ei_assert(dst.stride()==1 && "not implemented yet"); - ei_product_selfadjoint_vector::Flags&RowMajorBit, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)> + ei_product_selfadjoint_vector::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)> ( lhs.rows(), // size &lhs.coeff(0,0), lhs.stride(), // lhs info diff --git a/Eigen/src/Core/products/SelfadjointProduct.h b/Eigen/src/Core/products/SelfadjointProduct.h index d3fc962d9..f9cdda637 100644 --- a/Eigen/src/Core/products/SelfadjointProduct.h +++ b/Eigen/src/Core/products/SelfadjointProduct.h @@ -132,7 +132,7 @@ SelfAdjointView& SelfAdjointView Scalar actualAlpha = alpha * UBlasTraits::extractScalarFactor(u.derived()); - enum { IsRowMajor = (ei_traits::Flags&RowMajorBit)?1:0 }; + enum { IsRowMajor = (ei_traits::Flags&RowMajorBit) ? 1 : 0 }; ei_selfadjoint_product& SelfAdjointView Scalar actualAlpha = alpha * UBlasTraits::extractScalarFactor(u.derived()) * VBlasTraits::extractScalarFactor(v.derived()); - enum { IsRowMajor = (ei_traits::Flags&RowMajorBit)?1:0 }; + enum { IsRowMajor = (ei_traits::Flags&RowMajorBit) ? 1 : 0 }; ei_selfadjoint_rank2_update_selector::ret>::type, typename ei_cleantype::ret>::type, diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index 620b090b9..291177445 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h @@ -145,7 +145,7 @@ struct TriangularProduct Mode, LhsBlasTraits::NeedToConjugate, RhsBlasTraits::NeedToConjugate, - ei_traits::Flags&RowMajorBit> + (int(ei_traits::Flags)&RowMajorBit) ? RowMajor : ColMajor> ::run(lhs,rhs,dst,actualAlpha); } }; From 16c7b1daabd2697950605706a8bc68ae32d70fc8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 11:17:16 +0200 Subject: [PATCH 35/66] add examples for makeJacobi and makeGivens --- Eigen/Jacobi | 6 ++++- Eigen/src/Jacobi/Jacobi.h | 39 +++++++++++++++++++++-------- doc/Doxyfile.in | 1 + doc/snippets/Jacobi_makeGivens.cpp | 6 +++++ doc/snippets/Jacobi_makeJacobi.cpp | 8 ++++++ doc/snippets/compile_snippet.cpp.in | 1 + 6 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 doc/snippets/Jacobi_makeGivens.cpp create mode 100644 doc/snippets/Jacobi_makeJacobi.cpp diff --git a/Eigen/Jacobi b/Eigen/Jacobi index 33a6b757e..da67d2a6a 100644 --- a/Eigen/Jacobi +++ b/Eigen/Jacobi @@ -8,11 +8,15 @@ namespace Eigen { /** \defgroup Jacobi_Module Jacobi module - * This module provides Jacobi rotations. + * This module provides Jacobi and Givens rotations. * * \code * #include * \endcode + * + * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation: + * - MatrixBase::applyOnTheLeft() + * - MatrixBase::applyOnTheRight(). */ #include "src/Jacobi/Jacobi.h" diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 66ba06b19..3e3cce665 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -26,16 +26,23 @@ #ifndef EIGEN_JACOBI_H #define EIGEN_JACOBI_H -/** \ingroup Jacobi +/** \ingroup Jacobi_Module + * \jacobi_module * \class PlanarRotation * \brief Represents a rotation in the plane from a cosine-sine pair. * * This class represents a Jacobi or Givens rotation. - * This is a 2D clock-wise rotation in the plane \c J of angle \f$ \theta \f$ defined by + * This is a 2D rotation in the plane \c J of angle \f$ \theta \f$ defined by * its cosine \c c and sine \c s as follow: * \f$ J = \left ( \begin{array}{cc} c & \overline s \\ -s & \overline c \end{array} \right ) \f$ * - * \sa MatrixBase::makeJacobi(), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() + * You can apply the respective counter-clockwise rotation to a column vector \c v by + * applying its adjoint on the left: \f$ v = J^* v \f$ that translates to the following Eigen code: + * \code + * v.applyOnTheLeft(J.adjoint()); + * \endcode + * + * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template class PlanarRotation { @@ -79,11 +86,10 @@ template class PlanarRotation Scalar m_c, m_s; }; -/** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the 2x2 matrix - * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields - * a diagonal matrix \f$ A = J^* B J \f$ +/** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the selfadjoint 2x2 matrix + * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$ * - * \sa MatrixBase::makeJacobi(), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() + * \sa MatrixBase::makeJacobi(const MatrixBase&, int, int), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) @@ -116,10 +122,13 @@ bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) } } -/** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 matrix +/** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 selfadjoint matrix * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ * & \text{this}_{qq} \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * + * Example: \include Jacobi_makeJacobi.cpp + * Output: \verbinclude Jacobi_makeJacobi.out + * * \sa PlanarRotation::makeJacobi(RealScalar, Scalar, RealScalar), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template @@ -136,6 +145,9 @@ inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int * The value of \a z is returned if \a z is not null (the default is null). * Also note that G is built such that the cosine is always real. * + * Example: \include Jacobi_makeGivens.cpp + * Output: \verbinclude Jacobi_makeGivens.out + * * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template @@ -171,9 +183,11 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar } // specialization for reals +// TODO compute z template void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false) { + ei_assert(z==0 && "not implemented yet"); // from Golub's "Matrix Computations", algorithm 5.1.3 if(q==0) { @@ -197,7 +211,8 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar * Implementation of MatrixBase methods ****************************************************************************************/ -/** Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: +/** \jacobi_module + * Applies the clock wise 2D rotation \a j to the set of 2D vectors of cordinates \a x and \a y: * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right ) = J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$ * * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() @@ -205,7 +220,8 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar template void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, const PlanarRotation& j); -/** Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B, +/** \jacobi_module + * Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B, * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$. * * \sa class PlanarRotation, MatrixBase::applyOnTheRight(), ei_apply_rotation_in_the_plane() @@ -219,7 +235,8 @@ inline void MatrixBase::applyOnTheLeft(int p, int q, const PlanarRotati ei_apply_rotation_in_the_plane(x, y, j); } -/** Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J +/** \ingroup Jacobi_Module + * Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$. * * \sa class PlanarRotation, MatrixBase::applyOnTheLeft(), ei_apply_rotation_in_the_plane() diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index cd67bb07d..a66750c3e 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -208,6 +208,7 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "lu_module=This is defined in the %LU module. \code #include \endcode" \ "cholesky_module=This is defined in the %Cholesky module. \code #include \endcode" \ "qr_module=This is defined in the %QR module. \code #include \endcode" \ + "jacobi_module=This is defined in the %Jacobi module. \code #include \endcode" \ "svd_module=This is defined in the %SVD module. \code #include \endcode" \ "geometry_module=This is defined in the %Geometry module. \code #include \endcode" \ "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" \ diff --git a/doc/snippets/Jacobi_makeGivens.cpp b/doc/snippets/Jacobi_makeGivens.cpp new file mode 100644 index 000000000..3a4defe24 --- /dev/null +++ b/doc/snippets/Jacobi_makeGivens.cpp @@ -0,0 +1,6 @@ +Vector2f v = Vector2f::Random(); +PlanarRotation G; +G.makeGivens(v.x(), v.y()); +cout << "Here is the vector v:" << endl << v << endl; +v.applyOnTheLeft(0, 1, G.adjoint()); +cout << "Here is the vector J' * v:" << endl << v << endl; \ No newline at end of file diff --git a/doc/snippets/Jacobi_makeJacobi.cpp b/doc/snippets/Jacobi_makeJacobi.cpp new file mode 100644 index 000000000..5c0ab7374 --- /dev/null +++ b/doc/snippets/Jacobi_makeJacobi.cpp @@ -0,0 +1,8 @@ +Matrix2f m = Matrix2f::Random(); +m = (m + m.adjoint()).eval(); +PlanarRotation J; +J.makeJacobi(m, 0, 1); +cout << "Here is the matrix m:" << endl << m << endl; +m.applyOnTheLeft(0, 1, J.adjoint()); +m.applyOnTheRight(0, 1, J); +cout << "Here is the matrix J' * m * J:" << endl << m << endl; \ No newline at end of file diff --git a/doc/snippets/compile_snippet.cpp.in b/doc/snippets/compile_snippet.cpp.in index d074cac50..3bea1ac8d 100644 --- a/doc/snippets/compile_snippet.cpp.in +++ b/doc/snippets/compile_snippet.cpp.in @@ -4,6 +4,7 @@ #include #include #include +#include using namespace Eigen; using namespace std; From 9515b00876ab8e84ae4beb61e8661400ebb49522 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 11:22:42 +0200 Subject: [PATCH 36/66] remove the \addexample tags --- Eigen/src/Array/BooleanRedux.h | 8 +++----- Eigen/src/Array/Random.h | 10 ++++------ Eigen/src/Core/Block.h | 10 ---------- Eigen/src/Core/CommaInitializer.h | 2 -- Eigen/src/Core/CwiseBinaryOp.h | 2 -- Eigen/src/Core/CwiseNullaryOp.h | 6 ------ Eigen/src/Core/CwiseUnaryOp.h | 2 -- Eigen/src/Core/CwiseUnaryView.h | 2 -- Eigen/src/Core/DiagonalMatrix.h | 26 ++++++++++++-------------- Eigen/src/Core/VectorBlock.h | 12 ++---------- Eigen/src/Geometry/AngleAxis.h | 4 +--- doc/Doxyfile.in | 1 - unsupported/Eigen/BVH | 2 -- unsupported/doc/Doxyfile.in | 1 - 14 files changed, 22 insertions(+), 66 deletions(-) diff --git a/Eigen/src/Array/BooleanRedux.h b/Eigen/src/Array/BooleanRedux.h index 6a5e208de..ab6e06d56 100644 --- a/Eigen/src/Array/BooleanRedux.h +++ b/Eigen/src/Array/BooleanRedux.h @@ -78,10 +78,8 @@ struct ei_any_unroller }; /** \array_module - * - * \returns true if all coefficients are true * - * \addexample CwiseAll \label How to check whether a point is inside a box (using operator< and all()) + * \returns true if all coefficients are true * * Example: \include MatrixBase_all.cpp * Output: \verbinclude MatrixBase_all.out @@ -107,7 +105,7 @@ inline bool MatrixBase::all() const } /** \array_module - * + * * \returns true if at least one coefficient is true * * \sa MatrixBase::all() @@ -131,7 +129,7 @@ inline bool MatrixBase::any() const } /** \array_module - * + * * \returns the number of coefficients which evaluate to true * * \sa MatrixBase::all(), MatrixBase::any() diff --git a/Eigen/src/Array/Random.h b/Eigen/src/Array/Random.h index 15cc6ae7c..adadf99e3 100644 --- a/Eigen/src/Array/Random.h +++ b/Eigen/src/Array/Random.h @@ -34,7 +34,7 @@ struct ei_functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; /** \array_module - * + * * \returns a random matrix expression * * The parameters \a rows and \a cols are the number of rows and of columns of @@ -44,8 +44,6 @@ struct ei_functor_traits > * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. * - * \addexample RandomExample \label How to create a matrix with random coefficients - * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out * @@ -63,7 +61,7 @@ MatrixBase::Random(int rows, int cols) } /** \array_module - * + * * \returns a random vector expression * * The parameter \a size is the size of the returned vector. @@ -92,7 +90,7 @@ MatrixBase::Random(int size) } /** \array_module - * + * * \returns a fixed-size random matrix or vector expression * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you @@ -115,7 +113,7 @@ MatrixBase::Random() } /** \array_module - * + * * Sets all coefficients in this expression to random values. * * Example: \include MatrixBase_setRandom.cpp diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 42d6bc3c3..cebfeaf75 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -308,8 +308,6 @@ class Block * \param blockRows the number of rows in the block * \param blockCols the number of columns in the block * - * \addexample BlockIntIntIntInt \label How to reference a sub-matrix (dynamic-size) - * * Example: \include MatrixBase_block_int_int_int_int.cpp * Output: \verbinclude MatrixBase_block_int_int_int_int.out * @@ -341,8 +339,6 @@ inline const typename BlockReturnType::Type MatrixBase * \param cRows the number of rows in the corner * \param cCols the number of columns in the corner * - * \addexample BlockCornerDynamicSize \label How to reference a sub-corner of a matrix - * * Example: \include MatrixBase_corner_enum_int_int.cpp * Output: \verbinclude MatrixBase_corner_enum_int_int.out * @@ -452,8 +448,6 @@ MatrixBase::corner(CornerType type) const * \param startRow the first row in the block * \param startCol the first column in the block * - * \addexample BlockSubMatrixFixedSize \label How to reference a sub-matrix (fixed-size) - * * Example: \include MatrixBase_block_int_int.cpp * Output: \verbinclude MatrixBase_block_int_int.out * @@ -480,8 +474,6 @@ MatrixBase::block(int startRow, int startCol) const } /** \returns an expression of the \a i-th column of *this. Note that the numbering starts at 0. - * - * \addexample BlockColumn \label How to reference a single column of a matrix * * Example: \include MatrixBase_col.cpp * Output: \verbinclude MatrixBase_col.out @@ -503,8 +495,6 @@ MatrixBase::col(int i) const } /** \returns an expression of the \a i-th row of *this. Note that the numbering starts at 0. - * - * \addexample BlockRow \label How to reference a single row of a matrix * * Example: \include MatrixBase_row.cpp * Output: \verbinclude MatrixBase_row.out diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h index c0dd701f2..e86f47ad0 100644 --- a/Eigen/src/Core/CommaInitializer.h +++ b/Eigen/src/Core/CommaInitializer.h @@ -124,8 +124,6 @@ struct CommaInitializer * The coefficients must be provided in a row major order and exactly match * the size of the matrix. Otherwise an assertion is raised. * - * \addexample CommaInit \label How to easily set all the coefficients of a matrix - * * Example: \include MatrixBase_set.cpp * Output: \verbinclude MatrixBase_set.out * diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 78de9fbce..875bc9aa5 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -291,8 +291,6 @@ Cwise::max(const MatrixBase &other) const * The template parameter \a CustomBinaryOp is the type of the functor * of the custom operator (see class CwiseBinaryOp for an example) * - * \addexample CustomCwiseBinaryFunctors \label How to use custom coeff wise binary functors - * * Here is an example illustrating the use of custom functors: * \include class_CwiseBinaryOp.cpp * Output: \verbinclude class_CwiseBinaryOp.out diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index 804bc2e74..61ce51885 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -317,8 +317,6 @@ Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::setConstant(int row * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * - * \addexample Zero \label How to take get a zero matrix - * * Example: \include MatrixBase_zero_int_int.cpp * Output: \verbinclude MatrixBase_zero_int_int.out * @@ -448,8 +446,6 @@ Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::setZero(int rows, i * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used * instead. * - * \addexample One \label How to get a matrix with all coefficients equal one - * * Example: \include MatrixBase_ones_int_int.cpp * Output: \verbinclude MatrixBase_ones_int_int.out * @@ -576,8 +572,6 @@ Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::setOnes(int rows, i * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used * instead. * - * \addexample Identity \label How to get an identity matrix - * * Example: \include MatrixBase_identity_int_int.cpp * Output: \verbinclude MatrixBase_identity_int_int.out * diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index d701c25d9..6e4c0d4ec 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -109,8 +109,6 @@ class CwiseUnaryOp : ei_no_assignment_operator, * The template parameter \a CustomUnaryOp is the type of the functor * of the custom unary operator. * - * \addexample CustomCwiseUnaryFunctors \label How to use custom coeff wise unary functors - * * Example: * \include class_CwiseUnaryOp.cpp * Output: \verbinclude class_CwiseUnaryOp.out diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 4b7d87953..580344379 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -98,8 +98,6 @@ class CwiseUnaryView : public MatrixBase > * The template parameter \a CustomUnaryOp is the type of the functor * of the custom unary operator. * - * \addexample CustomCwiseUnaryFunctors \label How to use custom coeff wise unary functors - * * Example: * \include class_CwiseUnaryOp.cpp * Output: \verbinclude class_CwiseUnaryOp.out diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index ebbed15d4..a74695921 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -32,7 +32,7 @@ class DiagonalBase : public AnyMatrixBase public: typedef typename ei_traits::DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; - + enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -41,14 +41,14 @@ class DiagonalBase : public AnyMatrixBase IsVectorAtCompileTime = 0, Flags = 0 }; - + typedef Matrix DenseMatrixType; - + #ifndef EIGEN_PARSED_BY_DOXYGEN inline const Derived& derived() const { return *static_cast(this); } inline Derived& derived() { return *static_cast(this); } #endif // not EIGEN_PARSED_BY_DOXYGEN - + DenseMatrixType toDenseMatrix() const { return derived(); } template void evalToDense(MatrixBase &other) const; @@ -64,7 +64,7 @@ class DiagonalBase : public AnyMatrixBase inline int rows() const { return diagonal().size(); } inline int cols() const { return diagonal().size(); } - + template const DiagonalProduct operator*(const MatrixBase &matrix) const; @@ -100,20 +100,20 @@ class DiagonalMatrix : public DiagonalBase > { public: - + typedef typename ei_traits::DiagonalVectorType DiagonalVectorType; typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; - + protected: DiagonalVectorType m_diagonal; - + public: inline const DiagonalVectorType& diagonal() const { return m_diagonal; } inline DiagonalVectorType& diagonal() { return m_diagonal; } - + /** Default constructor without initialization */ inline DiagonalMatrix() {} @@ -152,7 +152,7 @@ class DiagonalMatrix m_diagonal = other.m_diagonal(); return *this; } - + inline void resize(int size) { m_diagonal.resize(size); } inline void setZero() { m_diagonal.setZero(); } inline void setZero(int size) { m_diagonal.setZero(size); } @@ -194,10 +194,10 @@ class DiagonalWrapper public: typedef _DiagonalVectorType DiagonalVectorType; typedef DiagonalWrapper Nested; - + inline DiagonalWrapper(const DiagonalVectorType& diagonal) : m_diagonal(diagonal) {} const DiagonalVectorType& diagonal() const { return m_diagonal; } - + protected: const typename DiagonalVectorType::Nested m_diagonal; }; @@ -207,8 +207,6 @@ class DiagonalWrapper * * \only_for_vectors * - * \addexample AsDiagonalExample \label How to build a diagonal matrix from a vector - * * Example: \include MatrixBase_asDiagonal.cpp * Output: \verbinclude MatrixBase_asDiagonal.out * diff --git a/Eigen/src/Core/VectorBlock.h b/Eigen/src/Core/VectorBlock.h index 7ce5977f6..b291f7b1a 100644 --- a/Eigen/src/Core/VectorBlock.h +++ b/Eigen/src/Core/VectorBlock.h @@ -88,7 +88,7 @@ template class VectorBlock using Base::operator-=; using Base::operator*=; using Base::operator/=; - + /** Dynamic-size constructor */ inline VectorBlock(const VectorType& vector, int start, int size) @@ -96,7 +96,7 @@ template class VectorBlock IsColVector ? start : 0, IsColVector ? 0 : start, IsColVector ? size : 1, IsColVector ? 1 : size) { - + EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorBlock); } @@ -114,8 +114,6 @@ template class VectorBlock * * \only_for_vectors * - * \addexample VectorBlockIntInt \label How to reference a sub-vector (dynamic size) - * * \param start the first coefficient in the segment * \param size the number of coefficients in the segment * @@ -151,8 +149,6 @@ MatrixBase::segment(int start, int size) const * * \param size the number of coefficients in the block * - * \addexample BlockInt \label How to reference a sub-vector (fixed-size) - * * Example: \include MatrixBase_start_int.cpp * Output: \verbinclude MatrixBase_start_int.out * @@ -185,8 +181,6 @@ MatrixBase::start(int size) const * * \param size the number of coefficients in the block * - * \addexample BlockEnd \label How to reference the end of a vector (fixed-size) - * * Example: \include MatrixBase_end_int.cpp * Output: \verbinclude MatrixBase_end_int.out * @@ -251,8 +245,6 @@ MatrixBase::segment(int start) const * * The template parameter \a Size is the number of coefficients in the block * - * \addexample BlockStart \label How to reference the start of a vector (fixed-size) - * * Example: \include MatrixBase_template_int_start.cpp * Output: \verbinclude MatrixBase_template_int_start.out * diff --git a/Eigen/src/Geometry/AngleAxis.h b/Eigen/src/Geometry/AngleAxis.h index 9fd239354..b9dfa6972 100644 --- a/Eigen/src/Geometry/AngleAxis.h +++ b/Eigen/src/Geometry/AngleAxis.h @@ -39,8 +39,6 @@ * \li \c AngleAxisf for \c float * \li \c AngleAxisd for \c double * - * \addexample AngleAxisForEuler \label How to define a rotation from Euler-angles - * * Combined with MatrixBase::Unit{X,Y,Z}, AngleAxis can be used to easily * mimic Euler-angles. Here is an example: * \include AngleAxis_mimic_euler.cpp @@ -85,7 +83,7 @@ public: AngleAxis() {} /** Constructs and initialize the angle-axis rotation from an \a angle in radian * and an \a axis which \b must \b be \b normalized. - * + * * \warning If the \a axis vector is not normalized, then the angle-axis object * represents an invalid rotation. */ template diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index a66750c3e..dba66c0d9 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -212,7 +212,6 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "svd_module=This is defined in the %SVD module. \code #include \endcode" \ "geometry_module=This is defined in the %Geometry module. \code #include \endcode" \ "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" \ - "addexample=\anchor" \ "label=\bug" \ "redstar=*" \ "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" diff --git a/unsupported/Eigen/BVH b/unsupported/Eigen/BVH index 7b9c3c7c6..f307da2f7 100644 --- a/unsupported/Eigen/BVH +++ b/unsupported/Eigen/BVH @@ -94,8 +94,6 @@ namespace Eigen { * responsibility of the intersectObject function to keep track of the results in whatever manner is appropriate. * The cartesian product intersection and the BVMinimize queries are similar--see their individual documentation. * - * \addexample BVH_Example \label How to use a BVH to find the closest pair between two point sets - * * The following is a simple but complete example for how to use the BVH to accelerate the search for a closest red-blue point pair: * \include BVH_Example.cpp * Output: \verbinclude BVH_Example.out diff --git a/unsupported/doc/Doxyfile.in b/unsupported/doc/Doxyfile.in index c33986224..561f18fe7 100644 --- a/unsupported/doc/Doxyfile.in +++ b/unsupported/doc/Doxyfile.in @@ -211,7 +211,6 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "svd_module=This is defined in the %SVD module. \code #include \endcode" \ "geometry_module=This is defined in the %Geometry module. \code #include \endcode" \ "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" \ - "addexample=\anchor" \ "label=\bug" \ "redstar=*" \ "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" From a54b99fa72e34a4ed6da643f32517a43a4ae76b6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 11:39:44 +0200 Subject: [PATCH 37/66] move eigen values related stuff of the QR module to a new EigenSolver module. - perhaps we can find a better name ? - note that the QR module still includes the EigenSolver module for compatibility --- Eigen/CMakeLists.txt | 2 +- Eigen/EigenSolver | 74 +++++++++++++++++++ Eigen/LeastSquares | 2 +- Eigen/QR | 19 +---- Eigen/src/CMakeLists.txt | 1 + Eigen/src/EigenSolver/CMakeLists.txt | 6 ++ .../{QR => EigenSolver}/ComplexEigenSolver.h | 1 + Eigen/src/{QR => EigenSolver}/ComplexSchur.h | 1 + Eigen/src/{QR => EigenSolver}/EigenSolver.h | 18 ++--- .../HessenbergDecomposition.h | 4 +- .../SelfAdjointEigenSolver.h | 8 +- .../{QR => EigenSolver}/Tridiagonalization.h | 2 +- Eigen/src/QR/QrInstantiations.cpp | 5 -- doc/Doxyfile.in | 1 + test/eigensolver_complex.cpp | 2 +- test/eigensolver_generic.cpp | 2 +- test/eigensolver_selfadjoint.cpp | 2 +- test/product_notemporary.cpp | 2 - 18 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 Eigen/EigenSolver create mode 100644 Eigen/src/EigenSolver/CMakeLists.txt rename Eigen/src/{QR => EigenSolver}/ComplexEigenSolver.h (95%) rename Eigen/src/{QR => EigenSolver}/ComplexSchur.h (99%) rename Eigen/src/{QR => EigenSolver}/EigenSolver.h (98%) rename Eigen/src/{QR => EigenSolver}/HessenbergDecomposition.h (99%) rename Eigen/src/{QR => EigenSolver}/SelfAdjointEigenSolver.h (99%) rename Eigen/src/{QR => EigenSolver}/Tridiagonalization.h (99%) diff --git a/Eigen/CMakeLists.txt b/Eigen/CMakeLists.txt index b692cdc51..ebdf57812 100644 --- a/Eigen/CMakeLists.txt +++ b/Eigen/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD LeastSquares QtAlignedMalloc StdVector Householder Jacobi) +set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD LeastSquares QtAlignedMalloc StdVector Householder Jacobi EigenSolver) if(EIGEN_BUILD_LIB) set(Eigen_SRCS diff --git a/Eigen/EigenSolver b/Eigen/EigenSolver new file mode 100644 index 000000000..fd126d282 --- /dev/null +++ b/Eigen/EigenSolver @@ -0,0 +1,74 @@ +#ifndef EIGEN_EIGEN_SOLVER_MODULE_H +#define EIGEN_EIGEN_SOLVER_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableMSVCWarnings.h" + +#include "Cholesky" +#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 EigenSolver_Module Eigen Solver module + * + * \nonstableyet + * + * This module mainly provides various eigen value solvers. + * This module also provides some MatrixBase methods, including: + * - MatrixBase::eigenvalues(), + * - MatrixBase::operatorNorm() + * + * \code + * #include + * \endcode + */ + +#include "src/EigenSolver/Tridiagonalization.h" +#include "src/EigenSolver/EigenSolver.h" +#include "src/EigenSolver/SelfAdjointEigenSolver.h" +#include "src/EigenSolver/HessenbergDecomposition.h" +#include "src/EigenSolver/ComplexSchur.h" +#include "src/EigenSolver/ComplexEigenSolver.h" + +// declare all classes for a given matrix type +#define EIGEN_EIGEN_SOLVER_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_EIGEN_SOLVER_MODULE_INSTANTIATE(PREFIX) \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) + +#ifdef EIGEN_EXTERN_INSTANTIATIONS + EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE(extern); +#endif // EIGEN_EXTERN_INSTANTIATIONS + +} // namespace Eigen + +#include "src/Core/util/EnableMSVCWarnings.h" + +#endif // EIGEN_EIGEN_SOLVER_MODULE_H diff --git a/Eigen/LeastSquares b/Eigen/LeastSquares index 573a13cb4..db620f548 100644 --- a/Eigen/LeastSquares +++ b/Eigen/LeastSquares @@ -5,7 +5,7 @@ #include "src/Core/util/DisableMSVCWarnings.h" -#include "QR" +#include "EigenSolver" #include "Geometry" namespace Eigen { diff --git a/Eigen/QR b/Eigen/QR index 4b49004c3..a7273bc8a 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -24,11 +24,9 @@ namespace Eigen { * * \nonstableyet * - * This module mainly provides QR decomposition and an eigen value solver. + * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: * - MatrixBase::qr(), - * - MatrixBase::eigenvalues(), - * - MatrixBase::operatorNorm() * * \code * #include @@ -38,22 +36,10 @@ namespace Eigen { #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivotingHouseholderQR.h" #include "src/QR/ColPivotingHouseholderQR.h" -#include "src/QR/Tridiagonalization.h" -#include "src/QR/EigenSolver.h" -#include "src/QR/SelfAdjointEigenSolver.h" -#include "src/QR/HessenbergDecomposition.h" -#include "src/QR/ComplexSchur.h" -#include "src/QR/ComplexEigenSolver.h" // declare all classes for a given matrix type #define EIGEN_QR_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ PREFIX template class HouseholderQR; \ - 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_QR_MODULE_INSTANTIATE(PREFIX) \ @@ -76,4 +62,7 @@ namespace Eigen { #include "src/Core/util/EnableMSVCWarnings.h" +// FIXME for compatibility we include EigenSolver here: +#include "EigenSolver" + #endif // EIGEN_QR_MODULE_H diff --git a/Eigen/src/CMakeLists.txt b/Eigen/src/CMakeLists.txt index 2f6a83a1b..6b1333860 100644 --- a/Eigen/src/CMakeLists.txt +++ b/Eigen/src/CMakeLists.txt @@ -9,3 +9,4 @@ ADD_SUBDIRECTORY(LeastSquares) ADD_SUBDIRECTORY(Sparse) ADD_SUBDIRECTORY(Jacobi) ADD_SUBDIRECTORY(Householder) +ADD_SUBDIRECTORY(EigenSolver) diff --git a/Eigen/src/EigenSolver/CMakeLists.txt b/Eigen/src/EigenSolver/CMakeLists.txt new file mode 100644 index 000000000..63bc75e0c --- /dev/null +++ b/Eigen/src/EigenSolver/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_EIGENSOLVER_SRCS "*.h") + +INSTALL(FILES + ${Eigen_EIGENSOLVER_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/EigenSolver COMPONENT Devel + ) diff --git a/Eigen/src/QR/ComplexEigenSolver.h b/Eigen/src/EigenSolver/ComplexEigenSolver.h similarity index 95% rename from Eigen/src/QR/ComplexEigenSolver.h rename to Eigen/src/EigenSolver/ComplexEigenSolver.h index 6caa6bc2d..2ea7464a6 100644 --- a/Eigen/src/QR/ComplexEigenSolver.h +++ b/Eigen/src/EigenSolver/ComplexEigenSolver.h @@ -79,6 +79,7 @@ template class ComplexEigenSolver template void ComplexEigenSolver::compute(const MatrixType& matrix) { + // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); m_eivalues.resize(n,1); diff --git a/Eigen/src/QR/ComplexSchur.h b/Eigen/src/EigenSolver/ComplexSchur.h similarity index 99% rename from Eigen/src/QR/ComplexSchur.h rename to Eigen/src/EigenSolver/ComplexSchur.h index b60be5430..915f351fc 100644 --- a/Eigen/src/QR/ComplexSchur.h +++ b/Eigen/src/EigenSolver/ComplexSchur.h @@ -120,6 +120,7 @@ std::complex ei_sqrt(const std::complex &z) template void ComplexSchur::compute(const MatrixType& matrix) { + // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); diff --git a/Eigen/src/QR/EigenSolver.h b/Eigen/src/EigenSolver/EigenSolver.h similarity index 98% rename from Eigen/src/QR/EigenSolver.h rename to Eigen/src/EigenSolver/EigenSolver.h index 79d73db7e..1046780c6 100644 --- a/Eigen/src/QR/EigenSolver.h +++ b/Eigen/src/EigenSolver/EigenSolver.h @@ -25,7 +25,7 @@ #ifndef EIGEN_EIGENSOLVER_H #define EIGEN_EIGENSOLVER_H -/** \ingroup QR_Module +/** \ingroup EigenSolver_Module * \nonstableyet * * \class EigenSolver @@ -53,7 +53,7 @@ template class EigenSolver typedef Matrix RealVectorType; typedef Matrix RealVectorTypeX; - /** + /** * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to @@ -103,19 +103,19 @@ template class EigenSolver * * \sa pseudoEigenvalueMatrix() */ - const MatrixType& pseudoEigenvectors() const - { + const MatrixType& pseudoEigenvectors() const + { ei_assert(m_isInitialized && "EigenSolver is not initialized."); - return m_eivec; + return m_eivec; } MatrixType pseudoEigenvalueMatrix() const; /** \returns the eigenvalues as a column vector */ - EigenvalueType eigenvalues() const - { + EigenvalueType eigenvalues() const + { ei_assert(m_isInitialized && "EigenSolver is not initialized."); - return m_eivalues; + return m_eivalues; } EigenSolver& compute(const MatrixType& matrix); @@ -265,7 +265,7 @@ void EigenSolver::orthes(MatrixType& matH, RealVectorType& ort) ort.segment(m+1, high-m) = matH.col(m-1).segment(m+1, high-m); int bSize = high-m+1; - m_eivec.block(m, m, bSize, bSize).noalias() += ( (ort.segment(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m))) + m_eivec.block(m, m, bSize, bSize).noalias() += ( (ort.segment(m, bSize) / (matH.coeff(m,m-1) * ort.coeff(m))) * (ort.segment(m, bSize).transpose() * m_eivec.block(m, m, bSize, bSize)) ); } } diff --git a/Eigen/src/QR/HessenbergDecomposition.h b/Eigen/src/EigenSolver/HessenbergDecomposition.h similarity index 99% rename from Eigen/src/QR/HessenbergDecomposition.h rename to Eigen/src/EigenSolver/HessenbergDecomposition.h index 6b261a8a7..f782cef30 100644 --- a/Eigen/src/QR/HessenbergDecomposition.h +++ b/Eigen/src/EigenSolver/HessenbergDecomposition.h @@ -25,7 +25,7 @@ #ifndef EIGEN_HESSENBERGDECOMPOSITION_H #define EIGEN_HESSENBERGDECOMPOSITION_H -/** \ingroup QR_Module +/** \ingroup EigenSolver_Module * \nonstableyet * * \class HessenbergDecomposition @@ -156,7 +156,7 @@ void HessenbergDecomposition::_compute(MatrixType& matA, CoeffVector // Apply similarity transformation to remaining columns, // i.e., compute A = H A H' - + // A = H A matA.corner(BottomRight, remainingSize, remainingSize) .applyHouseholderOnTheLeft(matA.col(i).end(remainingSize-1), h, &temp.coeffRef(0)); diff --git a/Eigen/src/QR/SelfAdjointEigenSolver.h b/Eigen/src/EigenSolver/SelfAdjointEigenSolver.h similarity index 99% rename from Eigen/src/QR/SelfAdjointEigenSolver.h rename to Eigen/src/EigenSolver/SelfAdjointEigenSolver.h index 580b042f6..40b06df2c 100644 --- a/Eigen/src/QR/SelfAdjointEigenSolver.h +++ b/Eigen/src/EigenSolver/SelfAdjointEigenSolver.h @@ -25,7 +25,7 @@ #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H #define EIGEN_SELFADJOINTEIGENSOLVER_H -/** \qr_module \ingroup QR_Module +/** \eigensolver_module \ingroup EigenSolver_Module * \nonstableyet * * \class SelfAdjointEigenSolver @@ -137,7 +137,7 @@ template class SelfAdjointEigenSolver /** \internal * - * \qr_module + * \eigensolver_module * * Performs a QR step on a tridiagonal symmetric matrix represented as a * pair of two vectors \a diag and \a subdiag. @@ -266,7 +266,7 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors #endif // EIGEN_HIDE_HEAVY_CODE -/** \qr_module +/** \eigensolver_module * * \returns a vector listing the eigenvalues of this matrix. */ @@ -307,7 +307,7 @@ template struct ei_operatorNorm_selector } }; -/** \qr_module +/** \eigensolver_module * * \returns the matrix norm of this matrix. */ diff --git a/Eigen/src/QR/Tridiagonalization.h b/Eigen/src/EigenSolver/Tridiagonalization.h similarity index 99% rename from Eigen/src/QR/Tridiagonalization.h rename to Eigen/src/EigenSolver/Tridiagonalization.h index 2053505f6..e0bff17b9 100644 --- a/Eigen/src/QR/Tridiagonalization.h +++ b/Eigen/src/EigenSolver/Tridiagonalization.h @@ -25,7 +25,7 @@ #ifndef EIGEN_TRIDIAGONALIZATION_H #define EIGEN_TRIDIAGONALIZATION_H -/** \ingroup QR_Module +/** \ingroup EigenSolver_Module * \nonstableyet * * \class Tridiagonalization diff --git a/Eigen/src/QR/QrInstantiations.cpp b/Eigen/src/QR/QrInstantiations.cpp index 38b0a57da..695377d69 100644 --- a/Eigen/src/QR/QrInstantiations.cpp +++ b/Eigen/src/QR/QrInstantiations.cpp @@ -33,11 +33,6 @@ namespace Eigen { -template static void ei_tridiagonal_qr_step(float* , float* , int, int, float* , int); -template static void ei_tridiagonal_qr_step(double* , double* , int, int, double* , int); -template static void ei_tridiagonal_qr_step(float* , float* , int, int, std::complex* , int); -template static void ei_tridiagonal_qr_step(double* , double* , int, int, std::complex* , int); - EIGEN_QR_MODULE_INSTANTIATE(); } diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index dba66c0d9..bd0df9eb2 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -212,6 +212,7 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "svd_module=This is defined in the %SVD module. \code #include \endcode" \ "geometry_module=This is defined in the %Geometry module. \code #include \endcode" \ "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" \ + "eigensolver_module=This is defined in the %EigenSolver module. \code #include \endcode" \ "label=\bug" \ "redstar=*" \ "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index dad5a69f8..db129c064 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #include template void eigensolver(const MatrixType& m) diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index 2be49faf4..68ee447e9 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #ifdef HAS_GSL #include "gsl_helper.h" diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 2571dbf43..61d8f1cb5 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #ifdef HAS_GSL #include "gsl_helper.h" diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 3b0329f43..1a3d65291 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -71,8 +71,6 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1); VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0); - // NOTE in this case the slow product is used: - // FIXME: VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0); From 00f4b4690872ea333d426611b3942f4aaacc0139 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 11:50:06 +0200 Subject: [PATCH 38/66] typo in sqrt(complex) --- Eigen/src/EigenSolver/ComplexSchur.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/EigenSolver/ComplexSchur.h b/Eigen/src/EigenSolver/ComplexSchur.h index 915f351fc..1a07fe163 100644 --- a/Eigen/src/EigenSolver/ComplexSchur.h +++ b/Eigen/src/EigenSolver/ComplexSchur.h @@ -88,7 +88,7 @@ std::complex ei_sqrt(const std::complex &z) t = ei_abs(z); - if (ei_abs(ei_real(z)) <= ei_abs(ei_real(z))) + if (ei_abs(ei_real(z)) <= ei_abs(ei_imag(z))) { // No cancellation in these formulas tre = ei_sqrt(0.5*(t + ei_real(z))); From 3eb37fe1fb36be375c6211fc00d56a89b08b12fb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 13:03:26 +0200 Subject: [PATCH 39/66] update mixingtype unit test to reflect current status, but it is still clear we should allow matrix products between complex and real ? --- Eigen/src/Core/Product.h | 18 +++- Eigen/src/Core/products/GeneralMatrixMatrix.h | 6 +- test/mixingtypes.cpp | 87 ++++++++++++++++--- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 5c6cee426..dfdbca839 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -162,7 +162,11 @@ class GeneralProduct public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } EIGEN_STRONG_INLINE Scalar value() const { @@ -197,7 +201,11 @@ class GeneralProduct public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } template void scaleAndAddTo(Dest& dest, Scalar alpha) const { @@ -251,7 +259,11 @@ class GeneralProduct public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; typedef typename ei_meta_if::ret MatrixType; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index c4692b872..beec17ee4 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -135,7 +135,11 @@ class GeneralProduct public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} + GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } template void scaleAndAddTo(Dest& dst, Scalar alpha) const { diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index d14232bd4..52e68aba2 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -61,7 +61,75 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_RAISES_ASSERT(vf+=vd); VERIFY_RAISES_ASSERT(mcd=md); + vf.dot(vf); + VERIFY_RAISES_ASSERT(vd.dot(vf)); + VERIFY_RAISES_ASSERT(vcf.dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h +} // especially as that might be rewritten as cwise product .sum() which would make that automatic. + + +void mixingtypes_large(int size) +{ + static const int SizeAtCompileType = Dynamic; + typedef Matrix Mat_f; + typedef Matrix Mat_d; + typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cf; + typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cd; + typedef Matrix Vec_f; + typedef Matrix Vec_d; + typedef Matrix, SizeAtCompileType, 1> Vec_cf; + typedef Matrix, SizeAtCompileType, 1> Vec_cd; + + Mat_f mf(size,size); + Mat_d md(size,size); + Mat_cf mcf(size,size); + Mat_cd mcd(size,size); + Vec_f vf(size,1); + Vec_d vd(size,1); + Vec_cf vcf(size,1); + Vec_cd vcd(size,1); + mf*mf; + // FIXME large products does not allow mixing types + VERIFY_RAISES_ASSERT(md*mcd); + VERIFY_RAISES_ASSERT(mcd*md); + VERIFY_RAISES_ASSERT(mf*vcf); + VERIFY_RAISES_ASSERT(mcf*vf); + VERIFY_RAISES_ASSERT(mcf *= mf); + // VERIFY_RAISES_ASSERT(vcd = md*vcd); // does not even compile + VERIFY_RAISES_ASSERT(vcf = mcf*vf); + + VERIFY_RAISES_ASSERT(mf*md); + VERIFY_RAISES_ASSERT(mcf*mcd); + VERIFY_RAISES_ASSERT(mcf*vcd); + VERIFY_RAISES_ASSERT(vcf = mf*vf); +} + +template void mixingtypes_small() +{ + int size = SizeAtCompileType; + typedef Matrix Mat_f; + typedef Matrix Mat_d; + typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cf; + typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cd; + typedef Matrix Vec_f; + typedef Matrix Vec_d; + typedef Matrix, SizeAtCompileType, 1> Vec_cf; + typedef Matrix, SizeAtCompileType, 1> Vec_cd; + + Mat_f mf(size,size); + Mat_d md(size,size); + Mat_cf mcf(size,size); + Mat_cd mcd(size,size); + Vec_f vf(size,1); + Vec_d vd(size,1); + Vec_cf vcf(size,1); + Vec_cd vcd(size,1); + + + mf*mf; + // FIXME shall we discard those products ? + // 1) currently they work only if SizeAtCompileType is small enough + // 2) in case we vectorize complexes this might be difficult to still allow that md*mcd; mcd*md; mf*vcf; @@ -69,20 +137,19 @@ template void mixingtypes(int size = SizeAtCompileType) mcf *= mf; vcd = md*vcd; vcf = mcf*vf; - VERIFY_RAISES_ASSERT(mf*md); - VERIFY_RAISES_ASSERT(mcf*mcd); - VERIFY_RAISES_ASSERT(mcf*vcd); +// VERIFY_RAISES_ASSERT(mf*md); // does not even compile +// VERIFY_RAISES_ASSERT(mcf*mcd); // does not even compile +// VERIFY_RAISES_ASSERT(mcf*vcd); // does not even compile VERIFY_RAISES_ASSERT(vcf = mf*vf); - - vf.dot(vf); - VERIFY_RAISES_ASSERT(vd.dot(vf)); - VERIFY_RAISES_ASSERT(vcf.dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h -} // especially as that might be rewritten as cwise product .sum() which would make that automatic. +} void test_mixingtypes() { // check that our operator new is indeed called: - CALL_SUBTEST(mixingtypes<3>(3)); - CALL_SUBTEST(mixingtypes<4>(4)); + CALL_SUBTEST(mixingtypes<3>()); + CALL_SUBTEST(mixingtypes<4>()); CALL_SUBTEST(mixingtypes(20)); + + CALL_SUBTEST(mixingtypes_small<4>()); + CALL_SUBTEST(mixingtypes_large(20)); } From 41aea9508e55b83f3834d189ef87118b9066b106 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 3 Sep 2009 13:46:44 +0200 Subject: [PATCH 40/66] This seems to be important for MSVC to optimize the size of empty base classes. --- Eigen/src/Core/MatrixBase.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 9ac964168..fececdd5f 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -35,7 +35,9 @@ * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. */ -template struct AnyMatrixBase +template struct AnyMatrixBase + : public ei_special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real> { typedef typename ei_plain_matrix_type::type PlainMatrixType; @@ -91,9 +93,7 @@ template struct AnyMatrixBase */ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public AnyMatrixBase, - public ei_special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real> + : public AnyMatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: From 82ad37c730264a8acd119f328a7007b93257246c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 17:08:38 +0200 Subject: [PATCH 41/66] implement the continuous generation algorithm of Givens rotations by Anderson (2000) --- Eigen/src/Jacobi/Jacobi.h | 107 +++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 3e3cce665..7fd57ed5f 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -87,7 +87,7 @@ template class PlanarRotation }; /** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the selfadjoint 2x2 matrix - * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$ + * \f$ B = \left ( \begin{array}{cc} x & y \\ \overline y & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$ * * \sa MatrixBase::makeJacobi(const MatrixBase&, int, int), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ @@ -123,7 +123,7 @@ bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) } /** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 selfadjoint matrix - * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ * & \text{this}_{qq} \end{array} \right )\f$ yields + * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ \overline \text{this}_{pq} & \text{this}_{qq} \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * * Example: \include Jacobi_makeJacobi.cpp @@ -140,7 +140,7 @@ inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int /** Makes \c *this as a Givens rotation \c G such that applying \f$ G^* \f$ to the left of the vector * \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields: - * \f$ G^* V = \left ( \begin{array}{c} z \\ 0 \end{array} \right )\f$. + * \f$ G^* V = \left ( \begin{array}{c} r \\ 0 \end{array} \right )\f$. * * The value of \a z is returned if \a z is not null (the default is null). * Also note that G is built such that the cosine is always real. @@ -148,6 +148,10 @@ inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int * Example: \include Jacobi_makeGivens.cpp * Output: \verbinclude Jacobi_makeGivens.out * + * This function implements the continuous Givens rotation generation algorithm + * found in Anderson (2000), Discontinuous Plane Rotations and the Symmetric Eigenvalue Problem. + * LAPACK Working Note 150, University of Tennessee, UT-CS-00-454, December 4, 2000. + * * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template @@ -159,52 +163,97 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar // specialization for complexes template -void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_true) +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, ei_meta_true) { - RealScalar scale, absx, absxy; if(q==Scalar(0)) { - // return identity - m_c = Scalar(1); - m_s = Scalar(0); - if(z) *z = p; + m_c = ei_real(p)<0 ? Scalar(-1) : Scalar(1); + m_s = 0; + if(r) *r = m_c * p; + } + else if(p==Scalar(0)) + { + m_c = 0; + m_s = -q/ei_abs(q); + if(r) *r = ei_abs(q); } else { - scale = ei_norm1(p); - absx = scale * ei_sqrt(ei_abs2(p/scale)); - scale = ei_abs(scale) + ei_norm1(q); - absxy = scale * ei_sqrt((absx/scale)*(absx/scale) + ei_abs2(q/scale)); - m_c = Scalar(absx / absxy); - Scalar np = p/absx; - m_s = -ei_conj(np) * q / absxy; - if(z) *z = np * absxy; + RealScalar p1 = ei_norm1(p); + RealScalar q1 = ei_norm1(q); + if(p1>=q1) + { + Scalar ps = p / p1; + RealScalar p2 = ei_abs2(ps); + Scalar qs = q / p1; + RealScalar q2 = ei_abs2(qs); + + RealScalar u = ei_sqrt(RealScalar(1) + q2/p2); + if(ei_real(p) -void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false) +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, ei_meta_false) { - ei_assert(z==0 && "not implemented yet"); - // from Golub's "Matrix Computations", algorithm 5.1.3 + if(q==0) { - m_c = 1; m_s = 0; + m_c = pei_abs(p)) + else if(p==0) { - Scalar t = -p/q; - m_s = Scalar(1)/ei_sqrt(1+t*t); - m_c = m_s * t; + m_c = 0; + m_s = qq) + { + Scalar t = q/p; + Scalar u = ei_sqrt(Scalar(1) + ei_abs2(t)); + if(p Date: Thu, 3 Sep 2009 17:27:51 +0200 Subject: [PATCH 42/66] Added conservativeResize + unit test. --- Eigen/src/Core/Matrix.h | 61 ++++++++++++++ Eigen/src/Core/util/StaticAssert.h | 6 ++ test/CMakeLists.txt | 1 + test/conservative_resize.cpp | 129 +++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 test/conservative_resize.cpp diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 2fc38c812..70862ad11 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -321,6 +321,67 @@ class Matrix else resize(other.rows(), other.cols()); } + /** Resizes \c *this to a \a rows x \a cols matrix while leaving old values of *this untouched. + * + * This method is intended for dynamic-size matrices, although it is legal to call it on any + * matrix as long as fixed dimensions are left unchanged. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, int), + * conservativeResize(int, NoChange_t). + * + * The top-left part of the resized matrix will be the same as the overlapping top-left corner + * of *this. In case values need to be appended to the matrix they will be uninitialized per + * default and set to zero when init_with_zero is set to true. + */ + inline void conservativeResize(int rows, int cols, bool init_with_zero = false) + { + // Note: Here is space for improvement. Basically, for conservativeResize(int,int), + // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the + // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or + // conservativeResize(NoChange_t, int cols). For these methods new static asserts like + // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) + PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(rows, cols) : PlainMatrixType(rows,cols); + const int common_rows = std::min(rows, this->rows()); + const int common_cols = std::min(cols, this->cols()); + tmp.block(0,0,common_rows,common_cols) = this->block(0,0,common_rows,common_cols); + this->derived().swap(tmp); + } + + EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t, bool init_with_zero = false) + { + // Note: see the comment in conservativeResize(int,int,bool) + conservativeResize(rows, cols(), init_with_zero); + } + + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, int cols, bool init_with_zero = false) + { + // Note: see the comment in conservativeResize(int,int,bool) + conservativeResize(rows(), cols, init_with_zero); + } + + /** Resizes \c *this to a vector of length \a size while retaining old values of *this. + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * When values are appended, they will be uninitialized per default and set + * to zero when init_with_zero is set to true. + */ + inline void conservativeResize(int size, bool init_with_zero = false) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) + + if (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) + { + PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(size) : PlainMatrixType(size); + const int common_size = std::min(this->size(),size); + tmp.segment(0,common_size) = this->segment(0,common_size); + this->derived().swap(tmp); + } + } + /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index e1ccd58e7..73d302fda 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -62,6 +62,7 @@ THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE, YOU_MADE_A_PROGRAMMING_MISTAKE, YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR, + YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR, UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC, NUMERIC_TYPE_MUST_BE_FLOATING_POINT, NUMERIC_TYPE_MUST_BE_REAL, @@ -114,6 +115,11 @@ EIGEN_STATIC_ASSERT(TYPE::SizeAtCompileTime!=Eigen::Dynamic, \ YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR) +// static assertion failing if the type \a TYPE is not dynamic-size +#define EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(TYPE) \ + EIGEN_STATIC_ASSERT(TYPE::SizeAtCompileTime==Eigen::Dynamic, \ + YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR) + // static assertion failing if the type \a TYPE is not a vector type of the given size #define EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(TYPE, SIZE) \ EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6bbf82144..03fbd48fc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -149,6 +149,7 @@ ei_add_test(sparse_solvers " " "${SPARSE_LIBS}") ei_add_test(umeyama) ei_add_test(householder) ei_add_test(swap) +ei_add_test(conservative_resize) ei_add_property(EIGEN_TESTING_SUMMARY "CXX: ${CMAKE_CXX_COMPILER}\n") if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp new file mode 100644 index 000000000..f0d025283 --- /dev/null +++ b/test/conservative_resize.cpp @@ -0,0 +1,129 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2009 Hauke Heibel +// +// 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 or1 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 . + +#include "main.h" + +#include +#include + +using namespace Eigen; + +template +void run_matrix_tests() +{ + typedef Matrix MatrixType; + + MatrixType m, n; + + // boundary cases ... + m = n = MatrixType::Random(50,50); + m.conservativeResize(1,50); + VERIFY_IS_APPROX(m, n.block(0,0,1,50)); + + m = n = MatrixType::Random(50,50); + m.conservativeResize(50,1); + VERIFY_IS_APPROX(m, n.block(0,0,50,1)); + + m = n = MatrixType::Random(50,50); + m.conservativeResize(50,50); + VERIFY_IS_APPROX(m, n.block(0,0,50,50)); + + // random shrinking ... + for (int i=0; i<25; ++i) + { + const int rows = ei_random(1,50); + const int cols = ei_random(1,50); + m = n = MatrixType::Random(50,50); + m.conservativeResize(rows,cols); + VERIFY_IS_APPROX(m, n.block(0,0,rows,cols)); + } + + // random growing with zeroing ... + for (int i=0; i<25; ++i) + { + const int rows = ei_random(50,75); + const int cols = ei_random(50,75); + m = n = MatrixType::Random(50,50); + m.conservativeResize(rows,cols,true); + VERIFY_IS_APPROX(m.block(0,0,n.rows(),n.cols()), n); + VERIFY( rows<=50 || m.block(50,0,rows-50,cols).sum() == Scalar(0) ); + VERIFY( cols<=50 || m.block(0,50,rows,cols-50).sum() == Scalar(0) ); + } +} + +template +void run_vector_tests() +{ + typedef Matrix MatrixType; + + MatrixType m, n; + + // boundary cases ... + m = n = MatrixType::Random(50); + m.conservativeResize(1); + VERIFY_IS_APPROX(m, n.segment(0,1)); + + m = n = MatrixType::Random(50); + m.conservativeResize(50); + VERIFY_IS_APPROX(m, n.segment(0,50)); + + // random shrinking ... + for (int i=0; i<50; ++i) + { + const int size = ei_random(1,50); + m = n = MatrixType::Random(50); + m.conservativeResize(size); + VERIFY_IS_APPROX(m, n.segment(0,size)); + } + + // random growing with zeroing ... + for (int i=0; i<50; ++i) + { + const int size = ei_random(50,100); + m = n = MatrixType::Random(50); + m.conservativeResize(size,true); + VERIFY_IS_APPROX(m.segment(0,50), n); + VERIFY( size<=50 || m.segment(50,size-50).sum() == Scalar(0) ); + } +} + +void test_conservative_resize() +{ + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests, Eigen::RowMajor>(); + run_matrix_tests, Eigen::ColMajor>(); + run_matrix_tests, Eigen::RowMajor>(); + run_matrix_tests, Eigen::ColMajor>(); + + run_vector_tests(); + run_vector_tests(); + run_vector_tests(); + run_vector_tests >(); + run_vector_tests >(); +} From 68b28f7bfb29474ad21036476618a3730fa7fffa Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Sep 2009 09:23:38 +0200 Subject: [PATCH 43/66] rename the EigenSolver module to Eigenvalues --- Eigen/CMakeLists.txt | 2 +- Eigen/EigenSolver | 74 ------------------- Eigen/Eigenvalues | 74 +++++++++++++++++++ Eigen/LeastSquares | 2 +- Eigen/QR | 4 +- Eigen/src/CMakeLists.txt | 2 +- Eigen/src/EigenSolver/CMakeLists.txt | 6 -- Eigen/src/Eigenvalues/CMakeLists.txt | 6 ++ .../ComplexEigenSolver.h | 13 +++- .../ComplexSchur.h | 7 +- .../EigenSolver.h | 2 +- .../HessenbergDecomposition.h | 2 +- .../SelfAdjointEigenSolver.h | 8 +- .../Tridiagonalization.h | 2 +- doc/Doxyfile.in | 2 +- test/eigensolver_complex.cpp | 2 +- test/eigensolver_generic.cpp | 2 +- test/eigensolver_selfadjoint.cpp | 2 +- test/mixingtypes.cpp | 2 +- 19 files changed, 111 insertions(+), 103 deletions(-) delete mode 100644 Eigen/EigenSolver create mode 100644 Eigen/Eigenvalues delete mode 100644 Eigen/src/EigenSolver/CMakeLists.txt create mode 100644 Eigen/src/Eigenvalues/CMakeLists.txt rename Eigen/src/{EigenSolver => Eigenvalues}/ComplexEigenSolver.h (89%) rename Eigen/src/{EigenSolver => Eigenvalues}/ComplexSchur.h (98%) rename Eigen/src/{EigenSolver => Eigenvalues}/EigenSolver.h (99%) rename Eigen/src/{EigenSolver => Eigenvalues}/HessenbergDecomposition.h (99%) rename Eigen/src/{EigenSolver => Eigenvalues}/SelfAdjointEigenSolver.h (98%) rename Eigen/src/{EigenSolver => Eigenvalues}/Tridiagonalization.h (99%) diff --git a/Eigen/CMakeLists.txt b/Eigen/CMakeLists.txt index ebdf57812..931cc6e20 100644 --- a/Eigen/CMakeLists.txt +++ b/Eigen/CMakeLists.txt @@ -1,4 +1,4 @@ -set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD LeastSquares QtAlignedMalloc StdVector Householder Jacobi EigenSolver) +set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD LeastSquares QtAlignedMalloc StdVector Householder Jacobi Eigenvalues) if(EIGEN_BUILD_LIB) set(Eigen_SRCS diff --git a/Eigen/EigenSolver b/Eigen/EigenSolver deleted file mode 100644 index fd126d282..000000000 --- a/Eigen/EigenSolver +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef EIGEN_EIGEN_SOLVER_MODULE_H -#define EIGEN_EIGEN_SOLVER_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableMSVCWarnings.h" - -#include "Cholesky" -#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 EigenSolver_Module Eigen Solver module - * - * \nonstableyet - * - * This module mainly provides various eigen value solvers. - * This module also provides some MatrixBase methods, including: - * - MatrixBase::eigenvalues(), - * - MatrixBase::operatorNorm() - * - * \code - * #include - * \endcode - */ - -#include "src/EigenSolver/Tridiagonalization.h" -#include "src/EigenSolver/EigenSolver.h" -#include "src/EigenSolver/SelfAdjointEigenSolver.h" -#include "src/EigenSolver/HessenbergDecomposition.h" -#include "src/EigenSolver/ComplexSchur.h" -#include "src/EigenSolver/ComplexEigenSolver.h" - -// declare all classes for a given matrix type -#define EIGEN_EIGEN_SOLVER_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_EIGEN_SOLVER_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - EIGEN_EIGEN_SOLVER_MODULE_INSTANTIATE(extern); -#endif // EIGEN_EXTERN_INSTANTIATIONS - -} // namespace Eigen - -#include "src/Core/util/EnableMSVCWarnings.h" - -#endif // EIGEN_EIGEN_SOLVER_MODULE_H diff --git a/Eigen/Eigenvalues b/Eigen/Eigenvalues new file mode 100644 index 000000000..9a6443f39 --- /dev/null +++ b/Eigen/Eigenvalues @@ -0,0 +1,74 @@ +#ifndef EIGEN_EIGENVALUES_MODULE_H +#define EIGEN_EIGENVALUES_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableMSVCWarnings.h" + +#include "Cholesky" +#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 Eigenvalues_Module Eigenvalues module + * + * \nonstableyet + * + * This module mainly provides various eigenvalue solvers. + * This module also provides some MatrixBase methods, including: + * - MatrixBase::eigenvalues(), + * - MatrixBase::operatorNorm() + * + * \code + * #include + * \endcode + */ + +#include "src/Eigenvalues/Tridiagonalization.h" +#include "src/Eigenvalues/EigenSolver.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver.h" +#include "src/Eigenvalues/HessenbergDecomposition.h" +#include "src/Eigenvalues/ComplexSchur.h" +#include "src/Eigenvalues/ComplexEigenSolver.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" + +#endif // EIGEN_EIGENVALUES_MODULE_H diff --git a/Eigen/LeastSquares b/Eigen/LeastSquares index db620f548..75620a349 100644 --- a/Eigen/LeastSquares +++ b/Eigen/LeastSquares @@ -5,7 +5,7 @@ #include "src/Core/util/DisableMSVCWarnings.h" -#include "EigenSolver" +#include "Eigenvalues" #include "Geometry" namespace Eigen { diff --git a/Eigen/QR b/Eigen/QR index a7273bc8a..f38e96c5e 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -62,7 +62,7 @@ namespace Eigen { #include "src/Core/util/EnableMSVCWarnings.h" -// FIXME for compatibility we include EigenSolver here: -#include "EigenSolver" +// FIXME for compatibility we include Eigenvalues here: +#include "Eigenvalues" #endif // EIGEN_QR_MODULE_H diff --git a/Eigen/src/CMakeLists.txt b/Eigen/src/CMakeLists.txt index 6b1333860..0df8273d1 100644 --- a/Eigen/src/CMakeLists.txt +++ b/Eigen/src/CMakeLists.txt @@ -9,4 +9,4 @@ ADD_SUBDIRECTORY(LeastSquares) ADD_SUBDIRECTORY(Sparse) ADD_SUBDIRECTORY(Jacobi) ADD_SUBDIRECTORY(Householder) -ADD_SUBDIRECTORY(EigenSolver) +ADD_SUBDIRECTORY(Eigenvalues) diff --git a/Eigen/src/EigenSolver/CMakeLists.txt b/Eigen/src/EigenSolver/CMakeLists.txt deleted file mode 100644 index 63bc75e0c..000000000 --- a/Eigen/src/EigenSolver/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_EIGENSOLVER_SRCS "*.h") - -INSTALL(FILES - ${Eigen_EIGENSOLVER_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/EigenSolver COMPONENT Devel - ) diff --git a/Eigen/src/Eigenvalues/CMakeLists.txt b/Eigen/src/Eigenvalues/CMakeLists.txt new file mode 100644 index 000000000..193e02685 --- /dev/null +++ b/Eigen/src/Eigenvalues/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_EIGENVALUES_SRCS "*.h") + +INSTALL(FILES + ${Eigen_EIGENVALUES_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Eigenvalues COMPONENT Devel + ) diff --git a/Eigen/src/EigenSolver/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h similarity index 89% rename from Eigen/src/EigenSolver/ComplexEigenSolver.h rename to Eigen/src/Eigenvalues/ComplexEigenSolver.h index 2ea7464a6..666381949 100644 --- a/Eigen/src/EigenSolver/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -26,8 +26,17 @@ #ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H #define EIGEN_COMPLEX_EIGEN_SOLVER_H -#define MAXITER 30 - +/** \eigenvalues_module \ingroup Eigenvalues_Module + * \nonstableyet + * + * \class ComplexEigenSolver + * + * \brief Eigen values/vectors solver for general complex matrices + * + * \param MatrixType the type of the matrix of which we are computing the eigen decomposition + * + * \sa class EigenSolver, class SelfAdjointEigenSolver + */ template class ComplexEigenSolver { public: diff --git a/Eigen/src/EigenSolver/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h similarity index 98% rename from Eigen/src/EigenSolver/ComplexSchur.h rename to Eigen/src/Eigenvalues/ComplexSchur.h index 1a07fe163..58e2ea440 100644 --- a/Eigen/src/EigenSolver/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -26,9 +26,8 @@ #ifndef EIGEN_COMPLEX_SCHUR_H #define EIGEN_COMPLEX_SCHUR_H -#define MAXITER 30 - -/** \ingroup QR +/** \eigenvalues_module \ingroup Eigenvalues_Module + * \nonstableyet * * \class ComplexShur * @@ -155,7 +154,7 @@ void ComplexSchur::compute(const MatrixType& matrix) if(iu==0) break; iter++; - if(iter >= MAXITER) + if(iter >= 30) { // FIXME : what to do when iter==MAXITER ?? std::cerr << "MAXITER" << std::endl; diff --git a/Eigen/src/EigenSolver/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h similarity index 99% rename from Eigen/src/EigenSolver/EigenSolver.h rename to Eigen/src/Eigenvalues/EigenSolver.h index 1046780c6..3fc36c080 100644 --- a/Eigen/src/EigenSolver/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -25,7 +25,7 @@ #ifndef EIGEN_EIGENSOLVER_H #define EIGEN_EIGENSOLVER_H -/** \ingroup EigenSolver_Module +/** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * * \class EigenSolver diff --git a/Eigen/src/EigenSolver/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h similarity index 99% rename from Eigen/src/EigenSolver/HessenbergDecomposition.h rename to Eigen/src/Eigenvalues/HessenbergDecomposition.h index f782cef30..b1e21d4ee 100644 --- a/Eigen/src/EigenSolver/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -25,7 +25,7 @@ #ifndef EIGEN_HESSENBERGDECOMPOSITION_H #define EIGEN_HESSENBERGDECOMPOSITION_H -/** \ingroup EigenSolver_Module +/** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * * \class HessenbergDecomposition diff --git a/Eigen/src/EigenSolver/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h similarity index 98% rename from Eigen/src/EigenSolver/SelfAdjointEigenSolver.h rename to Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 40b06df2c..84856aa66 100644 --- a/Eigen/src/EigenSolver/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -25,7 +25,7 @@ #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H #define EIGEN_SELFADJOINTEIGENSOLVER_H -/** \eigensolver_module \ingroup EigenSolver_Module +/** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * * \class SelfAdjointEigenSolver @@ -137,7 +137,7 @@ template class SelfAdjointEigenSolver /** \internal * - * \eigensolver_module + * \eigenvalues_module \ingroup Eigenvalues_Module * * Performs a QR step on a tridiagonal symmetric matrix represented as a * pair of two vectors \a diag and \a subdiag. @@ -266,7 +266,7 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors #endif // EIGEN_HIDE_HEAVY_CODE -/** \eigensolver_module +/** \eigenvalues_module * * \returns a vector listing the eigenvalues of this matrix. */ @@ -307,7 +307,7 @@ template struct ei_operatorNorm_selector } }; -/** \eigensolver_module +/** \eigenvalues_module * * \returns the matrix norm of this matrix. */ diff --git a/Eigen/src/EigenSolver/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h similarity index 99% rename from Eigen/src/EigenSolver/Tridiagonalization.h rename to Eigen/src/Eigenvalues/Tridiagonalization.h index e0bff17b9..5f891bfa6 100644 --- a/Eigen/src/EigenSolver/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -25,7 +25,7 @@ #ifndef EIGEN_TRIDIAGONALIZATION_H #define EIGEN_TRIDIAGONALIZATION_H -/** \ingroup EigenSolver_Module +/** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * * \class Tridiagonalization diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index bd0df9eb2..5b055ed11 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -212,7 +212,7 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "svd_module=This is defined in the %SVD module. \code #include \endcode" \ "geometry_module=This is defined in the %Geometry module. \code #include \endcode" \ "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" \ - "eigensolver_module=This is defined in the %EigenSolver module. \code #include \endcode" \ + "eigenvalues_module=This is defined in the %Eigenvalues module. \code #include \endcode" \ "label=\bug" \ "redstar=*" \ "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index db129c064..38ede7c4a 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #include template void eigensolver(const MatrixType& m) diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index 68ee447e9..e2b2055b4 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #ifdef HAS_GSL #include "gsl_helper.h" diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 61d8f1cb5..3836c074b 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -23,7 +23,7 @@ // Eigen. If not, see . #include "main.h" -#include +#include #ifdef HAS_GSL #include "gsl_helper.h" diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 52e68aba2..690442a02 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -95,7 +95,7 @@ void mixingtypes_large(int size) VERIFY_RAISES_ASSERT(mf*vcf); VERIFY_RAISES_ASSERT(mcf*vf); VERIFY_RAISES_ASSERT(mcf *= mf); - // VERIFY_RAISES_ASSERT(vcd = md*vcd); // does not even compile + // VERIFY_RAISES_ASSERT(vcd = md*vcd); // does not even compile (cannot convert complex to double) VERIFY_RAISES_ASSERT(vcf = mcf*vf); VERIFY_RAISES_ASSERT(mf*md); From 3fbf71d6b95c11729c673d11aa6d193faae4589e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Sep 2009 09:26:00 +0200 Subject: [PATCH 44/66] compilation fix for conservativeResize --- Eigen/src/Core/Matrix.h | 121 ++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 70862ad11..0975b3b77 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -126,6 +126,7 @@ class Matrix EIGEN_GENERIC_PUBLIC_INTERFACE(Matrix) enum { Options = _Options }; + typedef typename Base::PlainMatrixType PlainMatrixType; friend class Eigen::Map; typedef class Eigen::Map UnalignedMapType; friend class Eigen::Map; @@ -321,65 +322,65 @@ class Matrix else resize(other.rows(), other.cols()); } - /** Resizes \c *this to a \a rows x \a cols matrix while leaving old values of *this untouched. - * - * This method is intended for dynamic-size matrices, although it is legal to call it on any - * matrix as long as fixed dimensions are left unchanged. If you only want to change the number - * of rows and/or of columns, you can use conservativeResize(NoChange_t, int), - * conservativeResize(int, NoChange_t). - * - * The top-left part of the resized matrix will be the same as the overlapping top-left corner - * of *this. In case values need to be appended to the matrix they will be uninitialized per - * default and set to zero when init_with_zero is set to true. - */ - inline void conservativeResize(int rows, int cols, bool init_with_zero = false) - { - // Note: Here is space for improvement. Basically, for conservativeResize(int,int), - // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the - // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or - // conservativeResize(NoChange_t, int cols). For these methods new static asserts like - // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(rows, cols) : PlainMatrixType(rows,cols); - const int common_rows = std::min(rows, this->rows()); - const int common_cols = std::min(cols, this->cols()); - tmp.block(0,0,common_rows,common_cols) = this->block(0,0,common_rows,common_cols); - this->derived().swap(tmp); - } - - EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t, bool init_with_zero = false) - { - // Note: see the comment in conservativeResize(int,int,bool) - conservativeResize(rows, cols(), init_with_zero); - } - - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, int cols, bool init_with_zero = false) - { - // Note: see the comment in conservativeResize(int,int,bool) - conservativeResize(rows(), cols, init_with_zero); - } - - /** Resizes \c *this to a vector of length \a size while retaining old values of *this. - * - * \only_for_vectors. This method does not work for - * partially dynamic matrices when the static dimension is anything other - * than 1. For example it will not work with Matrix. - * - * When values are appended, they will be uninitialized per default and set - * to zero when init_with_zero is set to true. - */ - inline void conservativeResize(int size, bool init_with_zero = false) - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - - if (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) - { - PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(size) : PlainMatrixType(size); - const int common_size = std::min(this->size(),size); - tmp.segment(0,common_size) = this->segment(0,common_size); - this->derived().swap(tmp); - } + /** Resizes \c *this to a \a rows x \a cols matrix while leaving old values of *this untouched. + * + * This method is intended for dynamic-size matrices, although it is legal to call it on any + * matrix as long as fixed dimensions are left unchanged. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, int), + * conservativeResize(int, NoChange_t). + * + * The top-left part of the resized matrix will be the same as the overlapping top-left corner + * of *this. In case values need to be appended to the matrix they will be uninitialized per + * default and set to zero when init_with_zero is set to true. + */ + inline void conservativeResize(int rows, int cols, bool init_with_zero = false) + { + // Note: Here is space for improvement. Basically, for conservativeResize(int,int), + // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the + // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or + // conservativeResize(NoChange_t, int cols). For these methods new static asserts like + // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) + PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(rows, cols) : PlainMatrixType(rows,cols); + const int common_rows = std::min(rows, this->rows()); + const int common_cols = std::min(cols, this->cols()); + tmp.block(0,0,common_rows,common_cols) = this->block(0,0,common_rows,common_cols); + this->derived().swap(tmp); + } + + EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t, bool init_with_zero = false) + { + // Note: see the comment in conservativeResize(int,int,bool) + conservativeResize(rows, cols(), init_with_zero); + } + + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, int cols, bool init_with_zero = false) + { + // Note: see the comment in conservativeResize(int,int,bool) + conservativeResize(rows(), cols, init_with_zero); + } + + /** Resizes \c *this to a vector of length \a size while retaining old values of *this. + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * When values are appended, they will be uninitialized per default and set + * to zero when init_with_zero is set to true. + */ + inline void conservativeResize(int size, bool init_with_zero = false) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) + + if (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) + { + PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(size) : PlainMatrixType(size); + const int common_size = std::min(this->size(),size); + tmp.segment(0,common_size) = this->segment(0,common_size); + this->derived().swap(tmp); + } } /** Copies the value of the expression \a other into \c *this with automatic resizing. @@ -711,7 +712,7 @@ class Matrix m_storage.data()[0] = x; m_storage.data()[1] = y; } - + template friend struct ei_matrix_swap_impl; }; From a7ed998d523287e790142f4d3ff3d7f8e37e4d17 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Sep 2009 10:05:22 +0200 Subject: [PATCH 45/66] bug fix in novel makeGivens for real --- Eigen/src/Jacobi/Jacobi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 7fd57ed5f..3905f4d8f 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -233,7 +233,7 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar m_s = qq) + else if(ei_abs(p) > ei_abs(q)) { Scalar t = q/p; Scalar u = ei_sqrt(Scalar(1) + ei_abs2(t)); @@ -250,7 +250,7 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar if(q Date: Fri, 4 Sep 2009 10:17:28 +0200 Subject: [PATCH 46/66] extend mixingtype test to check diagonal products and fix the later for real*complex products --- Eigen/src/Core/DiagonalProduct.h | 6 +++--- test/mixingtypes.cpp | 28 +++++++++++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index b838d1b31..7eaa380eb 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -29,7 +29,7 @@ template struct ei_traits > { - typedef typename MatrixType::Scalar Scalar; + typedef typename ei_scalar_product_traits::ReturnType Scalar; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, @@ -62,7 +62,7 @@ class DiagonalProduct : ei_no_assignment_operator, { return m_diagonal.diagonal().coeff(ProductOrder == DiagonalOnTheLeft ? row : col) * m_matrix.coeff(row, col); } - + template EIGEN_STRONG_INLINE PacketScalar packet(int row, int col) const { @@ -72,7 +72,7 @@ class DiagonalProduct : ei_no_assignment_operator, DiagonalVectorPacketLoadMode = (LoadMode == Aligned && ((InnerSize%16) == 0)) ? Aligned : Unaligned }; const int indexInDiagonalVector = ProductOrder == DiagonalOnTheLeft ? row : col; - + if((int(StorageOrder) == RowMajor && int(ProductOrder) == DiagonalOnTheLeft) ||(int(StorageOrder) == ColMajor && int(ProductOrder) == DiagonalOnTheRight)) { diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 690442a02..6280c3b6e 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -33,6 +33,7 @@ #include "main.h" +using namespace std; template void mixingtypes(int size = SizeAtCompileType) { @@ -45,14 +46,14 @@ template void mixingtypes(int size = SizeAtCompileType) typedef Matrix, SizeAtCompileType, 1> Vec_cf; typedef Matrix, SizeAtCompileType, 1> Vec_cd; - Mat_f mf(size,size); - Mat_d md(size,size); - Mat_cf mcf(size,size); - Mat_cd mcd(size,size); - Vec_f vf(size,1); - Vec_d vd(size,1); - Vec_cf vcf(size,1); - Vec_cd vcd(size,1); + Mat_f mf = Mat_f::Random(size,size); + Mat_d md = mf.template cast(); + Mat_cf mcf = Mat_cf::Random(size,size); + Mat_cd mcd = mcf.template cast >(); + Vec_f vf = Vec_f::Random(size,1); + Vec_d vd = vf.template cast(); + Vec_cf vcf = Vec_cf::Random(size,1); + Vec_cd vcd = vcf.template cast >(); mf+mf; VERIFY_RAISES_ASSERT(mf+md); @@ -64,7 +65,16 @@ template void mixingtypes(int size = SizeAtCompileType) vf.dot(vf); VERIFY_RAISES_ASSERT(vd.dot(vf)); VERIFY_RAISES_ASSERT(vcf.dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h -} // especially as that might be rewritten as cwise product .sum() which would make that automatic. + // especially as that might be rewritten as cwise product .sum() which would make that automatic. + + VERIFY_IS_APPROX(vf.asDiagonal() * mcf, vf.template cast >().asDiagonal() * mcf); + VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast >()); + VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast >().asDiagonal()); + VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast >() * vcd.asDiagonal()); + +// vd.asDiagonal() * mf; // does not even compile +// vcd.asDiagonal() * mf; // does not even compile +} void mixingtypes_large(int size) From b0aa2520f120f256c00357948149b64661e54783 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Sep 2009 11:22:32 +0200 Subject: [PATCH 47/66] * add real scalar * complex matrix, real matrix * complex scalar, and complex scalar * real matrix overloads * allows the inner and outer product specialisations to mix real and complex --- Eigen/src/Core/CwiseUnaryOp.h | 14 +++++++++++-- Eigen/src/Core/MatrixBase.h | 13 +++++++++--- Eigen/src/Core/Product.h | 28 +++++++++++++------------ Eigen/src/Core/ProductBase.h | 4 ++-- Eigen/src/Core/util/XprHelper.h | 4 ++++ test/mixingtypes.cpp | 36 ++++++++++++++++++++++++--------- 6 files changed, 70 insertions(+), 29 deletions(-) diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index 6e4c0d4ec..03011800c 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -232,7 +232,7 @@ Cwise::log() const } -/** \relates MatrixBase */ +/** \returns an expression of \c *this scaled by the scalar factor \a scalar */ template EIGEN_STRONG_INLINE const typename MatrixBase::ScalarMultipleReturnType MatrixBase::operator*(const Scalar& scalar) const @@ -241,7 +241,17 @@ MatrixBase::operator*(const Scalar& scalar) const (derived(), ei_scalar_multiple_op(scalar)); } -/** \relates MatrixBase */ +/** Overloaded for efficient real matrix times complex scalar value */ +template +EIGEN_STRONG_INLINE const CwiseUnaryOp::Scalar, + std::complex::Scalar> >, Derived> +MatrixBase::operator*(const std::complex& scalar) const +{ + return CwiseUnaryOp >, Derived> + (*static_cast(this), ei_scalar_multiple2_op >(scalar)); +} + +/** \returns an expression of \c *this divided by the scalar value \a scalar */ template EIGEN_STRONG_INLINE const CwiseUnaryOp::Scalar>, Derived> MatrixBase::operator/(const Scalar& scalar) const diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index fececdd5f..ad5fde562 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -35,7 +35,7 @@ * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. */ -template struct AnyMatrixBase +template struct AnyMatrixBase : public ei_special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real> { @@ -93,7 +93,7 @@ template struct AnyMatrixBase */ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public AnyMatrixBase + : public AnyMatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: @@ -419,10 +419,17 @@ template class MatrixBase const CwiseUnaryOp::Scalar>, Derived> operator/(const Scalar& scalar) const; - inline friend const CwiseUnaryOp::Scalar>, Derived> + const CwiseUnaryOp >, Derived> + operator*(const std::complex& scalar) const; + + inline friend const ScalarMultipleReturnType operator*(const Scalar& scalar, const MatrixBase& matrix) { return matrix*scalar; } + inline friend const CwiseUnaryOp >, Derived> + operator*(const std::complex& scalar, const MatrixBase& matrix) + { return matrix*scalar; } + template const typename ProductReturnType::Type operator*(const MatrixBase &other) const; diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index dfdbca839..e7227d4f6 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -84,18 +84,18 @@ public: * based on the three dimensions of the product. * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ // FIXME I'm not sure the current mapping is the ideal one. -template struct ei_product_type_selector { enum { ret = OuterProduct }; }; -template struct ei_product_type_selector<1,1,Depth> { enum { ret = InnerProduct }; }; -template<> struct ei_product_type_selector<1,1,1> { enum { ret = InnerProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector<1,Small,Small> { enum { ret = UnrolledProduct }; }; +template struct ei_product_type_selector { enum { ret = OuterProduct }; }; +template struct ei_product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; +template<> struct ei_product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; +template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; +template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector<1,Large,Small> { enum { ret = GemvProduct }; }; -template<> struct ei_product_type_selector<1,Large,Large> { enum { ret = GemvProduct }; }; -template<> struct ei_product_type_selector<1,Small,Large> { enum { ret = GemvProduct }; }; -template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; -template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; -template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; +template<> struct ei_product_type_selector { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector { enum { ret = GemmProduct }; }; template<> struct ei_product_type_selector { enum { ret = GemmProduct }; }; template<> struct ei_product_type_selector { enum { ret = GemmProduct }; }; @@ -164,7 +164,7 @@ class GeneralProduct GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) { - EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) } @@ -203,7 +203,7 @@ class GeneralProduct GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) { - EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) } @@ -217,6 +217,7 @@ template<> struct ei_outer_product_selector { template EIGEN_DONT_INLINE static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { // FIXME make sure lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too const int cols = dest.cols(); for (int j=0; j struct ei_outer_product_selector { template EIGEN_DONT_INLINE static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { // FIXME make sure rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too const int rows = dest.rows(); for (int i=0; i > { typedef typename ei_cleantype<_Lhs>::type Lhs; typedef typename ei_cleantype<_Rhs>::type Rhs; - typedef typename ei_traits::Scalar Scalar; + typedef typename ei_scalar_product_traits::ReturnType Scalar; enum { RowsAtCompileTime = ei_traits::RowsAtCompileTime, ColsAtCompileTime = ei_traits::ColsAtCompileTime, @@ -146,7 +146,7 @@ class ScaledProduct; // functions of ProductBase, because, otherwise we would have to // define all overloads defined in MatrixBase. Furthermore, Using // "using Base::operator*" would not work with MSVC. -// +// // Also note that here we accept any compatible scalar types template const ScaledProduct diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 871259b08..2f8d35d05 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -233,6 +233,10 @@ struct ei_special_scalar_op_base return CwiseUnaryOp, Derived> (*static_cast(this), ei_scalar_multiple2_op(scalar)); } + + inline friend const CwiseUnaryOp, Derived> + operator*(const OtherScalar& scalar, const Derived& matrix) + { return matrix*scalar; } }; /** \internal Gives the type of a sub-matrix or sub-vector of a matrix of type \a ExpressionType and size \a Size diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 6280c3b6e..7dc57e6f7 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -54,6 +54,11 @@ template void mixingtypes(int size = SizeAtCompileType) Vec_d vd = vf.template cast(); Vec_cf vcf = Vec_cf::Random(size,1); Vec_cd vcd = vcf.template cast >(); + float sf = ei_random(); + double sd = ei_random(); + complex scf = ei_random >(); + complex scd = ei_random >(); + mf+mf; VERIFY_RAISES_ASSERT(mf+md); @@ -62,18 +67,31 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_RAISES_ASSERT(vf+=vd); VERIFY_RAISES_ASSERT(mcd=md); + // check scalar products + VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); + VERIFY_IS_APPROX(sd * vcd, complex(sd) * vcd); + VERIFY_IS_APPROX(vf * scf , vf.template cast >() * scf); + VERIFY_IS_APPROX(scd * vd, scd * vd.template cast >()); + + // check dot product vf.dot(vf); VERIFY_RAISES_ASSERT(vd.dot(vf)); VERIFY_RAISES_ASSERT(vcf.dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h // especially as that might be rewritten as cwise product .sum() which would make that automatic. + // check diagonal product VERIFY_IS_APPROX(vf.asDiagonal() * mcf, vf.template cast >().asDiagonal() * mcf); VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast >()); VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast >().asDiagonal()); VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast >() * vcd.asDiagonal()); - // vd.asDiagonal() * mf; // does not even compile // vcd.asDiagonal() * mf; // does not even compile + + // check inner product + VERIFY_IS_APPROX((vf.transpose() * vcf).value(), (vf.template cast >().transpose() * vcf).value()); + + // check outer product + VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast >() * vcf.transpose()).eval()); } @@ -108,9 +126,9 @@ void mixingtypes_large(int size) // VERIFY_RAISES_ASSERT(vcd = md*vcd); // does not even compile (cannot convert complex to double) VERIFY_RAISES_ASSERT(vcf = mcf*vf); - VERIFY_RAISES_ASSERT(mf*md); - VERIFY_RAISES_ASSERT(mcf*mcd); - VERIFY_RAISES_ASSERT(mcf*vcd); +// VERIFY_RAISES_ASSERT(mf*md); // does not even compile +// VERIFY_RAISES_ASSERT(mcf*mcd); // does not even compile +// VERIFY_RAISES_ASSERT(mcf*vcd); // does not even compile VERIFY_RAISES_ASSERT(vcf = mf*vf); } @@ -157,9 +175,9 @@ void test_mixingtypes() { // check that our operator new is indeed called: CALL_SUBTEST(mixingtypes<3>()); - CALL_SUBTEST(mixingtypes<4>()); - CALL_SUBTEST(mixingtypes(20)); - - CALL_SUBTEST(mixingtypes_small<4>()); - CALL_SUBTEST(mixingtypes_large(20)); +// CALL_SUBTEST(mixingtypes<4>()); +// CALL_SUBTEST(mixingtypes(20)); +// +// CALL_SUBTEST(mixingtypes_small<4>()); +// CALL_SUBTEST(mixingtypes_large(20)); } From 80179e954916cdd8222aaa1f5e7b991c421214a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rom=C3=A1n?= Date: Fri, 21 Aug 2009 11:14:45 +0200 Subject: [PATCH 48/66] Added support for SuperLU's ILU factorization --- Eigen/src/Sparse/SuperLUSupport.h | 101 ++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 20 deletions(-) diff --git a/Eigen/src/Sparse/SuperLUSupport.h b/Eigen/src/Sparse/SuperLUSupport.h index b4f34f094..ad0c5cd92 100644 --- a/Eigen/src/Sparse/SuperLUSupport.h +++ b/Eigen/src/Sparse/SuperLUSupport.h @@ -48,6 +48,29 @@ DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex) DECL_GSSVX(SuperLU_D,dgssvx,double,double) DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex) +// similarly for the incomplete factorization using gsisx +#define DECL_GSISX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \ + inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, \ + int *perm_c, int *perm_r, int *etree, char *equed, \ + FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \ + SuperMatrix *U, void *work, int lwork, \ + SuperMatrix *B, SuperMatrix *X, \ + FLOATTYPE *recip_pivot_growth, \ + FLOATTYPE *rcond, \ + SuperLUStat_t *stats, int *info, KEYTYPE) { \ + using namespace NAMESPACE; \ + mem_usage_t mem_usage; \ + NAMESPACE::FNAME(options, A, perm_c, perm_r, etree, equed, R, C, L, \ + U, work, lwork, B, X, recip_pivot_growth, rcond, \ + &mem_usage, stats, info); \ + return mem_usage.for_lu; /* bytes used by the factor storage */ \ + } + +DECL_GSISX(SuperLU_S,sgsisx,float,float) +DECL_GSISX(SuperLU_C,cgsisx,float,std::complex) +DECL_GSISX(SuperLU_D,dgsisx,double,double) +DECL_GSISX(SuperLU_Z,zgsisx,double,std::complex) + template struct SluMatrixMapHelper; @@ -373,7 +396,7 @@ void SparseLU::compute(const MatrixType& a) m_sluA = m_matrix.asSluMatrix(); memset(&m_sluL,0,sizeof m_sluL); memset(&m_sluU,0,sizeof m_sluU); - m_sluEqued = 'B'; + //m_sluEqued = 'B'; int info = 0; m_p.resize(size); @@ -395,14 +418,38 @@ void SparseLU::compute(const MatrixType& a) m_sluX = m_sluB; StatInit(&m_sluStat); - SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], - &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], - &m_sluL, &m_sluU, - NULL, 0, - &m_sluB, &m_sluX, - &recip_pivot_gross, &rcond, - &ferr, &berr, - &m_sluStat, &info, Scalar()); + if (m_flags&IncompleteFactorization) + { + ilu_set_default_options(&m_sluOptions); + + // no attempt to preserve column sum + m_sluOptions.ILU_MILU = SILU; + + // only basic ILU(k) support -- no direct control over memory consumption + // better to use ILU_DropRule = DROP_BASIC | DROP_AREA + // and set ILU_FillFactor to max memory growth + m_sluOptions.ILU_DropRule = DROP_BASIC; + m_sluOptions.ILU_DropTol = Base::m_precision; + + SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], + &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_gross, &rcond, + &m_sluStat, &info, Scalar()); + } + else + { + SuperLU_gssvx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], + &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_gross, &rcond, + &ferr, &berr, + &m_sluStat, &info, Scalar()); + } StatFree(&m_sluStat); m_extractedDataAreDirty = true; @@ -440,17 +487,31 @@ bool SparseLU::solve(const MatrixBase &b, StatInit(&m_sluStat); int info = 0; RealScalar recip_pivot_gross, rcond; - SuperLU_gssvx( - &m_sluOptions, &m_sluA, - m_q.data(), m_p.data(), - &m_sluEtree[0], &m_sluEqued, - &m_sluRscale[0], &m_sluCscale[0], - &m_sluL, &m_sluU, - NULL, 0, - &m_sluB, &m_sluX, - &recip_pivot_gross, &rcond, - &m_sluFerr[0], &m_sluBerr[0], - &m_sluStat, &info, Scalar()); + + if (m_flags&IncompleteFactorization) + { + SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], + &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_gross, &rcond, + &m_sluStat, &info, Scalar()); + } + else + { + SuperLU_gssvx( + &m_sluOptions, &m_sluA, + m_q.data(), m_p.data(), + &m_sluEtree[0], &m_sluEqued, + &m_sluRscale[0], &m_sluCscale[0], + &m_sluL, &m_sluU, + NULL, 0, + &m_sluB, &m_sluX, + &recip_pivot_gross, &rcond, + &m_sluFerr[0], &m_sluBerr[0], + &m_sluStat, &info, Scalar()); + } StatFree(&m_sluStat); // reset to previous state From e4f94b8c58bcfe63c444463b69ac272122175d55 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 4 Sep 2009 18:19:34 +0200 Subject: [PATCH 49/66] enable ILU in super LU only if the super version supports it --- Eigen/src/Sparse/SuperLUSupport.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Sparse/SuperLUSupport.h b/Eigen/src/Sparse/SuperLUSupport.h index ad0c5cd92..98d598809 100644 --- a/Eigen/src/Sparse/SuperLUSupport.h +++ b/Eigen/src/Sparse/SuperLUSupport.h @@ -48,6 +48,12 @@ DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex) DECL_GSSVX(SuperLU_D,dgssvx,double,double) DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex) +#ifdef MILU_ALPHA +#define EIGEN_SUPERLU_HAS_ILU +#endif + +#ifdef EIGEN_SUPERLU_HAS_ILU + // similarly for the incomplete factorization using gsisx #define DECL_GSISX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \ inline float SuperLU_gsisx(superlu_options_t *options, SuperMatrix *A, \ @@ -71,6 +77,8 @@ DECL_GSISX(SuperLU_C,cgsisx,float,std::complex) DECL_GSISX(SuperLU_D,dgsisx,double,double) DECL_GSISX(SuperLU_Z,zgsisx,double,std::complex) +#endif + template struct SluMatrixMapHelper; @@ -94,7 +102,7 @@ struct SluMatrix : SuperMatrix Store = &storage; storage = other.storage; } - + SluMatrix& operator=(const SluMatrix& other) { SuperMatrix::operator=(static_cast(other)); @@ -420,6 +428,7 @@ void SparseLU::compute(const MatrixType& a) StatInit(&m_sluStat); if (m_flags&IncompleteFactorization) { + #ifdef EIGEN_SUPERLU_HAS_ILU ilu_set_default_options(&m_sluOptions); // no attempt to preserve column sum @@ -430,7 +439,7 @@ void SparseLU::compute(const MatrixType& a) // and set ILU_FillFactor to max memory growth m_sluOptions.ILU_DropRule = DROP_BASIC; m_sluOptions.ILU_DropTol = Base::m_precision; - + SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], &m_sluL, &m_sluU, @@ -438,6 +447,11 @@ void SparseLU::compute(const MatrixType& a) &m_sluB, &m_sluX, &recip_pivot_gross, &rcond, &m_sluStat, &info, Scalar()); + #else + std::cerr << "Incomplete factorization is only available in SuperLU v4\n"; + Base::m_succeeded = false; + return; + #endif } else { @@ -490,6 +504,7 @@ bool SparseLU::solve(const MatrixBase &b, if (m_flags&IncompleteFactorization) { + #ifdef EIGEN_SUPERLU_HAS_ILU SuperLU_gsisx(&m_sluOptions, &m_sluA, m_q.data(), m_p.data(), &m_sluEtree[0], &m_sluEqued, &m_sluRscale[0], &m_sluCscale[0], &m_sluL, &m_sluU, @@ -497,6 +512,10 @@ bool SparseLU::solve(const MatrixBase &b, &m_sluB, &m_sluX, &recip_pivot_gross, &rcond, &m_sluStat, &info, Scalar()); + #else + std::cerr << "Incomplete factorization is only available in SuperLU v4\n"; + return false; + #endif } else { From 5eea8f182405fd36eae8dc345cfdce146d7ca83f Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 5 Sep 2009 19:46:33 +0100 Subject: [PATCH 50/66] Typos in tutorial 1. --- doc/C01_QuickStartGuide.dox | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/C01_QuickStartGuide.dox b/doc/C01_QuickStartGuide.dox index d43dbd72d..2943aed80 100644 --- a/doc/C01_QuickStartGuide.dox +++ b/doc/C01_QuickStartGuide.dox @@ -129,7 +129,7 @@ The default constructor leaves coefficients uninitialized. Any dynamic size is s Matrix3f A; // construct 3x3 matrix with uninitialized coefficients A(0,0) = 5; // OK MatrixXf B; // construct 0x0 matrix without allocating anything -A(0,0) = 5; // Error, B is uninitialized, doesn't have any coefficients to address +B(0,0) = 5; // Error, B is uninitialized, doesn't have any coefficients to address \endcode In the above example, B is an uninitialized matrix. What to do with such a matrix? You can call resize() on it, or you can assign another matrix to it. Like this: @@ -261,7 +261,7 @@ v = 6 6 6 \subsection TutorialCasting Casting -In Eigen, any matrices of same size and same scalar type are all naturally compatible. The scalar type can be explicitely casted to another one using the template MatrixBase::cast() function: +In Eigen, any matrices of same size and same scalar type are all naturally compatible. The scalar type can be explicitly casted to another one using the template MatrixBase::cast() function: \code Matrix3d md(1,2,3); Matrix3f mf = md.cast(); @@ -328,7 +328,7 @@ In short, all arithmetic operators can be used right away as in the following ex mat4 -= mat1*1.5 + mat2 * (mat3/4); \endcode which includes two matrix scalar products ("mat1*1.5" and "mat3/4"), a matrix-matrix product ("mat2 * (mat3/4)"), -a matrix addition ("+") and substraction with assignment ("-="). +a matrix addition ("+") and subtraction with assignment ("-="). From 61fe2b6a567ac2df67d30e957342a3138b0d23b0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 10:55:33 +0200 Subject: [PATCH 51/66] bug fix in SuperLU support: the meaning of Matrix::stride() changed for vectors --- Eigen/src/Sparse/SuperLUSupport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Sparse/SuperLUSupport.h b/Eigen/src/Sparse/SuperLUSupport.h index 98d598809..708f177e8 100644 --- a/Eigen/src/Sparse/SuperLUSupport.h +++ b/Eigen/src/Sparse/SuperLUSupport.h @@ -161,7 +161,7 @@ struct SluMatrix : SuperMatrix res.nrow = mat.rows(); res.ncol = mat.cols(); - res.storage.lda = mat.stride(); + res.storage.lda = MatrixType::IsVectorAtCompileTime ? mat.size() : mat.stride(); res.storage.values = mat.data(); return res; } From 225ec02b06e013fd60dceeb6dc83cd08193719b9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 11:15:38 +0200 Subject: [PATCH 52/66] fix another .stride() issue in Cholmod support --- Eigen/src/Sparse/CholmodSupport.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Sparse/CholmodSupport.h b/Eigen/src/Sparse/CholmodSupport.h index ad59c89af..30a33c3dc 100644 --- a/Eigen/src/Sparse/CholmodSupport.h +++ b/Eigen/src/Sparse/CholmodSupport.h @@ -99,7 +99,7 @@ cholmod_dense ei_cholmod_map_eigen_to_dense(MatrixBase& mat) res.nrow = mat.rows(); res.ncol = mat.cols(); res.nzmax = res.nrow * res.ncol; - res.d = mat.derived().stride(); + res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().stride(); res.x = mat.derived().data(); res.z = 0; @@ -157,7 +157,7 @@ class SparseLLT : public SparseLLT inline const typename Base::CholMatrixType& matrixL(void) const; template - void solveInPlace(MatrixBase &b) const; + bool solveInPlace(MatrixBase &b) const; void compute(const MatrixType& matrix); @@ -216,7 +216,7 @@ SparseLLT::matrixL() const template template -void SparseLLT::solveInPlace(MatrixBase &b) const +bool SparseLLT::solveInPlace(MatrixBase &b) const { const int size = m_cholmodFactor->n; ei_assert(size==b.rows()); @@ -228,9 +228,16 @@ void SparseLLT::solveInPlace(MatrixBase &b) const // as long as our own triangular sparse solver is not fully optimal, // let's use CHOLMOD's one: cholmod_dense cdb = ei_cholmod_map_eigen_to_dense(b); - cholmod_dense* x = cholmod_solve(CHOLMOD_LDLt, m_cholmodFactor, &cdb, &m_cholmod); + //cholmod_dense* x = cholmod_solve(CHOLMOD_LDLt, m_cholmodFactor, &cdb, &m_cholmod); + cholmod_dense* x = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &cdb, &m_cholmod); + if(!x) + { + std::cerr << "Eigen: cholmod_solve failed\n"; + return false; + } b = Matrix::Map(reinterpret_cast(x->x),b.rows()); cholmod_free_dense(&x, &m_cholmod); + return true; } #endif // EIGEN_CHOLMODSUPPORT_H From a921292381d02d4932f6338aeecf9eff559d3c4b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 11:26:20 +0200 Subject: [PATCH 53/66] uncomment stuff commented for debugging (sorry for the noise) --- test/mixingtypes.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 7dc57e6f7..3e322c7fe 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -175,9 +175,9 @@ void test_mixingtypes() { // check that our operator new is indeed called: CALL_SUBTEST(mixingtypes<3>()); -// CALL_SUBTEST(mixingtypes<4>()); -// CALL_SUBTEST(mixingtypes(20)); -// -// CALL_SUBTEST(mixingtypes_small<4>()); -// CALL_SUBTEST(mixingtypes_large(20)); + CALL_SUBTEST(mixingtypes<4>()); + CALL_SUBTEST(mixingtypes(20)); + + CALL_SUBTEST(mixingtypes_small<4>()); + CALL_SUBTEST(mixingtypes_large(20)); } From bdcc0bc1570541c4516b83f1710586e214f6499f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 11:37:41 +0200 Subject: [PATCH 54/66] fix compilation of swap for ICC --- Eigen/src/Core/Matrix.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 0975b3b77..2774e0d78 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -713,13 +713,11 @@ class Matrix m_storage.data()[1] = y; } - template + template friend struct ei_matrix_swap_impl; }; -template::ret, - bool IsDynamicSize = MatrixType::SizeAtCompileTime==Dynamic> +template struct ei_matrix_swap_impl { static inline void run(MatrixType& matrix, MatrixBase& other) @@ -729,7 +727,7 @@ struct ei_matrix_swap_impl }; template -struct ei_matrix_swap_impl +struct ei_matrix_swap_impl { static inline void run(MatrixType& matrix, MatrixBase& other) { @@ -741,7 +739,8 @@ template inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) { - ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); + enum { SwapPointers = ei_is_same_type::ret && Base::SizeAtCompileTime==Dynamic }; + ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); } /** \defgroup matrixtypedefs Global matrix typedefs From b56bb441ddbd3e0a5b58a6642fafc99ff30340cf Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 12:46:16 +0200 Subject: [PATCH 55/66] add a stable_norm unit test --- test/CMakeLists.txt | 1 + test/adjoint.cpp | 9 +---- test/cholesky.cpp | 18 +++++----- test/stable_norm.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 test/stable_norm.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 03fbd48fc..4e279ea47 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -115,6 +115,7 @@ ei_add_test(product_trmv ${EI_OFLAG}) ei_add_test(product_trmm ${EI_OFLAG}) ei_add_test(product_trsm ${EI_OFLAG}) ei_add_test(product_notemporary ${EI_OFLAG}) +ei_add_test(stable_norm) ei_add_test(bandmatrix) ei_add_test(cholesky " " "${GSL_LIBRARIES}") ei_add_test(lu ${EI_OFLAG}) diff --git a/test/adjoint.cpp b/test/adjoint.cpp index 964658c65..bebf47ac3 100644 --- a/test/adjoint.cpp +++ b/test/adjoint.cpp @@ -72,13 +72,6 @@ template void adjoint(const MatrixType& m) if(NumTraits::HasFloatingPoint) VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm()); VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.dot(v1)), static_cast(1)); - if(NumTraits::HasFloatingPoint) - { - VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast(1)); - VERIFY_IS_APPROX(v1.norm(), v1.stableNorm()); - VERIFY_IS_APPROX(v1.blueNorm(), v1.stableNorm()); - VERIFY_IS_APPROX(v1.hypotNorm(), v1.stableNorm()); - } // check compatibility of dot and adjoint VERIFY(ei_isApprox(v1.dot(square * v2), (square.adjoint() * v1).dot(v2), largerEps)); @@ -124,7 +117,7 @@ void test_adjoint() } // test a large matrix only once CALL_SUBTEST( adjoint(Matrix()) ); - + { MatrixXcf a(10,10), b(10,10); VERIFY_RAISES_ASSERT(a = a.transpose()); diff --git a/test/cholesky.cpp b/test/cholesky.cpp index df937fd0f..526a9f9d0 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -82,7 +82,7 @@ template void cholesky(const MatrixType& m) // // test gsl itself ! // VERIFY_IS_APPROX(vecB, _vecB); // VERIFY_IS_APPROX(vecX, _vecX); -// +// // Gsl::free(gMatA); // Gsl::free(gSymm); // Gsl::free(gVecB); @@ -149,16 +149,16 @@ void test_cholesky() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( cholesky(Matrix()) ); -// CALL_SUBTEST( cholesky(MatrixXd(1,1)) ); -// CALL_SUBTEST( cholesky(Matrix2d()) ); -// CALL_SUBTEST( cholesky(Matrix3f()) ); -// CALL_SUBTEST( cholesky(Matrix4d()) ); + CALL_SUBTEST( cholesky(MatrixXd(1,1)) ); + CALL_SUBTEST( cholesky(Matrix2d()) ); + CALL_SUBTEST( cholesky(Matrix3f()) ); + CALL_SUBTEST( cholesky(Matrix4d()) ); CALL_SUBTEST( cholesky(MatrixXd(200,200)) ); CALL_SUBTEST( cholesky(MatrixXcd(100,100)) ); } -// CALL_SUBTEST( cholesky_verify_assert() ); -// CALL_SUBTEST( cholesky_verify_assert() ); -// CALL_SUBTEST( cholesky_verify_assert() ); -// CALL_SUBTEST( cholesky_verify_assert() ); + CALL_SUBTEST( cholesky_verify_assert() ); + CALL_SUBTEST( cholesky_verify_assert() ); + CALL_SUBTEST( cholesky_verify_assert() ); + CALL_SUBTEST( cholesky_verify_assert() ); } diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp new file mode 100644 index 000000000..0326f7bc9 --- /dev/null +++ b/test/stable_norm.cpp @@ -0,0 +1,80 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// 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 +// 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 . + +#include "main.h" + +template void stable_norm(const MatrixType& m) +{ + /* this test covers the following files: + StableNorm.h + */ + + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + int rows = m.rows(); + int cols = m.cols(); + + Scalar big = ei_random() * std::numeric_limits::max() * 1e-4; + Scalar small = 1/big; + + MatrixType vzero = MatrixType::Zero(rows, cols), + vrand = MatrixType::Random(rows, cols), + vbig(rows, cols), + vsmall(rows,cols); + + vbig.fill(big); + vsmall.fill(small); + + VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast(1)); + VERIFY_IS_APPROX(vrand.stableNorm(), vrand.norm()); + VERIFY_IS_APPROX(vrand.blueNorm(), vrand.norm()); + VERIFY_IS_APPROX(vrand.hypotNorm(), vrand.norm()); + + RealScalar size = m.size(); + + // test overflow + VERIFY_IS_NOT_APPROX(vbig.norm(), ei_sqrt(size)*big); // here the default norm must fail + VERIFY_IS_APPROX(vbig.stableNorm(), ei_sqrt(size)*big); + VERIFY_IS_APPROX(vbig.blueNorm(), ei_sqrt(size)*big); + VERIFY_IS_APPROX(vbig.hypotNorm(), ei_sqrt(size)*big); + + // test underflow + VERIFY_IS_NOT_APPROX(vsmall.norm(), ei_sqrt(size)*small); // here the default norm must fail + VERIFY_IS_APPROX(vsmall.stableNorm(), ei_sqrt(size)*small); + VERIFY_IS_APPROX(vsmall.blueNorm(), ei_sqrt(size)*small); + VERIFY_IS_APPROX(vsmall.hypotNorm(), ei_sqrt(size)*small); +} + +void test_stable_norm() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST( stable_norm(Matrix()) ); + CALL_SUBTEST( stable_norm(Vector4d()) ); + CALL_SUBTEST( stable_norm(VectorXd(ei_random(10,2000))) ); + CALL_SUBTEST( stable_norm(VectorXf(ei_random(10,2000))) ); + CALL_SUBTEST( stable_norm(VectorXcd(ei_random(10,2000))) ); + } +} + From fb5f546161fd3c4620bad9a8aef71faa7f520d1e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 12:53:25 +0200 Subject: [PATCH 56/66] improve coverage of unitOrthogonal --- test/geo_orthomethods.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp index 5e1d5bdb4..540a63b82 100644 --- a/test/geo_orthomethods.cpp +++ b/test/geo_orthomethods.cpp @@ -86,10 +86,10 @@ template void orthomethods(int size=Size) VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1)); VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1)); - if (size>3) + if (size>=3) { - v0.template start<3>().setZero(); - v0.end(size-3).setRandom(); + v0.template start<2>().setZero(); + v0.end(size-2).setRandom(); VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1)); VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1)); From ae1d1c8f6ce77c6137bedd3d8c571297524d0d78 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 14:04:56 +0200 Subject: [PATCH 57/66] improve coverage of matrix-vector product --- test/product_extra.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/product_extra.cpp b/test/product_extra.cpp index fcec362a5..3ad99fc7a 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -104,13 +104,24 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()), (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval()); + // test the vector-matrix product with non aligned starts + int i = ei_random(0,m1.rows()-2); + int j = ei_random(0,m1.cols()-2); + int r = ei_random(1,m1.rows()-i); + int c = ei_random(1,m1.cols()-j); + int i2 = ei_random(0,m1.rows()-1); + int j2 = ei_random(0,m1.cols()-1); + + VERIFY_IS_APPROX(m1.col(j2).adjoint() * m1.block(0,j,m1.rows(),c), m1.col(j2).adjoint().eval() * m1.block(0,j,m1.rows(),c).eval()); + VERIFY_IS_APPROX(m1.block(i,0,r,m1.cols()) * m1.row(i2).adjoint(), m1.block(i,0,r,m1.cols()).eval() * m1.row(i2).adjoint().eval()); + } void test_product_extra() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( product_extra(MatrixXf(ei_random(1,320), ei_random(1,320))) ); + CALL_SUBTEST( product_extra(MatrixXf(ei_random(2,320), ei_random(2,320))) ); CALL_SUBTEST( product_extra(MatrixXcf(ei_random(50,50), ei_random(50,50))) ); - CALL_SUBTEST( product_extra(Matrix,Dynamic,Dynamic,RowMajor>(ei_random(1,50), ei_random(1,50))) ); + CALL_SUBTEST( product_extra(Matrix,Dynamic,Dynamic,RowMajor>(ei_random(2,50), ei_random(2,50))) ); } } From 8f4bf4ed7ffa4f39957118a5b4162613b21f190a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 7 Sep 2009 14:05:27 +0200 Subject: [PATCH 58/66] add optional compile flags to enable coverage testing --- cmake/EigenTesting.cmake | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index e3a87f645..1baa1ae4b 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -153,11 +153,17 @@ macro(ei_init_testing) endmacro(ei_init_testing) if(CMAKE_COMPILER_IS_GNUCXX) + option(EIGEN_COVERAGE_TESTING "Enable/disable gcov" OFF) + if(EIGEN_COVERAGE_TESTING) + set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage") + else(EIGEN_COVERAGE_TESTING) + set(COVERAGE_FLAGS "") + endif(EIGEN_ENABLE_COVERAGE_TESTING) if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O2 -g2") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-inline-functions") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g2") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COVERAGE_FLAGS} -fno-inline-functions") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g2") endif(CMAKE_SYSTEM_NAME MATCHES Linux) set(EI_OFLAG "-O2") elseif(MSVC) From 64095b66108d358ebd31ab2cc596421b2bddfff3 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 7 Sep 2009 17:22:01 +0200 Subject: [PATCH 59/66] Changed the AnyMatrixBase / ei_special_scalar_op inheritance order as proposed by Gael. Added conservativeResizeLike as discussed on the mailing list. --- Eigen/src/Core/Matrix.h | 71 ++++++++++++++++++++++----------- Eigen/src/Core/MatrixBase.h | 5 +-- Eigen/src/Core/util/XprHelper.h | 4 +- test/conservative_resize.cpp | 44 +++++++++++++------- 4 files changed, 81 insertions(+), 43 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 2774e0d78..6bbd3a019 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -308,7 +308,7 @@ class Matrix */ template EIGEN_STRONG_INLINE void resizeLike(const MatrixBase& other) - { + { if(RowsAtCompileTime == 1) { ei_assert(other.isVector()); @@ -324,16 +324,14 @@ class Matrix /** Resizes \c *this to a \a rows x \a cols matrix while leaving old values of *this untouched. * - * This method is intended for dynamic-size matrices, although it is legal to call it on any - * matrix as long as fixed dimensions are left unchanged. If you only want to change the number + * This method is intended for dynamic-size matrices. If you only want to change the number * of rows and/or of columns, you can use conservativeResize(NoChange_t, int), * conservativeResize(int, NoChange_t). * * The top-left part of the resized matrix will be the same as the overlapping top-left corner - * of *this. In case values need to be appended to the matrix they will be uninitialized per - * default and set to zero when init_with_zero is set to true. + * of *this. In case values need to be appended to the matrix they will be uninitialized. */ - inline void conservativeResize(int rows, int cols, bool init_with_zero = false) + inline void conservativeResize(int rows, int cols) { // Note: Here is space for improvement. Basically, for conservativeResize(int,int), // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the @@ -341,23 +339,23 @@ class Matrix // conservativeResize(NoChange_t, int cols). For these methods new static asserts like // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(rows, cols) : PlainMatrixType(rows,cols); + PlainMatrixType tmp(rows, cols); const int common_rows = std::min(rows, this->rows()); const int common_cols = std::min(cols, this->cols()); tmp.block(0,0,common_rows,common_cols) = this->block(0,0,common_rows,common_cols); this->derived().swap(tmp); } - EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t, bool init_with_zero = false) + EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t) { - // Note: see the comment in conservativeResize(int,int,bool) - conservativeResize(rows, cols(), init_with_zero); + // Note: see the comment in conservativeResize(int,int) + conservativeResize(rows, cols()); } - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, int cols, bool init_with_zero = false) + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, int cols) { - // Note: see the comment in conservativeResize(int,int,bool) - conservativeResize(rows(), cols, init_with_zero); + // Note: see the comment in conservativeResize(int,int) + conservativeResize(rows(), cols); } /** Resizes \c *this to a vector of length \a size while retaining old values of *this. @@ -366,21 +364,23 @@ class Matrix * partially dynamic matrices when the static dimension is anything other * than 1. For example it will not work with Matrix. * - * When values are appended, they will be uninitialized per default and set - * to zero when init_with_zero is set to true. + * When values are appended, they will be uninitialized. */ - inline void conservativeResize(int size, bool init_with_zero = false) + inline void conservativeResize(int size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - if (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) - { - PlainMatrixType tmp = init_with_zero ? PlainMatrixType::Zero(size) : PlainMatrixType(size); - const int common_size = std::min(this->size(),size); - tmp.segment(0,common_size) = this->segment(0,common_size); - this->derived().swap(tmp); - } + PlainMatrixType tmp(size); + const int common_size = std::min(this->size(),size); + tmp.segment(0,common_size) = this->segment(0,common_size); + this->derived().swap(tmp); + } + + template + inline void conservativeResizeLike(const MatrixBase& other) + { + ei_conservative_resize_like_impl::run(*this, other); } /** Copies the value of the expression \a other into \c *this with automatic resizing. @@ -717,6 +717,31 @@ class Matrix friend struct ei_matrix_swap_impl; }; +template (Derived::IsVectorAtCompileTime)> +struct ei_conservative_resize_like_impl +{ + static void run(MatrixBase& _this, const MatrixBase& other) + { + MatrixBase::PlainMatrixType tmp(other); + const int common_rows = std::min(tmp.rows(), _this.rows()); + const int common_cols = std::min(tmp.cols(), _this.cols()); + tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); + _this.derived().swap(tmp); + } +}; + +template +struct ei_conservative_resize_like_impl +{ + static void run(MatrixBase& _this, const MatrixBase& other) + { + MatrixBase::PlainMatrixType tmp(other); + const int common_size = std::min(_this.size(),tmp.size()); + tmp.segment(0,common_size) = _this.segment(0,common_size); + _this.derived().swap(tmp); + } +}; + template struct ei_matrix_swap_impl { diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index ad5fde562..25a0545c6 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -36,8 +36,6 @@ * Notice that this class is trivial, it is only used to disambiguate overloaded functions. */ template struct AnyMatrixBase - : public ei_special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real> { typedef typename ei_plain_matrix_type::type PlainMatrixType; @@ -93,7 +91,8 @@ template struct AnyMatrixBase */ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public AnyMatrixBase + : public ei_special_scalar_op_base::Scalar, + typename NumTraits::Scalar>::Real> #endif // not EIGEN_PARSED_BY_DOXYGEN { public: diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 2f8d35d05..cea2faaa8 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -217,7 +217,7 @@ template struct ei_are_flags_consistent * overloads for complex types */ template::ret > -struct ei_special_scalar_op_base +struct ei_special_scalar_op_base : public AnyMatrixBase { // dummy operator* so that the // "using ei_special_scalar_op_base::operator*" compiles @@ -225,7 +225,7 @@ struct ei_special_scalar_op_base }; template -struct ei_special_scalar_op_base +struct ei_special_scalar_op_base : public AnyMatrixBase { const CwiseUnaryOp, Derived> operator*(const OtherScalar& scalar) const diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp index f0d025283..e4ff4f331 100644 --- a/test/conservative_resize.cpp +++ b/test/conservative_resize.cpp @@ -108,22 +108,36 @@ void run_vector_tests() } } +template +void run_resize_like_tests() +{ + typedef Matrix MatrixType; + + MatrixType m; + + m = MatrixType::Random(5); + m.conservativeResizeLike( MatrixType::Ones(2) ); + std::cout << m << std::endl; +} + void test_conservative_resize() { - run_matrix_tests(); - run_matrix_tests(); - run_matrix_tests(); - run_matrix_tests(); - run_matrix_tests(); - run_matrix_tests(); - run_matrix_tests, Eigen::RowMajor>(); - run_matrix_tests, Eigen::ColMajor>(); - run_matrix_tests, Eigen::RowMajor>(); - run_matrix_tests, Eigen::ColMajor>(); + run_resize_like_tests(); - run_vector_tests(); - run_vector_tests(); - run_vector_tests(); - run_vector_tests >(); - run_vector_tests >(); + //run_matrix_tests(); + //run_matrix_tests(); + //run_matrix_tests(); + //run_matrix_tests(); + //run_matrix_tests(); + //run_matrix_tests(); + //run_matrix_tests, Eigen::RowMajor>(); + //run_matrix_tests, Eigen::ColMajor>(); + //run_matrix_tests, Eigen::RowMajor>(); + //run_matrix_tests, Eigen::ColMajor>(); + + //run_vector_tests(); + //run_vector_tests(); + //run_vector_tests(); + //run_vector_tests >(); + //run_vector_tests >(); } From e49236bac6ee5689cd3719640dbe785430acbdda Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 7 Sep 2009 17:23:29 +0200 Subject: [PATCH 60/66] Ups - that was not intended to be part of the commit. --- test/conservative_resize.cpp | 44 ++++++++++++------------------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp index e4ff4f331..f0d025283 100644 --- a/test/conservative_resize.cpp +++ b/test/conservative_resize.cpp @@ -108,36 +108,22 @@ void run_vector_tests() } } -template -void run_resize_like_tests() -{ - typedef Matrix MatrixType; - - MatrixType m; - - m = MatrixType::Random(5); - m.conservativeResizeLike( MatrixType::Ones(2) ); - std::cout << m << std::endl; -} - void test_conservative_resize() { - run_resize_like_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests(); + run_matrix_tests, Eigen::RowMajor>(); + run_matrix_tests, Eigen::ColMajor>(); + run_matrix_tests, Eigen::RowMajor>(); + run_matrix_tests, Eigen::ColMajor>(); - //run_matrix_tests(); - //run_matrix_tests(); - //run_matrix_tests(); - //run_matrix_tests(); - //run_matrix_tests(); - //run_matrix_tests(); - //run_matrix_tests, Eigen::RowMajor>(); - //run_matrix_tests, Eigen::ColMajor>(); - //run_matrix_tests, Eigen::RowMajor>(); - //run_matrix_tests, Eigen::ColMajor>(); - - //run_vector_tests(); - //run_vector_tests(); - //run_vector_tests(); - //run_vector_tests >(); - //run_vector_tests >(); + run_vector_tests(); + run_vector_tests(); + run_vector_tests(); + run_vector_tests >(); + run_vector_tests >(); } From 437a79e1ab2606aa0d6346df0bee99347e771e01 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 7 Sep 2009 17:48:42 +0200 Subject: [PATCH 61/66] Fixed unit test and improved code reusage for resizing. --- Eigen/src/Core/Matrix.h | 35 ++++++++++++++--------------------- test/conservative_resize.cpp | 4 ++-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 6bbd3a019..6eae75dcd 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -331,19 +331,9 @@ class Matrix * The top-left part of the resized matrix will be the same as the overlapping top-left corner * of *this. In case values need to be appended to the matrix they will be uninitialized. */ - inline void conservativeResize(int rows, int cols) + EIGEN_STRONG_INLINE void conservativeResize(int rows, int cols) { - // Note: Here is space for improvement. Basically, for conservativeResize(int,int), - // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the - // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or - // conservativeResize(NoChange_t, int cols). For these methods new static asserts like - // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - PlainMatrixType tmp(rows, cols); - const int common_rows = std::min(rows, this->rows()); - const int common_cols = std::min(cols, this->cols()); - tmp.block(0,0,common_rows,common_cols) = this->block(0,0,common_rows,common_cols); - this->derived().swap(tmp); + conservativeResizeLike(PlainMatrixType(rows, cols)); } EIGEN_STRONG_INLINE void conservativeResize(int rows, NoChange_t) @@ -366,19 +356,13 @@ class Matrix * * When values are appended, they will be uninitialized. */ - inline void conservativeResize(int size) + EIGEN_STRONG_INLINE void conservativeResize(int size) { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Matrix) - - PlainMatrixType tmp(size); - const int common_size = std::min(this->size(),size); - tmp.segment(0,common_size) = this->segment(0,common_size); - this->derived().swap(tmp); + conservativeResizeLike(PlainMatrixType(size)); } template - inline void conservativeResizeLike(const MatrixBase& other) + EIGEN_STRONG_INLINE void conservativeResizeLike(const MatrixBase& other) { ei_conservative_resize_like_impl::run(*this, other); } @@ -722,6 +706,14 @@ struct ei_conservative_resize_like_impl { static void run(MatrixBase& _this, const MatrixBase& other) { + // Note: Here is space for improvement. Basically, for conservativeResize(int,int), + // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the + // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or + // conservativeResize(NoChange_t, int cols). For these methods new static asserts like + // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) + MatrixBase::PlainMatrixType tmp(other); const int common_rows = std::min(tmp.rows(), _this.rows()); const int common_cols = std::min(tmp.cols(), _this.cols()); @@ -735,6 +727,7 @@ struct ei_conservative_resize_like_impl { static void run(MatrixBase& _this, const MatrixBase& other) { + // segment(...) will check whether Derived/OtherDerived are vectors! MatrixBase::PlainMatrixType tmp(other); const int common_size = std::min(_this.size(),tmp.size()); tmp.segment(0,common_size) = _this.segment(0,common_size); diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp index f0d025283..b92dd5449 100644 --- a/test/conservative_resize.cpp +++ b/test/conservative_resize.cpp @@ -65,7 +65,7 @@ void run_matrix_tests() const int rows = ei_random(50,75); const int cols = ei_random(50,75); m = n = MatrixType::Random(50,50); - m.conservativeResize(rows,cols,true); + m.conservativeResizeLike(MatrixType::Zero(rows,cols)); VERIFY_IS_APPROX(m.block(0,0,n.rows(),n.cols()), n); VERIFY( rows<=50 || m.block(50,0,rows-50,cols).sum() == Scalar(0) ); VERIFY( cols<=50 || m.block(0,50,rows,cols-50).sum() == Scalar(0) ); @@ -102,7 +102,7 @@ void run_vector_tests() { const int size = ei_random(50,100); m = n = MatrixType::Random(50); - m.conservativeResize(size,true); + m.conservativeResizeLike(MatrixType::Zero(size)); VERIFY_IS_APPROX(m.segment(0,50), n); VERIFY( size<=50 || m.segment(50,size-50).sum() == Scalar(0) ); } From e6cac85333c9d03421ded5ea356f806521ae58c4 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Sep 2009 08:27:18 +0200 Subject: [PATCH 62/66] Added missing casts. --- test/stable_norm.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 0326f7bc9..b8fbf5271 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -36,8 +36,8 @@ template void stable_norm(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - Scalar big = ei_random() * std::numeric_limits::max() * 1e-4; - Scalar small = 1/big; + Scalar big = ei_random() * std::numeric_limits::max() * RealScalar(1e-4); + Scalar small = static_cast(1)/big; MatrixType vzero = MatrixType::Zero(rows, cols), vrand = MatrixType::Random(rows, cols), @@ -52,19 +52,19 @@ template void stable_norm(const MatrixType& m) VERIFY_IS_APPROX(vrand.blueNorm(), vrand.norm()); VERIFY_IS_APPROX(vrand.hypotNorm(), vrand.norm()); - RealScalar size = m.size(); + RealScalar size = static_cast(m.size()); // test overflow - VERIFY_IS_NOT_APPROX(vbig.norm(), ei_sqrt(size)*big); // here the default norm must fail - VERIFY_IS_APPROX(vbig.stableNorm(), ei_sqrt(size)*big); - VERIFY_IS_APPROX(vbig.blueNorm(), ei_sqrt(size)*big); - VERIFY_IS_APPROX(vbig.hypotNorm(), ei_sqrt(size)*big); + VERIFY_IS_NOT_APPROX(static_cast(vbig.norm()), ei_sqrt(size)*big); // here the default norm must fail + 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 underflow - VERIFY_IS_NOT_APPROX(vsmall.norm(), ei_sqrt(size)*small); // here the default norm must fail - VERIFY_IS_APPROX(vsmall.stableNorm(), ei_sqrt(size)*small); - VERIFY_IS_APPROX(vsmall.blueNorm(), ei_sqrt(size)*small); - VERIFY_IS_APPROX(vsmall.hypotNorm(), ei_sqrt(size)*small); + VERIFY_IS_NOT_APPROX(static_cast(vsmall.norm()), ei_sqrt(size)*small); // here the default norm must fail + 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); } void test_stable_norm() @@ -77,4 +77,3 @@ void test_stable_norm() CALL_SUBTEST( stable_norm(VectorXcd(ei_random(10,2000))) ); } } - From 3a2499fb112a3220d1a4281d3d451581cf0ebc2e Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Sep 2009 10:02:19 +0200 Subject: [PATCH 63/66] Fixed conservative_resize compilation errors. --- Eigen/src/Core/Matrix.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 6eae75dcd..c08f12491 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -25,6 +25,7 @@ #ifndef EIGEN_MATRIX_H #define EIGEN_MATRIX_H +template (Derived::IsVectorAtCompileTime)> struct ei_conservative_resize_like_impl; /** \class Matrix * @@ -701,7 +702,7 @@ class Matrix friend struct ei_matrix_swap_impl; }; -template (Derived::IsVectorAtCompileTime)> +template struct ei_conservative_resize_like_impl { static void run(MatrixBase& _this, const MatrixBase& other) @@ -714,7 +715,7 @@ struct ei_conservative_resize_like_impl EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) - MatrixBase::PlainMatrixType tmp(other); + typename MatrixBase::PlainMatrixType tmp(other); const int common_rows = std::min(tmp.rows(), _this.rows()); const int common_cols = std::min(tmp.cols(), _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); @@ -728,7 +729,7 @@ struct ei_conservative_resize_like_impl static void run(MatrixBase& _this, const MatrixBase& other) { // segment(...) will check whether Derived/OtherDerived are vectors! - MatrixBase::PlainMatrixType tmp(other); + typename MatrixBase::PlainMatrixType tmp(other); const int common_size = std::min(_this.size(),tmp.size()); tmp.segment(0,common_size) = _this.segment(0,common_size); _this.derived().swap(tmp); From 26ed19e4cf0b1ca46f814d6425e9aa90749f1097 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 8 Sep 2009 10:20:26 +0200 Subject: [PATCH 64/66] Fixed if clause. --- cmake/EigenTesting.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 1baa1ae4b..faa75c6f4 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -158,7 +158,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage") else(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "") - endif(EIGEN_ENABLE_COVERAGE_TESTING) + endif(EIGEN_COVERAGE_TESTING) if(CMAKE_SYSTEM_NAME MATCHES Linux) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2") From 220ff5413125e323ad454d325c81624549e9409c Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 8 Sep 2009 14:41:54 +0100 Subject: [PATCH 65/66] Fix LaTeX error in doxygen comment. --- Eigen/src/Jacobi/Jacobi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 3905f4d8f..eeb81c178 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -123,7 +123,7 @@ bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) } /** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 selfadjoint matrix - * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ \overline \text{this}_{pq} & \text{this}_{qq} \end{array} \right )\f$ yields + * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ (\text{this}_{pq})^* & \text{this}_{qq} \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * * Example: \include Jacobi_makeJacobi.cpp From 2a6db40f1064c71400bd0be35da440aa82591331 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 8 Sep 2009 14:51:34 +0100 Subject: [PATCH 66/66] Re-factor matrix exponential. Put all routines in a class. I think this is a cleaner design. --- .../src/MatrixFunctions/MatrixExponential.h | 467 +++++++++--------- 1 file changed, 227 insertions(+), 240 deletions(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index bf5b79955..36d13b7eb 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -25,6 +25,10 @@ #ifndef EIGEN_MATRIX_EXPONENTIAL #define EIGEN_MATRIX_EXPONENTIAL +#ifdef _MSC_VER + template Scalar log2(Scalar v) { return std::log(v)/std::log(Scalar(2)); } +#endif + /** \brief Compute the matrix exponential. * * \param M matrix whose exponential is to be computed. @@ -61,260 +65,243 @@ template EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase &M, typename MatrixBase::PlainMatrixType* result); +/** \brief Class for computing the matrix exponential.*/ +template +class MatrixExponential { -/** \internal \brief Internal helper functions for computing the - * matrix exponential. - */ -namespace MatrixExponentialInternal { + public: + + /** \brief Compute the matrix exponential. + * + * \param M matrix whose exponential is to be computed. + * \param result pointer to the matrix in which to store the result. + */ + MatrixExponential(const MatrixType &M, MatrixType *result); -#ifdef _MSC_VER - template Scalar log2(Scalar v) { return std::log(v)/std::log(Scalar(2)); } -#endif + private: + + // Prevent copying + MatrixExponential(const MatrixExponential&); + MatrixExponential& operator=(const MatrixExponential&); + + /** \brief Compute the (3,3)-Padé approximant to the exponential. + * + * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé + * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. + * + * \param A Argument of matrix exponential + */ + void pade3(const MatrixType &A); + + /** \brief Compute the (5,5)-Padé approximant to the exponential. + * + * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé + * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. + * + * \param A Argument of matrix exponential + */ + void pade5(const MatrixType &A); + + /** \brief Compute the (7,7)-Padé approximant to the exponential. + * + * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé + * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. + * + * \param A Argument of matrix exponential + */ + void pade7(const MatrixType &A); + + /** \brief Compute the (9,9)-Padé approximant to the exponential. + * + * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé + * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. + * + * \param A Argument of matrix exponential + */ + void pade9(const MatrixType &A); + + /** \brief Compute the (13,13)-Padé approximant to the exponential. + * + * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé + * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. + * + * \param A Argument of matrix exponential + */ + void pade13(const MatrixType &A); + + /** \brief Compute Padé approximant to the exponential. + * + * Computes \c m_U, \c m_V and \c m_squarings such that + * \f$ (V+U)(V-U)^{-1} \f$ is a Padé of + * \f$ \exp(2^{-\mbox{squarings}}M) \f$ around \f$ M = 0 \f$. The + * degree of the Padé approximant and the value of + * squarings are chosen such that the approximation error is no + * more than the round-off error. + * + * The argument of this function should correspond with the (real + * part of) the entries of \c m_M. It is used to select the + * correct implementation using overloading. + */ + void computeUV(double); + + /** \brief Compute Padé approximant to the exponential. + * + * \sa computeUV(double); + */ + void computeUV(float); - /** \internal \brief Compute the (3,3)-Padé approximant to - * the exponential. - * - * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé - * approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp Temporary storage, to be provided by the caller - * \param M2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - */ - template - EIGEN_STRONG_INLINE void pade3(const MatrixType &M, const MatrixType& Id, MatrixType& tmp, - MatrixType& M2, MatrixType& U, MatrixType& V) - { typedef typename ei_traits::Scalar Scalar; - const Scalar b[] = {120., 60., 12., 1.}; - M2.noalias() = M * M; - tmp = b[3]*M2 + b[1]*Id; - U.noalias() = M * tmp; - V = b[2]*M2 + b[0]*Id; - } - - /** \internal \brief Compute the (5,5)-Padé approximant to - * the exponential. - * - * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé - * approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp Temporary storage, to be provided by the caller - * \param M2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - */ - template - EIGEN_STRONG_INLINE void pade5(const MatrixType &M, const MatrixType& Id, MatrixType& tmp, - MatrixType& M2, MatrixType& U, MatrixType& V) - { - typedef typename ei_traits::Scalar Scalar; - const Scalar b[] = {30240., 15120., 3360., 420., 30., 1.}; - M2.noalias() = M * M; - MatrixType M4 = M2 * M2; - tmp = b[5]*M4 + b[3]*M2 + b[1]*Id; - U.noalias() = M * tmp; - V = b[4]*M4 + b[2]*M2 + b[0]*Id; - } - - /** \internal \brief Compute the (7,7)-Padé approximant to - * the exponential. - * - * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé - * approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp Temporary storage, to be provided by the caller - * \param M2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - */ - template - EIGEN_STRONG_INLINE void pade7(const MatrixType &M, const MatrixType& Id, MatrixType& tmp, - MatrixType& M2, MatrixType& U, MatrixType& V) - { - typedef typename ei_traits::Scalar Scalar; - const Scalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.}; - M2.noalias() = M * M; - MatrixType M4 = M2 * M2; - MatrixType M6 = M4 * M2; - tmp = b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U.noalias() = M * tmp; - V = b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; - } - - /** \internal \brief Compute the (9,9)-Padé approximant to - * the exponential. - * - * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé - * approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp Temporary storage, to be provided by the caller - * \param M2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - */ - template - EIGEN_STRONG_INLINE void pade9(const MatrixType &M, const MatrixType& Id, MatrixType& tmp, - MatrixType& M2, MatrixType& U, MatrixType& V) - { - typedef typename ei_traits::Scalar Scalar; - const Scalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240., + typedef typename NumTraits::Scalar>::Real RealScalar; + + /** \brief Pointer to matrix whose exponential is to be computed. */ + const MatrixType* m_M; + + /** \brief Even-degree terms in numerator of Padé approximant. */ + MatrixType m_U; + + /** \brief Odd-degree terms in numerator of Padé approximant. */ + MatrixType m_V; + + /** \brief Used for temporary storage. */ + MatrixType m_tmp1; + + /** \brief Used for temporary storage. */ + MatrixType m_tmp2; + + /** \brief Identity matrix of the same size as \c m_M. */ + MatrixType m_Id; + + /** \brief Number of squarings required in the last step. */ + int m_squarings; + + /** \brief L1 norm of m_M. */ + float m_l1norm; +}; + +template +MatrixExponential::MatrixExponential(const MatrixType &M, MatrixType *result) : + m_M(&M), + m_U(M.rows(),M.cols()), + m_V(M.rows(),M.cols()), + m_tmp1(M.rows(),M.cols()), + m_tmp2(M.rows(),M.cols()), + m_Id(MatrixType::Identity(M.rows(), M.cols())), + m_squarings(0), + m_l1norm(static_cast(M.cwise().abs().colwise().sum().maxCoeff())) +{ + computeUV(RealScalar()); + m_tmp1 = m_U + m_V; // numerator of Pade approximant + m_tmp2 = -m_U + m_V; // denominator of Pade approximant + m_tmp2.partialLu().solve(m_tmp1, result); + for (int i=0; i +EIGEN_STRONG_INLINE void MatrixExponential::pade3(const MatrixType &A) +{ + const Scalar b[] = {120., 60., 12., 1.}; + m_tmp1.noalias() = A * A; + m_tmp2 = b[3]*m_tmp1 + b[1]*m_Id; + m_U.noalias() = A * m_tmp2; + m_V = b[2]*m_tmp1 + b[0]*m_Id; +} + +template +EIGEN_STRONG_INLINE void MatrixExponential::pade5(const MatrixType &A) +{ + const Scalar b[] = {30240., 15120., 3360., 420., 30., 1.}; + MatrixType A2 = A * A; + m_tmp1.noalias() = A2 * A2; + m_tmp2 = b[5]*m_tmp1 + b[3]*A2 + b[1]*m_Id; + m_U.noalias() = A * m_tmp2; + m_V = b[4]*m_tmp1 + b[2]*A2 + b[0]*m_Id; +} + +template +EIGEN_STRONG_INLINE void MatrixExponential::pade7(const MatrixType &A) +{ + const Scalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.}; + MatrixType A2 = A * A; + MatrixType A4 = A2 * A2; + m_tmp1.noalias() = A4 * A2; + m_tmp2 = b[7]*m_tmp1 + b[5]*A4 + b[3]*A2 + b[1]*m_Id; + m_U.noalias() = A * m_tmp2; + m_V = b[6]*m_tmp1 + b[4]*A4 + b[2]*A2 + b[0]*m_Id; +} + +template +EIGEN_STRONG_INLINE void MatrixExponential::pade9(const MatrixType &A) +{ + const Scalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240., 2162160., 110880., 3960., 90., 1.}; - M2.noalias() = M * M; - MatrixType M4 = M2 * M2; - MatrixType M6 = M4 * M2; - MatrixType M8 = M6 * M2; - tmp = b[9]*M8 + b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U.noalias() = M * tmp; - V = b[8]*M8 + b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; - } - - /** \internal \brief Compute the (13,13)-Padé approximant to - * the exponential. - * - * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé - * approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp Temporary storage, to be provided by the caller - * \param M2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - */ - template - EIGEN_STRONG_INLINE void pade13(const MatrixType &M, const MatrixType& Id, MatrixType& tmp, - MatrixType& M2, MatrixType& U, MatrixType& V) - { - typedef typename ei_traits::Scalar Scalar; - const Scalar b[] = {64764752532480000., 32382376266240000., 7771770303897600., + MatrixType A2 = A * A; + MatrixType A4 = A2 * A2; + MatrixType A6 = A4 * A2; + m_tmp1.noalias() = A6 * A2; + m_tmp2 = b[9]*m_tmp1 + b[7]*A6 + b[5]*A4 + b[3]*A2 + b[1]*m_Id; + m_U.noalias() = A * m_tmp2; + m_V = b[8]*m_tmp1 + b[6]*A6 + b[4]*A4 + b[2]*A2 + b[0]*m_Id; +} + +template +EIGEN_STRONG_INLINE void MatrixExponential::pade13(const MatrixType &A) +{ + const Scalar b[] = {64764752532480000., 32382376266240000., 7771770303897600., 1187353796428800., 129060195264000., 10559470521600., 670442572800., 33522128640., 1323241920., 40840800., 960960., 16380., 182., 1.}; - M2.noalias() = M * M; - MatrixType M4 = M2 * M2; - MatrixType M6 = M4 * M2; - V = b[13]*M6 + b[11]*M4 + b[9]*M2; - tmp.noalias() = M6 * V; - tmp += b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; - U.noalias() = M * tmp; - tmp = b[12]*M6 + b[10]*M4 + b[8]*M2; - V.noalias() = M6 * tmp; - V += b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; - } - - /** \internal \brief Helper class for computing Padé - * approximants to the exponential. - */ - template ::Scalar>::Real> - struct computeUV_selector - { - /** \internal \brief Compute Padé approximant to the exponential. - * - * Computes \p U, \p V and \p squarings such that \f$ (V+U)(V-U)^{-1} \f$ - * is a Padé of \f$ \exp(2^{-\mbox{squarings}}M) \f$ - * around \f$ M = 0 \f$. The degree of the Padé - * approximant and the value of squarings are chosen such that - * the approximation error is no more than the round-off error. - * - * \param M Argument of matrix exponential - * \param Id Identity matrix of same size as M - * \param tmp1 Temporary storage, to be provided by the caller - * \param tmp2 Temporary storage, to be provided by the caller - * \param U Even-degree terms in numerator of Padé approximant - * \param V Odd-degree terms in numerator of Padé approximant - * \param l1norm L1 norm of M - * \param squarings Pointer to integer containing number of times - * that the result needs to be squared to find the - * matrix exponential - */ - static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2, - MatrixType& U, MatrixType& V, float l1norm, int* squarings); - }; - - template - struct computeUV_selector - { - static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2, - MatrixType& U, MatrixType& V, float l1norm, int* squarings) - { - *squarings = 0; - if (l1norm < 4.258730016922831e-001) { - pade3(M, Id, tmp1, tmp2, U, V); - } else if (l1norm < 1.880152677804762e+000) { - pade5(M, Id, tmp1, tmp2, U, V); - } else { - const float maxnorm = 3.925724783138660f; - *squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm))); - MatrixType A = M / std::pow(typename ei_traits::Scalar(2), *squarings); - pade7(A, Id, tmp1, tmp2, U, V); - } - } - }; - - template - struct computeUV_selector - { - static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2, - MatrixType& U, MatrixType& V, float l1norm, int* squarings) - { - *squarings = 0; - if (l1norm < 1.495585217958292e-002) { - pade3(M, Id, tmp1, tmp2, U, V); - } else if (l1norm < 2.539398330063230e-001) { - pade5(M, Id, tmp1, tmp2, U, V); - } else if (l1norm < 9.504178996162932e-001) { - pade7(M, Id, tmp1, tmp2, U, V); - } else if (l1norm < 2.097847961257068e+000) { - pade9(M, Id, tmp1, tmp2, U, V); - } else { - const double maxnorm = 5.371920351148152; - *squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm))); - MatrixType A = M / std::pow(typename ei_traits::Scalar(2), *squarings); - pade13(A, Id, tmp1, tmp2, U, V); - } - } - }; - - /** \internal \brief Compute the matrix exponential. - * - * \param M matrix whose exponential is to be computed. - * \param result pointer to the matrix in which to store the result. - */ - template - void compute(const MatrixType &M, MatrixType* result) - { - MatrixType num(M.rows(), M.cols()); - MatrixType den(M.rows(), M.cols()); - MatrixType U(M.rows(), M.cols()); - MatrixType V(M.rows(), M.cols()); - MatrixType Id = MatrixType::Identity(M.rows(), M.cols()); - float l1norm = static_cast(M.cwise().abs().colwise().sum().maxCoeff()); - int squarings; - computeUV_selector::run(M, Id, num, den, U, V, l1norm, &squarings); - num = U + V; // numerator of Pade approximant - den = -U + V; // denominator of Pade approximant - den.partialLu().solve(num, result); - for (int i=0; i +void MatrixExponential::computeUV(float) +{ + if (m_l1norm < 4.258730016922831e-001) { + pade3(*m_M); + } else if (m_l1norm < 1.880152677804762e+000) { + pade5(*m_M); + } else { + const float maxnorm = 3.925724783138660f; + m_squarings = std::max(0, (int)ceil(log2(m_l1norm / maxnorm))); + MatrixType A = *m_M / std::pow(Scalar(2), m_squarings); + pade7(A); + } +} + +template +void MatrixExponential::computeUV(double) +{ + if (m_l1norm < 1.495585217958292e-002) { + pade3(*m_M); + } else if (m_l1norm < 2.539398330063230e-001) { + pade5(*m_M); + } else if (m_l1norm < 9.504178996162932e-001) { + pade7(*m_M); + } else if (m_l1norm < 2.097847961257068e+000) { + pade9(*m_M); + } else { + const double maxnorm = 5.371920351148152; + m_squarings = std::max(0, (int)ceil(log2(m_l1norm / maxnorm))); + MatrixType A = *m_M / std::pow(Scalar(2), m_squarings); + pade13(A); + } +} template EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase &M, typename MatrixBase::PlainMatrixType* result) { ei_assert(M.rows() == M.cols()); - MatrixExponentialInternal::compute(M.eval(), result); + MatrixExponential::PlainMatrixType>(M, result); } #endif // EIGEN_MATRIX_EXPONENTIAL
@@ -464,7 +464,7 @@ mat = 2 7 8 Also note that maxCoeff and minCoeff can takes optional arguments returning the coordinates of the respective min/max coeff: \link MatrixBase::maxCoeff(int*,int*) const maxCoeff(int* i, int* j) \endlink, \link MatrixBase::minCoeff(int*,int*) const minCoeff(int* i, int* j) \endlink. -\b Side \b note: The all() and any() functions are especially useful in combinaison with coeff-wise comparison operators (\ref CwiseAll "example"). +\b Side \b note: The all() and any() functions are especially useful in combination with coeff-wise comparison operators (\ref CwiseAll "example"). @@ -578,7 +578,7 @@ vec1.normalize();\endcode top\section TutorialCoreTriangularMatrix Dealing with triangular matrices -Currently, Eigen does not provide any explcit triangular matrix, with storage class. Instead, we +Currently, Eigen does not provide any explicit triangular matrix, with storage class. Instead, we can reference a triangular part of a square matrix or expression to perform special treatment on it. This is achieved by the class TriangularView and the MatrixBase::triangularView template function. Note that the opposite triangular part of the matrix is never referenced, and so it can, e.g., store @@ -595,12 +595,12 @@ m.triangularView() m.triangularView()\endcode
-Writting to a specific triangular part:\n (only the referenced triangular part is evaluated) +Writing to a specific triangular part:\n (only the referenced triangular part is evaluated) \code m1.triangularView() = m2 + m3 \endcode
-Convertion to a dense matrix setting the opposite triangular part to zero: +Conversion to a dense matrix setting the opposite triangular part to zero: \code m2 = m1.triangularView()\endcode