diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c068e6f5..bf609be66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,12 @@ project(Eigen) cmake_minimum_required(VERSION 2.6.2) # automatically parse the version number -file(READ "${CMAKE_SOURCE_DIR}/Eigen/src/Core/util/Macros.h" _eigen2_version_header LIMIT 5000 OFFSET 1000) -string(REGEX MATCH "define *EIGEN_WORLD_VERSION ([0-9]*)" _eigen2_world_version_match "${_eigen2_version_header}") +file(READ "${CMAKE_SOURCE_DIR}/Eigen/src/Core/util/Macros.h" _eigen2_version_header) +string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen2_world_version_match "${_eigen2_version_header}") set(EIGEN2_WORLD_VERSION "${CMAKE_MATCH_1}") -string(REGEX MATCH "define *EIGEN_MAJOR_VERSION ([0-9]*)" _eigen2_major_version_match "${_eigen2_version_header}") +string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen2_major_version_match "${_eigen2_version_header}") set(EIGEN2_MAJOR_VERSION "${CMAKE_MATCH_1}") -string(REGEX MATCH "define *EIGEN_MINOR_VERSION ([0-9]*)" _eigen2_minor_version_match "${_eigen2_version_header}") +string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen2_minor_version_match "${_eigen2_version_header}") set(EIGEN2_MINOR_VERSION "${CMAKE_MATCH_1}") set(EIGEN_VERSION_NUMBER ${EIGEN2_WORLD_VERSION}.${EIGEN2_MAJOR_VERSION}.${EIGEN2_MINOR_VERSION}) @@ -142,21 +142,23 @@ if(EIGEN_BUILD_BTL) endif(EIGEN_BUILD_BTL) ei_testing_print_summary() -if(NOT MSVC_IDE) + message("") message("Configured Eigen ${EIGEN_VERSION_NUMBER}") -message("You can now do the following:") -message("--------------+----------------------------------------------------------------") -message("Command | Description") -message("--------------+----------------------------------------------------------------") -message("make install | Install to ${CMAKE_INSTALL_PREFIX}") -message(" | * To change that: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") -message("make btest | Build the unit tests") -message(" | * That takes lots of memory! Easy on the -j option") -message("make test | Build and run the unit tests (using CTest)") -message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") -message("make debug_qr | Build a test with full debug info. To run it: test/debug_qr") -message("make blas | Build BLAS library (not the same thing as Eigen)") -message("make doc | Generate the API documentation, requires Doxygen & LaTeX") -message("--------------+----------------------------------------------------------------") -endif(NOT MSVC_IDE) + +string(TOLOWER "${CMAKE_GENERATOR}" cmake_generator_tolower) +if(cmake_generator_tolower MATCHES "makefile") + message("You can now do the following:") + message("--------------+----------------------------------------------------------------") + message("Command | Description") + message("--------------+----------------------------------------------------------------") + message("make install | Install to ${CMAKE_INSTALL_PREFIX}") + message(" | * To change that: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") + message("make btest | Build the unit tests") + message("make test | Build and run the unit tests (using CTest)") + message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") + message("make debug_qr | Build a test with full debug info. To run it: test/debug_qr") + message("make blas | Build BLAS library (not the same thing as Eigen)") + message("make doc | Generate the API documentation, requires Doxygen & LaTeX") + message("--------------+----------------------------------------------------------------") +endif() diff --git a/Eigen/CMakeLists.txt b/Eigen/CMakeLists.txt index 931cc6e20..e0eb837a5 100644 --- a/Eigen/CMakeLists.txt +++ b/Eigen/CMakeLists.txt @@ -1,25 +1,5 @@ set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD LeastSquares QtAlignedMalloc StdVector Householder Jacobi Eigenvalues) -if(EIGEN_BUILD_LIB) - set(Eigen_SRCS - src/Core/CoreInstantiations.cpp - src/Cholesky/CholeskyInstantiations.cpp - src/QR/QrInstantiations.cpp - ) - - add_library(Eigen2 SHARED ${Eigen_SRCS}) - - install(TARGETS Eigen2 - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) -endif(EIGEN_BUILD_LIB) - -if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g1 -O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1 -O2") -endif(CMAKE_COMPILER_IS_GNUCXX) - install(FILES ${Eigen_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel diff --git a/Eigen/Cholesky b/Eigen/Cholesky index f1806f726..634dc156f 100644 --- a/Eigen/Cholesky +++ b/Eigen/Cholesky @@ -30,6 +30,7 @@ namespace Eigen { * \endcode */ +#include "src/misc/Solve.h" #include "src/Array/CwiseOperators.h" #include "src/Array/Functors.h" #include "src/Cholesky/LLT.h" diff --git a/Eigen/LU b/Eigen/LU index c63463359..e4aa3ecde 100644 --- a/Eigen/LU +++ b/Eigen/LU @@ -18,8 +18,11 @@ namespace Eigen { * \endcode */ -#include "src/LU/LU.h" -#include "src/LU/PartialLU.h" +#include "src/misc/Solve.h" +#include "src/misc/Kernel.h" +#include "src/misc/Image.h" +#include "src/LU/FullPivLU.h" +#include "src/LU/PartialPivLU.h" #include "src/LU/Determinant.h" #include "src/LU/Inverse.h" diff --git a/Eigen/QR b/Eigen/QR index f38e96c5e..de0179865 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -33,9 +33,10 @@ namespace Eigen { * \endcode */ +#include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" -#include "src/QR/FullPivotingHouseholderQR.h" -#include "src/QR/ColPivotingHouseholderQR.h" +#include "src/QR/FullPivHouseholderQR.h" +#include "src/QR/ColPivHouseholderQR.h" // declare all classes for a given matrix type #define EIGEN_QR_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ diff --git a/Eigen/SVD b/Eigen/SVD index 8d66d0736..44f0f4b31 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -22,6 +22,7 @@ namespace Eigen { * \endcode */ +#include "src/misc/Solve.h" #include "src/SVD/SVD.h" #include "src/SVD/JacobiSVD.h" diff --git a/Eigen/src/CMakeLists.txt b/Eigen/src/CMakeLists.txt index 0df8273d1..4c3ee6cb8 100644 --- a/Eigen/src/CMakeLists.txt +++ b/Eigen/src/CMakeLists.txt @@ -10,3 +10,4 @@ ADD_SUBDIRECTORY(Sparse) ADD_SUBDIRECTORY(Jacobi) ADD_SUBDIRECTORY(Householder) ADD_SUBDIRECTORY(Eigenvalues) +ADD_SUBDIRECTORY(misc) \ No newline at end of file diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index c8d92f3c0..d0f292634 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -43,8 +43,8 @@ * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root * on D also stabilizes the computation. * - * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky decomposition to determine - * whether a system of equations has a solution. + * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky + * decomposition to determine whether a system of equations has a solution. * * \sa MatrixBase::ldlt(), class LLT */ @@ -52,10 +52,10 @@ * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ -template class LDLT +template class LDLT { public: - + typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix VectorType; @@ -88,7 +88,7 @@ template class LDLT /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, * representing the P permutation i.e. the permutation of the rows. For its precise meaning, - * see the examples given in the documentation of class LU. + * see the examples given in the documentation of class FullPivLU. */ inline const IntColVectorType& permutationP() const { @@ -117,14 +117,40 @@ template class LDLT return m_sign == -1; } - template - bool solve(const MatrixBase &b, ResultType *result) const; - + /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \note_about_checking_solutions + * + * \sa solveInPlace(), MatrixBase::ldlt() + */ + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "LDLT is not initialized."); + ei_assert(m_matrix.rows()==b.rows() + && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); + return ei_solve_retval(*this, b.derived()); + } + template bool solveInPlace(MatrixBase &bAndX) const; LDLT& compute(const MatrixType& matrix); + /** \returns the LDLT decomposition matrix + * + * TODO: document the storage layout + */ + inline const MatrixType& matrixLDLT() const + { + ei_assert(m_isInitialized && "LDLT is not initialized."); + return m_matrix; + } + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + protected: /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. @@ -134,7 +160,7 @@ template class LDLT */ MatrixType m_matrix; IntColVectorType m_p; - IntColVectorType m_transpositions; + IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions? int m_sign; bool m_isInitialized; }; @@ -238,27 +264,18 @@ LDLT& LDLT::compute(const MatrixType& a) return *this; } -/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. - * The result is stored in \a result - * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. - * - * In other words, it computes \f$ b = A^{-1} b \f$ with - * \f$ P^T{L^{*}}^{-1} D^{-1} L^{-1} P b \f$ from right to left. - * - * \sa LDLT::solveInPlace(), MatrixBase::ldlt() - */ -template -template -bool LDLT -::solve(const MatrixBase &b, ResultType *result) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "LDLT is not initialized."); - const int size = m_matrix.rows(); - ei_assert(size==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - *result = b; - return solveInPlace(*result); -} + EIGEN_MAKE_SOLVE_HELPERS(LDLT<_MatrixType>,Rhs) + + template void evalTo(Dest& dst) const + { + dst = rhs(); + dec().solveInPlace(dst); + } +}; /** This is the \em in-place version of solve(). * diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index ec7b8123c..a1706e53e 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -53,9 +53,10 @@ template struct LLT_Traits; * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ -template class LLT +template class LLT { - private: + public: + typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix VectorType; @@ -68,8 +69,6 @@ template class LLT typedef LLT_Traits Traits; - public: - /** * \brief Default Constructor. * @@ -99,14 +98,44 @@ template class LLT return Traits::getL(m_matrix); } - template - bool solve(const MatrixBase &b, ResultType *result) const; - + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * Since this LLT class assumes anyway that the matrix A is invertible, the solution + * theoretically exists and is unique regardless of b. + * + * Example: \include LLT_solve.cpp + * Output: \verbinclude LLT_solve.out + * + * \sa solveInPlace(), MatrixBase::llt() + */ + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "LLT is not initialized."); + ei_assert(m_matrix.rows()==b.rows() + && "LLT::solve(): invalid number of rows of the right hand side matrix b"); + return ei_solve_retval(*this, b.derived()); + } + template bool solveInPlace(MatrixBase &bAndX) const; LLT& compute(const MatrixType& matrix); + /** \returns the LLT decomposition matrix + * + * TODO: document the storage layout + */ + inline const MatrixType& matrixLLT() const + { + ei_assert(m_isInitialized && "LLT is not initialized."); + return m_matrix; + } + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + protected: /** \internal * Used to compute and store L @@ -229,28 +258,19 @@ LLT& LLT::compute(const MatrixType& a) return *this; } -/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. - * The result is stored in \a result - * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. - * - * In other words, it computes \f$ b = A^{-1} b \f$ with - * \f$ {L^{*}}^{-1} L^{-1} b \f$ from right to left. - * - * Example: \include LLT_solve.cpp - * Output: \verbinclude LLT_solve.out - * - * \sa LLT::solveInPlace(), MatrixBase::llt() - */ -template -template -bool LLT::solve(const MatrixBase &b, ResultType *result) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "LLT is not initialized."); - const int size = m_matrix.rows(); - ei_assert(size==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return solveInPlace((*result) = b); -} + typedef LLT<_MatrixType,UpLo> LLTType; + EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) + + template void evalTo(Dest& dst) const + { + dst = rhs(); + dec().solveInPlace(dst); + } +}; /** This is the \em in-place version of solve(). * diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 72ce865c1..e5eed715b 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -206,7 +206,7 @@ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const - * reference to a matrix, not a matrix! It guaranteed however, that the return type of eval() is either + * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either * PlainMatrixType or const PlainMatrixType&. */ typedef typename ei_plain_matrix_type::type PlainMatrixType; @@ -713,13 +713,23 @@ template class MatrixBase /////////// LU module /////////// - const LU lu() const; - const PartialLU partialLu() const; - const PlainMatrixType inverse() const; + const FullPivLU fullPivLu() const; + const PartialPivLU partialPivLu() const; + const PartialPivLU lu() const; + const ei_inverse_impl inverse() const; template - void computeInverse(ResultType *result) const; + void computeInverseAndDetWithCheck( + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible, + const RealScalar& absDeterminantThreshold = precision() + ) const; template - bool computeInverseWithCheck(ResultType *result ) const; + void computeInverseWithCheck( + ResultType& inverse, + bool& invertible, + const RealScalar& absDeterminantThreshold = precision() + ) const; Scalar determinant() const; /////////// Cholesky module /////////// @@ -730,8 +740,8 @@ template class MatrixBase /////////// QR module /////////// const HouseholderQR householderQr() const; - const ColPivotingHouseholderQR colPivotingHouseholderQr() const; - const FullPivotingHouseholderQR fullPivotingHouseholderQr() const; + const ColPivHouseholderQR colPivHouseholderQr() const; + const FullPivHouseholderQR fullPivHouseholderQr() const; EigenvaluesReturnType eigenvalues() const; RealScalar operatorNorm() const; diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 4a5d5c105..1d977ace2 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 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 @@ -33,10 +34,23 @@ struct ei_traits > : public ei_traits::ReturnMatrixType> { enum { - Flags = ei_traits::ReturnMatrixType>::Flags | EvalBeforeNestingBit + // FIXME had to remove the DirectAccessBit for usage like + // matrix.inverse().block(...) + // because the Block ctor with direct access + // wants to call coeffRef() to get an address, and that fails (infinite recursion) as ReturnByValue + // doesnt implement coeffRef(). + // The fact that I had to do that shows that when doing xpr.block() with a non-direct-access xpr, + // even if xpr has the EvalBeforeNestingBit, the block() doesn't use direct access on the evaluated + // xpr. + Flags = (ei_traits::ReturnMatrixType>::Flags + | EvalBeforeNestingBit) & ~DirectAccessBit }; }; +/* The ReturnByValue object doesn't even have a coeff() method. + * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. + * So ei_nested always gives the plain return matrix type. + */ template struct ei_nested, n, PlainMatrixType> { @@ -46,9 +60,9 @@ struct ei_nested, n, PlainMatrixType> template class ReturnByValue : public MatrixBase > { - typedef typename ei_traits::ReturnMatrixType ReturnMatrixType; public: EIGEN_GENERIC_PUBLIC_INTERFACE(ReturnByValue) + typedef typename ei_traits::ReturnMatrixType ReturnMatrixType; template inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index f588a8621..60ccadc21 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -220,13 +220,13 @@ template<> EIGEN_STRONG_INLINE void ei_pstoreu(double* to, const Packet2 template<> EIGEN_STRONG_INLINE void ei_pstoreu(float* to, const Packet4f& from) { ei_pstoreu((double*)to, _mm_castps_pd(from)); } template<> EIGEN_STRONG_INLINE void ei_pstoreu(int* to, const Packet4i& from) { ei_pstoreu((double*)to, _mm_castsi128_pd(from)); } -#if (_MSC_VER <= 1500) && defined(_WIN64) +#if defined(_MSC_VER) && (_MSC_VER <= 1500) && defined(_WIN64) // The temporary variable fixes an internal compilation error. // Direct of the struct members fixed bug #62. template<> EIGEN_STRONG_INLINE float ei_pfirst(const Packet4f& a) { return a.m128_f32[0]; } template<> EIGEN_STRONG_INLINE double ei_pfirst(const Packet2d& a) { return a.m128d_f64[0]; } template<> EIGEN_STRONG_INLINE int ei_pfirst(const Packet4i& a) { int x = _mm_cvtsi128_si32(a); return x; } -#elif (_MSC_VER <= 1500) +#elif defined(_MSC_VER) && (_MSC_VER <= 1500) // The temporary variable fixes an internal compilation error. template<> EIGEN_STRONG_INLINE float ei_pfirst(const Packet4f& a) { float x = _mm_cvtss_f32(a); return x; } template<> EIGEN_STRONG_INLINE double ei_pfirst(const Packet2d& a) { double x = _mm_cvtsd_f64(a); return x; } diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 169fb5aec..c9735b6e4 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -258,6 +258,11 @@ namespace { EIGEN_UNUSED NoChange_t NoChange; } +struct Default_t {}; +namespace { + EIGEN_UNUSED Default_t Default; +} + enum { IsDense = 0, IsSparse = SparseBit, diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 025904734..86df5395e 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -66,6 +66,13 @@ template class WithFormat; template struct CommaInitializer; template class ReturnByValue; +template struct ei_solve_retval_base; +template struct ei_solve_retval; +template struct ei_kernel_retval_base; +template struct ei_kernel_retval; +template struct ei_image_retval_base; +template struct ei_image_retval; + template class BandMatrix; @@ -114,11 +121,12 @@ template class VectorwiseOp; template class Replicate; template class Reverse; -template class LU; -template class PartialLU; +template class FullPivLU; +template class PartialPivLU; +template struct ei_inverse_impl; template class HouseholderQR; -template class ColPivotingHouseholderQR; -template class FullPivotingHouseholderQR; +template class ColPivHouseholderQR; +template class FullPivHouseholderQR; template class SVD; template class JacobiSVD; template class LLT; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 5ee17e91e..dd41ad0e2 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -30,7 +30,7 @@ #define EIGEN_WORLD_VERSION 2 #define EIGEN_MAJOR_VERSION 90 -#define EIGEN_MINOR_VERSION 0 +#define EIGEN_MINOR_VERSION 1 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 67b040165..b08a027c9 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -26,6 +26,155 @@ #ifndef EIGEN_QUATERNION_H #define EIGEN_QUATERNION_H +/*************************************************************************** +* Definition of QuaternionBase +* The implementation is at the end of the file +***************************************************************************/ + +template +struct ei_quaternionbase_assign_impl; + +template +class QuaternionBase : public RotationBase +{ + typedef RotationBase Base; +public: + using Base::operator*; + using Base::derived; + + typedef typename ei_traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef typename ei_traits::Coefficients Coefficients; + + // typedef typename Matrix Coefficients; + /** the type of a 3D vector */ + typedef Matrix Vector3; + /** the equivalent rotation matrix type */ + typedef Matrix Matrix3; + /** the equivalent angle-axis type */ + typedef AngleAxis AngleAxisType; + + + + /** \returns the \c x coefficient */ + inline Scalar x() const { return this->derived().coeffs().coeff(0); } + /** \returns the \c y coefficient */ + inline Scalar y() const { return this->derived().coeffs().coeff(1); } + /** \returns the \c z coefficient */ + inline Scalar z() const { return this->derived().coeffs().coeff(2); } + /** \returns the \c w coefficient */ + inline Scalar w() const { return this->derived().coeffs().coeff(3); } + + /** \returns a reference to the \c x coefficient */ + inline Scalar& x() { return this->derived().coeffs().coeffRef(0); } + /** \returns a reference to the \c y coefficient */ + inline Scalar& y() { return this->derived().coeffs().coeffRef(1); } + /** \returns a reference to the \c z coefficient */ + inline Scalar& z() { return this->derived().coeffs().coeffRef(2); } + /** \returns a reference to the \c w coefficient */ + inline Scalar& w() { return this->derived().coeffs().coeffRef(3); } + + /** \returns a read-only vector expression of the imaginary part (x,y,z) */ + inline const VectorBlock vec() const { return coeffs().template start<3>(); } + + /** \returns a vector expression of the imaginary part (x,y,z) */ + inline VectorBlock vec() { return coeffs().template start<3>(); } + + /** \returns a read-only vector expression of the coefficients (x,y,z,w) */ + inline const typename ei_traits::Coefficients& coeffs() const { return derived().coeffs(); } + + /** \returns a vector expression of the coefficients (x,y,z,w) */ + inline typename ei_traits::Coefficients& coeffs() { return derived().coeffs(); } + + template Derived& operator=(const QuaternionBase& other); + +// disabled this copy operator as it is giving very strange compilation errors when compiling +// test_stdvector with GCC 4.4.2. This looks like a GCC bug though, so feel free to re-enable it if it's +// useful; however notice that we already have the templated operator= above and e.g. in MatrixBase +// we didn't have to add, in addition to templated operator=, such a non-templated copy operator. +// Derived& operator=(const QuaternionBase& other) +// { return operator=(other); } + + Derived& operator=(const AngleAxisType& aa); + template Derived& operator=(const MatrixBase& m); + + /** \returns a quaternion representing an identity rotation + * \sa MatrixBase::Identity() + */ + inline static Quaternion Identity() { return Quaternion(1, 0, 0, 0); } + + /** \sa QuaternionBase::Identity(), MatrixBase::setIdentity() + */ + inline QuaternionBase& setIdentity() { coeffs() << 0, 0, 0, 1; return *this; } + + /** \returns the squared norm of the quaternion's coefficients + * \sa QuaternionBase::norm(), MatrixBase::squaredNorm() + */ + inline Scalar squaredNorm() const { return coeffs().squaredNorm(); } + + /** \returns the norm of the quaternion's coefficients + * \sa QuaternionBase::squaredNorm(), MatrixBase::norm() + */ + inline Scalar norm() const { return coeffs().norm(); } + + /** Normalizes the quaternion \c *this + * \sa normalized(), MatrixBase::normalize() */ + inline void normalize() { coeffs().normalize(); } + /** \returns a normalized copy of \c *this + * \sa normalize(), MatrixBase::normalized() */ + inline Quaternion normalized() const { return Quaternion(coeffs().normalized()); } + + /** \returns the dot product of \c *this and \a other + * Geometrically speaking, the dot product of two unit quaternions + * corresponds to the cosine of half the angle between the two rotations. + * \sa angularDistance() + */ + template inline Scalar dot(const QuaternionBase& other) const { return coeffs().dot(other.coeffs()); } + + template inline Scalar angularDistance(const QuaternionBase& other) const; + + Matrix3 toRotationMatrix() const; + + template + Derived& setFromTwoVectors(const MatrixBase& a, const MatrixBase& b); + + template inline Quaternion operator* (const QuaternionBase& q) const; + template inline Derived& operator*= (const QuaternionBase& q); + + Quaternion inverse() const; + Quaternion conjugate() const; + + template Quaternion slerp(Scalar t, const QuaternionBase& other) const; + + /** \returns \c true if \c *this is approximately equal to \a other, within the precision + * determined by \a prec. + * + * \sa MatrixBase::isApprox() */ + template + bool isApprox(const QuaternionBase& other, RealScalar prec = precision()) const + { return coeffs().isApprox(other.coeffs(), prec); } + + Vector3 _transformVector(Vector3 v) const; + + /** \returns \c *this with scalar type casted to \a NewScalarType + * + * Note that if \a NewScalarType is equal to the current scalar type of \c *this + * then this function smartly returns a const reference to \c *this. + */ + template + inline typename ei_cast_return_type >::type cast() const + { + return typename ei_cast_return_type >::type( + coeffs().template cast()); + } +}; + +/*************************************************************************** +* Definition/implementation of Quaternion +***************************************************************************/ + /** \geometry_module \ingroup Geometry_Module * * \class Quaternion @@ -48,152 +197,13 @@ * \sa class AngleAxis, class Transform */ -template -struct ei_quaternionbase_assign_impl; - -template class Quaternion; // [XXX] => remove when Quaternion becomes Quaternion - -template -struct ei_traits > -{ - typedef typename ei_traits::Scalar Scalar; - enum { - PacketAccess = ei_traits::PacketAccess - }; -}; - -template -class QuaternionBase : public RotationBase -{ - typedef RotationBase Base; -public: - using Base::operator*; - - typedef typename ei_traits >::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - // typedef typename Matrix Coefficients; - /** the type of a 3D vector */ - typedef Matrix Vector3; - /** the equivalent rotation matrix type */ - typedef Matrix Matrix3; - /** the equivalent angle-axis type */ - typedef AngleAxis AngleAxisType; - - /** \returns the \c x coefficient */ - inline Scalar x() const { return this->derived().coeffs().coeff(0); } - /** \returns the \c y coefficient */ - inline Scalar y() const { return this->derived().coeffs().coeff(1); } - /** \returns the \c z coefficient */ - inline Scalar z() const { return this->derived().coeffs().coeff(2); } - /** \returns the \c w coefficient */ - inline Scalar w() const { return this->derived().coeffs().coeff(3); } - - /** \returns a reference to the \c x coefficient */ - inline Scalar& x() { return this->derived().coeffs().coeffRef(0); } - /** \returns a reference to the \c y coefficient */ - inline Scalar& y() { return this->derived().coeffs().coeffRef(1); } - /** \returns a reference to the \c z coefficient */ - inline Scalar& z() { return this->derived().coeffs().coeffRef(2); } - /** \returns a reference to the \c w coefficient */ - inline Scalar& w() { return this->derived().coeffs().coeffRef(3); } - - /** \returns a read-only vector expression of the imaginary part (x,y,z) */ - inline const VectorBlock::Coefficients,3> vec() const { return this->derived().coeffs().template start<3>(); } - - /** \returns a vector expression of the imaginary part (x,y,z) */ - inline VectorBlock::Coefficients,3> vec() { return this->derived().coeffs().template start<3>(); } - - /** \returns a read-only vector expression of the coefficients (x,y,z,w) */ - inline const typename ei_traits::Coefficients& coeffs() const { return this->derived().coeffs(); } - - /** \returns a vector expression of the coefficients (x,y,z,w) */ - inline typename ei_traits::Coefficients& coeffs() { return this->derived().coeffs(); } - - template QuaternionBase& operator=(const QuaternionBase& other); - QuaternionBase& operator=(const AngleAxisType& aa); - template - QuaternionBase& operator=(const MatrixBase& m); - - /** \returns a quaternion representing an identity rotation - * \sa MatrixBase::Identity() - */ - inline static Quaternion Identity() { return Quaternion(1, 0, 0, 0); } - - /** \sa Quaternion2::Identity(), MatrixBase::setIdentity() - */ - inline QuaternionBase& setIdentity() { coeffs() << 0, 0, 0, 1; return *this; } - - /** \returns the squared norm of the quaternion's coefficients - * \sa Quaternion2::norm(), MatrixBase::squaredNorm() - */ - inline Scalar squaredNorm() const { return coeffs().squaredNorm(); } - - /** \returns the norm of the quaternion's coefficients - * \sa Quaternion2::squaredNorm(), MatrixBase::norm() - */ - inline Scalar norm() const { return coeffs().norm(); } - - /** Normalizes the quaternion \c *this - * \sa normalized(), MatrixBase::normalize() */ - inline void normalize() { coeffs().normalize(); } - /** \returns a normalized version of \c *this - * \sa normalize(), MatrixBase::normalized() */ - inline Quaternion normalized() const { return Quaternion(coeffs().normalized()); } - - /** \returns the dot product of \c *this and \a other - * Geometrically speaking, the dot product of two unit quaternions - * corresponds to the cosine of half the angle between the two rotations. - * \sa angularDistance() - */ - template inline Scalar dot(const QuaternionBase& other) const { return coeffs().dot(other.coeffs()); } - - template inline Scalar angularDistance(const QuaternionBase& other) const; - - Matrix3 toRotationMatrix(void) const; - - template - QuaternionBase& setFromTwoVectors(const MatrixBase& a, const MatrixBase& b); - - template inline Quaternion operator* (const QuaternionBase& q) const; - template inline QuaternionBase& operator*= (const QuaternionBase& q); - - Quaternion inverse(void) const; - Quaternion conjugate(void) const; - - template Quaternion slerp(Scalar t, const QuaternionBase& other) const; - - /** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \sa MatrixBase::isApprox() */ - bool isApprox(const QuaternionBase& other, RealScalar prec = precision()) const - { return coeffs().isApprox(other.coeffs(), prec); } - - Vector3 _transformVector(Vector3 v) const; - - /** \returns \c *this with scalar type casted to \a NewScalarType - * - * Note that if \a NewScalarType is equal to the current scalar type of \c *this - * then this function smartly returns a const reference to \c *this. - */ - template - inline typename ei_cast_return_type >::type cast() const - { - return typename ei_cast_return_type >::type( - coeffs().template cast()); - } -}; - template struct ei_traits > { typedef _Scalar Scalar; typedef Matrix<_Scalar,4,1> Coefficients; enum{ - PacketAccess = Aligned + PacketAccess = Aligned }; }; @@ -239,7 +249,7 @@ public: explicit inline Quaternion(const MatrixBase& other) { *this = other; } /** Copy constructor with scalar type conversion */ - template + template inline explicit Quaternion(const QuaternionBase& other) { m_coeffs = other.coeffs().template cast(); } @@ -250,16 +260,29 @@ protected: Coefficients m_coeffs; }; -/* ########### Map */ +/** \ingroup Geometry_Module + * single precision quaternion type */ +typedef Quaternion Quaternionf; +/** \ingroup Geometry_Module + * double precision quaternion type */ +typedef Quaternion Quaterniond; + +/*************************************************************************** +* Specialization of Map> +***************************************************************************/ /** \class Map * \nonstableyet * - * \brief Expression of a quaternion + * \brief Expression of a quaternion from a memory buffer * - * \param Scalar the type of the vector of diagonal coefficients + * \param _Scalar the type of the Quaternion coefficients + * \param PacketAccess see class Map * - * \sa class Quaternion, class QuaternionBase + * This is a specialization of class Map for Quaternion. This class allows to view + * a 4 scalar memory buffer as an Eigen's Quaternion object. + * + * \sa class Map, class Quaternion, class QuaternionBase */ template struct ei_traits, _PacketAccess> >: @@ -273,15 +296,23 @@ ei_traits > }; template -class Map, PacketAccess > : public QuaternionBase, PacketAccess> >, ei_no_assignment_operator { +class Map, PacketAccess > + : public QuaternionBase, PacketAccess> >, + ei_no_assignment_operator +{ public: - + typedef _Scalar Scalar; + typedef typename ei_traits::Coefficients Coefficients; - typedef typename ei_traits, PacketAccess> >::Coefficients Coefficients; + /** Constructs a Mapped Quaternion object from the pointer \a coeffs + * + * The pointer \a coeffs must reference the four coeffecients of Quaternion in the following order: + * \code *coeffs == {x, y, z, w} \endcode + * + * If the template paramter PacketAccess is set to Aligned, then the pointer coeffs must be aligned. */ + inline Map(const Scalar* coeffs) : m_coeffs(coeffs) {} - inline Map, PacketAccess >(const Scalar* coeffs) : m_coeffs(coeffs) {} - inline Coefficients& coeffs() { return m_coeffs;} inline const Coefficients& coeffs() const { return m_coeffs;} @@ -289,15 +320,20 @@ class Map, PacketAccess > : public QuaternionBase > QuaternionMapd; -typedef Map > QuaternionMapf; -typedef Map, Aligned> QuaternionMapAlignedd; -typedef Map, Aligned> QuaternionMapAlignedf; +typedef Map > QuaternionMapd; +typedef Map > QuaternionMapf; +typedef Map, Aligned> QuaternionMapAlignedd; +typedef Map, Aligned> QuaternionMapAlignedf; + +/*************************************************************************** +* Implementation of QuaternionBase methods +***************************************************************************/ // Generic Quaternion * Quaternion product -template struct ei_quat_product +// This product can be specialized for a given architecture via the Arch template argument. +template struct ei_quat_product { - inline static Quaternion run(const QuaternionBase& a, const QuaternionBase& b){ + inline static Quaternion run(const QuaternionBase& a, const QuaternionBase& b){ return Quaternion ( a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z(), @@ -311,21 +347,22 @@ template template -inline Quaternion >::Scalar> QuaternionBase::operator* (const QuaternionBase& other) const +inline Quaternion::Scalar> +QuaternionBase::operator* (const QuaternionBase& other) const { 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) - return ei_quat_product::Scalar, - ei_traits::PacketAccess && ei_traits::PacketAccess>::run(*this, other); + return ei_quat_product::Scalar, + ei_traits::PacketAccess && ei_traits::PacketAccess>::run(*this, other); } /** \sa operator*(Quaternion) */ template template -inline QuaternionBase& QuaternionBase::operator*= (const QuaternionBase& other) +inline Derived& QuaternionBase::operator*= (const QuaternionBase& other) { - return (*this = *this * other); + return (derived() = derived() * other.derived()); } /** Rotation of a vector by a quaternion. @@ -350,21 +387,21 @@ QuaternionBase::_transformVector(Vector3 v) const template template -inline QuaternionBase& QuaternionBase::operator=(const QuaternionBase& other) +inline Derived& QuaternionBase::operator=(const QuaternionBase& other) { coeffs() = other.coeffs(); - return *this; + return derived(); } /** Set \c *this from an angle-axis \a aa and returns a reference to \c *this */ template -inline QuaternionBase& QuaternionBase::operator=(const AngleAxisType& aa) +inline Derived& QuaternionBase::operator=(const AngleAxisType& aa) { Scalar ha = Scalar(0.5)*aa.angle(); // Scalar(0.5) to suppress precision loss warnings this->w() = ei_cos(ha); this->vec() = ei_sin(ha) * aa.axis(); - return *this; + return derived(); } /** Set \c *this from the expression \a xpr: @@ -375,12 +412,12 @@ inline QuaternionBase& QuaternionBase::operator=(const AngleAx template template -inline QuaternionBase& QuaternionBase::operator=(const MatrixBase& xpr) +inline Derived& QuaternionBase::operator=(const MatrixBase& xpr) { 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) ei_quaternionbase_assign_impl::run(*this, xpr.derived()); - return *this; + return derived(); } /** Convert the quaternion to a 3x3 rotation matrix. The quaternion is required to @@ -434,7 +471,7 @@ QuaternionBase::toRotationMatrix(void) const */ template template -inline QuaternionBase& QuaternionBase::setFromTwoVectors(const MatrixBase& a, const MatrixBase& b) +inline Derived& QuaternionBase::setFromTwoVectors(const MatrixBase& a, const MatrixBase& b) { Vector3 v0 = a.normalized(); Vector3 v1 = b.normalized(); @@ -458,7 +495,7 @@ inline QuaternionBase& QuaternionBase::setFromTwoVectors(const Scalar w2 = (Scalar(1)+c)*Scalar(0.5); this->w() = ei_sqrt(w2); this->vec() = axis * ei_sqrt(Scalar(1) - w2); - return *this; + return derived(); } Vector3 axis = v0.cross(v1); Scalar s = ei_sqrt((Scalar(1)+c)*Scalar(2)); @@ -466,17 +503,17 @@ inline QuaternionBase& QuaternionBase::setFromTwoVectors(const this->vec() = axis * invs; this->w() = s * Scalar(0.5); - return *this; + return derived(); } /** \returns the multiplicative inverse of \c *this * Note that in most cases, i.e., if you simply want the opposite rotation, * and/or the quaternion is normalized, then it is enough to use the conjugate. * - * \sa Quaternion2::conjugate() + * \sa QuaternionBase::conjugate() */ template -inline Quaternion >::Scalar> QuaternionBase::inverse() const +inline Quaternion::Scalar> QuaternionBase::inverse() const { // FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite() ?? Scalar n2 = this->squaredNorm(); @@ -485,7 +522,7 @@ inline Quaternion >::Scalar> Quaterni else { // return an invalid result to flag the error - return Quaternion(ei_traits::Coefficients::Zero()); + return Quaternion(Coefficients::Zero()); } } @@ -496,7 +533,8 @@ inline Quaternion >::Scalar> Quaterni * \sa Quaternion2::inverse() */ template -inline Quaternion >::Scalar> QuaternionBase::conjugate() const +inline Quaternion::Scalar> +QuaternionBase::conjugate() const { return Quaternion(this->w(),-this->x(),-this->y(),-this->z()); } @@ -506,11 +544,12 @@ inline Quaternion >::Scalar> Quaterni */ template template -inline typename ei_traits >::Scalar QuaternionBase::angularDistance(const QuaternionBase& other) const +inline typename ei_traits::Scalar +QuaternionBase::angularDistance(const QuaternionBase& other) const { double d = ei_abs(this->dot(other)); if (d>=1.0) - return 0; + return Scalar(0); return Scalar(2) * std::acos(d); } @@ -519,13 +558,14 @@ inline typename ei_traits >::Scalar QuaternionBase template -Quaternion >::Scalar> QuaternionBase::slerp(Scalar t, const QuaternionBase& other) const +Quaternion::Scalar> +QuaternionBase::slerp(Scalar t, const QuaternionBase& other) const { static const Scalar one = Scalar(1) - precision(); Scalar d = this->dot(other); Scalar absD = ei_abs(d); if (absD>=one) - return Quaternion(*this); + return Quaternion(derived()); // theta is the angle between the 2 quaternions Scalar theta = std::acos(absD); @@ -549,7 +589,7 @@ struct ei_quaternionbase_assign_impl // This algorithm comes from "Quaternion Calculus and Fast Animation", // Ken Shoemake, 1987 SIGGRAPH course notes Scalar t = mat.trace(); - if (t > 0) + if (t > Scalar(0)) { t = ei_sqrt(t + Scalar(1.0)); q.w() = Scalar(0.5)*t; diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index c49356361..4ee036140 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -885,6 +885,24 @@ Transform::fromPositionOrientationScale(const MatrixBase +struct ei_projective_transform_inverse +{ + static inline void run(const TransformType&, TransformType&) + {} +}; + +template +struct ei_projective_transform_inverse +{ + static inline void run(const TransformType& m, TransformType& res) + { + res.matrix() = m.matrix().inverse(); + } +}; + + /** \nonstableyet * * \returns the inverse transformation according to some given knowledge @@ -911,7 +929,7 @@ Transform::inverse(TransformTraits hint) const Transform res; if (hint == Projective) { - res.matrix() = m_matrix.inverse(); + ei_projective_transform_inverse::run(*this, res); } else { diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h index b587065ed..8870d9f20 100644 --- a/Eigen/src/LU/Determinant.h +++ b/Eigen/src/LU/Determinant.h @@ -53,7 +53,7 @@ template::Scalar run(const Derived& m) { - return m.partialLu().determinant(); + return m.partialPivLu().determinant(); } }; diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h new file mode 100644 index 000000000..d8975b0b6 --- /dev/null +++ b/Eigen/src/LU/FullPivLU.h @@ -0,0 +1,684 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-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_LU_H +#define EIGEN_LU_H + +/** \ingroup LU_Module + * + * \class FullPivLU + * + * \brief LU decomposition of a matrix with complete pivoting, and related features + * + * \param MatrixType the type of the matrix of which we are computing the LU decomposition + * + * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A + * is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q + * are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues (diagonal + * coefficients) of U are sorted in such a way that any zeros are at the end. + * + * This decomposition provides the generic approach to solving systems of linear equations, computing + * the rank, invertibility, inverse, kernel, and determinant. + * + * This LU decomposition is very stable and well tested with large matrices. However there are use cases where the SVD + * decomposition is inherently more stable and/or flexible. For example, when computing the kernel of a matrix, + * working with the SVD allows to select the smallest singular values of the matrix, something that + * the LU decomposition doesn't see. + * + * The data of the LU decomposition can be directly accessed through the methods matrixLU(), + * permutationP(), permutationQ(). + * + * As an exemple, here is how the original matrix can be retrieved: + * \include class_FullPivLU.cpp + * Output: \verbinclude class_FullPivLU.out + * + * \sa MatrixBase::fullPivLu(), MatrixBase::determinant(), MatrixBase::inverse() + */ +template class FullPivLU +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix IntRowVectorType; + typedef Matrix IntColVectorType; + typedef Matrix RowVectorType; + typedef Matrix ColVectorType; + + /** + * \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via LU::compute(const MatrixType&). + */ + FullPivLU(); + + /** Constructor. + * + * \param matrix the matrix of which to compute the LU decomposition. + * It is required to be nonzero. + */ + FullPivLU(const MatrixType& matrix); + + /** Computes the LU decomposition of the given matrix. + * + * \param matrix the matrix of which to compute the LU decomposition. + * It is required to be nonzero. + * + * \returns a reference to *this + */ + FullPivLU& compute(const MatrixType& matrix); + + /** \returns the LU decomposition matrix: the upper-triangular part is U, the + * unit-lower-triangular part is L (at least for square matrices; in the non-square + * case, special care is needed, see the documentation of class FullPivLU). + * + * \sa matrixL(), matrixU() + */ + inline const MatrixType& matrixLU() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return m_lu; + } + + /** \returns the number of nonzero pivots in the LU decomposition. + * Here nonzero is meant in the exact sense, not in a fuzzy sense. + * So that notion isn't really intrinsically interesting, but it is + * still useful when implementing algorithms. + * + * \sa rank() + */ + inline int nonzeroPivots() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return m_nonzero_pivots; + } + + /** \returns the absolute value of the biggest pivot, i.e. the biggest + * diagonal coefficient of U. + */ + RealScalar maxPivot() const { return m_maxpivot; } + + /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, + * representing the P permutation i.e. the permutation of the rows. For its precise meaning, + * see the examples given in the documentation of class FullPivLU. + * + * \sa permutationQ() + */ + inline const IntColVectorType& permutationP() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return m_p; + } + + /** \returns a vector of integers, whose size is the number of columns of the matrix being + * decomposed, representing the Q permutation i.e. the permutation of the columns. + * For its precise meaning, see the examples given in the documentation of class FullPivLU. + * + * \sa permutationP() + */ + inline const IntRowVectorType& permutationQ() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return m_q; + } + + /** \returns the kernel of the matrix, also called its null-space. The columns of the returned matrix + * will form a basis of the kernel. + * + * \note If the kernel has dimension zero, then the returned matrix is a column-vector filled with zeros. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + * + * Example: \include FullPivLU_kernel.cpp + * Output: \verbinclude FullPivLU_kernel.out + * + * \sa image() + */ + inline const ei_kernel_retval kernel() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return ei_kernel_retval(*this); + } + + /** \returns the image of the matrix, also called its column-space. The columns of the returned matrix + * will form a basis of the kernel. + * + * \param originalMatrix the original matrix, of which *this is the LU decomposition. + * The reason why it is needed to pass it here, is that this allows + * a large optimization, as otherwise this method would need to reconstruct it + * from the LU decomposition. + * + * \note If the image has dimension zero, then the returned matrix is a column-vector filled with zeros. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + * + * Example: \include FullPivLU_image.cpp + * Output: \verbinclude FullPivLU_image.out + * + * \sa kernel() + */ + inline const ei_image_retval + image(const MatrixType& originalMatrix) const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return ei_image_retval(*this, originalMatrix); + } + + /** \return a solution x to the equation Ax=b, where A is the matrix of which + * *this is the LU decomposition. + * + * \param b the right-hand-side of the equation to solve. Can be a vector or a matrix, + * the only requirement in order for the equation to make sense is that + * b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition. + * + * \returns a solution. + * + * \note_about_checking_solutions + * + * \note_about_arbitrary_choice_of_solution + * \note_about_using_kernel_to_study_multiple_solutions + * + * Example: \include FullPivLU_solve.cpp + * Output: \verbinclude FullPivLU_solve.out + * + * \sa TriangularView::solve(), kernel(), inverse() + */ + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return ei_solve_retval(*this, b.derived()); + } + + /** \returns the determinant of the matrix of which + * *this is the LU decomposition. It has only linear complexity + * (that is, O(n) where n is the dimension of the square matrix) + * as the LU decomposition has already been computed. + * + * \note This is only for square matrices. + * + * \note For fixed-size matrices of size up to 4, MatrixBase::determinant() offers + * optimized paths. + * + * \warning a determinant can be very big or small, so for matrices + * of large enough dimension, there is a risk of overflow/underflow. + * + * \sa MatrixBase::determinant() + */ + typename ei_traits::Scalar determinant() const; + + /** Allows to prescribe a threshold to be used by certain methods, such as rank(), + * who need to determine when pivots are to be considered nonzero. This is not used for the + * LU decomposition itself. + * + * When it needs to get the threshold value, Eigen calls threshold(). By default, this calls + * defaultThreshold(). Once you have called the present method setThreshold(const RealScalar&), + * your value is used instead. + * + * \param threshold The new value to use as the threshold. + * + * A pivot will be considered nonzero if its absolute value is strictly greater than + * \f$ \vert pivot \vert \leqslant threshold \times \vert maxpivot \vert \f$ + * where maxpivot is the biggest pivot. + * + * If you want to come back to the default behavior, call setThreshold(Default_t) + */ + FullPivLU& setThreshold(const RealScalar& threshold) + { + m_usePrescribedThreshold = true; + m_prescribedThreshold = threshold; + } + + /** Allows to come back to the default behavior, letting Eigen use its default formula for + * determining the threshold. + * + * You should pass the special object Eigen::Default as parameter here. + * \code lu.setThreshold(Eigen::Default); \endcode + * + * See the documentation of setThreshold(const RealScalar&). + */ + FullPivLU& setThreshold(Default_t) + { + m_usePrescribedThreshold = false; + } + + /** Returns the threshold that will be used by certain methods such as rank(). + * + * See the documentation of setThreshold(const RealScalar&). + */ + RealScalar threshold() const + { + ei_assert(m_isInitialized || m_usePrescribedThreshold); + return m_usePrescribedThreshold ? m_prescribedThreshold + // this formula comes from experimenting (see "LU precision tuning" thread on the list) + // and turns out to be identical to Higham's formula used already in LDLt. + : epsilon() * m_lu.diagonalSize(); + } + + /** \returns the rank of the matrix of which *this is the LU decomposition. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline int rank() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + RealScalar premultiplied_threshold = ei_abs(m_maxpivot) * threshold(); + int result = 0; + for(int i = 0; i < m_nonzero_pivots; ++i) + result += (ei_abs(m_lu.coeff(i,i)) > premultiplied_threshold); + return result; + } + + /** \returns the dimension of the kernel of the matrix of which *this is the LU decomposition. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline int dimensionOfKernel() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return m_lu.cols() - rank(); + } + + /** \returns true if the matrix of which *this is the LU decomposition represents an injective + * linear map, i.e. has trivial kernel; false otherwise. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline bool isInjective() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return rank() == m_lu.cols(); + } + + /** \returns true if the matrix of which *this is the LU decomposition represents a surjective + * linear map; false otherwise. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline bool isSurjective() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return rank() == m_lu.rows(); + } + + /** \returns true if the matrix of which *this is the LU decomposition is invertible. + * + * \note This method has to determine which pivots should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline bool isInvertible() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + return isInjective() && (m_lu.rows() == m_lu.cols()); + } + + /** \returns the inverse of the matrix of which *this is the LU decomposition. + * + * \note If this matrix is not invertible, the returned matrix has undefined coefficients. + * Use isInvertible() to first determine whether this matrix is invertible. + * + * \sa MatrixBase::inverse() + */ + inline const ei_solve_retval > inverse() const + { + ei_assert(m_isInitialized && "LU is not initialized."); + ei_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); + return ei_solve_retval > + (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols()).nestByValue()); + } + + inline int rows() const { return m_lu.rows(); } + inline int cols() const { return m_lu.cols(); } + + protected: + MatrixType m_lu; + IntColVectorType m_p; + IntRowVectorType m_q; + int m_det_pq, m_nonzero_pivots; + RealScalar m_maxpivot, m_prescribedThreshold; + bool m_isInitialized, m_usePrescribedThreshold; +}; + +template +FullPivLU::FullPivLU() + : m_isInitialized(false), m_usePrescribedThreshold(false) +{ +} + +template +FullPivLU::FullPivLU(const MatrixType& matrix) + : m_isInitialized(false), m_usePrescribedThreshold(false) +{ + compute(matrix); +} + +template +FullPivLU& FullPivLU::compute(const MatrixType& matrix) +{ + m_isInitialized = true; + m_lu = matrix; + m_p.resize(matrix.rows()); + m_q.resize(matrix.cols()); + + const int size = matrix.diagonalSize(); + const int rows = matrix.rows(); + const int cols = matrix.cols(); + + // will store the transpositions, before we accumulate them at the end. + // can't accumulate on-the-fly because that will be done in reverse order for the rows. + IntColVectorType rows_transpositions(matrix.rows()); + IntRowVectorType cols_transpositions(matrix.cols()); + int number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. rows_transpositions[i]!=i + + m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case) + m_maxpivot = RealScalar(0); + for(int k = 0; k < size; ++k) + { + // First, we need to find the pivot. + + // biggest coefficient in the remaining bottom-right corner (starting at row k, col k) + int row_of_biggest_in_corner, col_of_biggest_in_corner; + RealScalar biggest_in_corner; + biggest_in_corner = m_lu.corner(Eigen::BottomRight, rows-k, cols-k) + .cwise().abs() + .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner); + row_of_biggest_in_corner += k; // correct the values! since they were computed in the corner, + col_of_biggest_in_corner += k; // need to add k to them. + + // if the pivot (hence the corner) is exactly zero, terminate to avoid generating nan/inf values + if(biggest_in_corner == RealScalar(0)) + { + // before exiting, make sure to initialize the still uninitialized row_transpositions + // in a sane state without destroying what we already have. + m_nonzero_pivots = k; + for(int i = k; i < size; i++) + { + rows_transpositions.coeffRef(i) = i; + cols_transpositions.coeffRef(i) = i; + } + break; + } + + if(biggest_in_corner > m_maxpivot) m_maxpivot = biggest_in_corner; + + // Now that we've found the pivot, we need to apply the row/col swaps to + // bring it to the location (k,k). + + rows_transpositions.coeffRef(k) = row_of_biggest_in_corner; + cols_transpositions.coeffRef(k) = col_of_biggest_in_corner; + if(k != row_of_biggest_in_corner) { + m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner)); + ++number_of_transpositions; + } + if(k != col_of_biggest_in_corner) { + m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner)); + ++number_of_transpositions; + } + + // Now that the pivot is at the right location, we update the remaining + // bottom-right corner by Gaussian elimination. + + if(k= 0; --k) + std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k))); + + for(int k = 0; k < matrix.cols(); ++k) m_q.coeffRef(k) = k; + for(int k = 0; k < size; ++k) + std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k))); + + m_det_pq = (number_of_transpositions%2) ? -1 : 1; + return *this; +} + +template +typename ei_traits::Scalar FullPivLU::determinant() const +{ + ei_assert(m_isInitialized && "LU is not initialized."); + ei_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); + return Scalar(m_det_pq) * m_lu.diagonal().prod(); +} + +/********* Implementation of kernel() **************************************************/ + +template +struct ei_kernel_retval > + : ei_kernel_retval_base > +{ + EIGEN_MAKE_KERNEL_HELPERS(FullPivLU<_MatrixType>) + + enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( + MatrixType::MaxColsAtCompileTime, + MatrixType::MaxRowsAtCompileTime) + }; + + template void evalTo(Dest& dst) const + { + const int cols = dec().matrixLU().cols(), dimker = cols - rank(); + if(dimker == 0) + { + // The Kernel is just {0}, so it doesn't have a basis properly speaking, but let's + // avoid crashing/asserting as that depends on floating point calculations. Let's + // just return a single column vector filled with zeros. + dst.setZero(); + return; + } + + /* Let us use the following lemma: + * + * Lemma: If the matrix A has the LU decomposition PAQ = LU, + * then Ker A = Q(Ker U). + * + * Proof: trivial: just keep in mind that P, Q, L are invertible. + */ + + /* Thus, all we need to do is to compute Ker U, and then apply Q. + * + * U is upper triangular, with eigenvalues sorted so that any zeros appear at the end. + * Thus, the diagonal of U ends with exactly + * dimKer zero's. Let us use that to construct dimKer linearly + * independent vectors in Ker U. + */ + + Matrix pivots(rank()); + RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold(); + int p = 0; + for(int i = 0; i < dec().nonzeroPivots(); ++i) + if(ei_abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold) + pivots.coeffRef(p++) = i; + ei_internal_assert(p == rank()); + + // we construct a temporaty trapezoid matrix m, by taking the U matrix and + // permuting the rows and cols to bring the nonnegligible pivots to the top of + // the main diagonal. We need that to be able to apply our triangular solvers. + // FIXME when we get triangularView-for-rectangular-matrices, this can be simplified + Matrix + m(dec().matrixLU().block(0, 0, rank(), cols)); + for(int i = 0; i < rank(); ++i) + { + if(i) m.row(i).start(i).setZero(); + m.row(i).end(cols-i) = dec().matrixLU().row(pivots.coeff(i)).end(cols-i); + } + m.block(0, 0, rank(), rank()); + m.block(0, 0, rank(), rank()).template triangularView().setZero(); + for(int i = 0; i < rank(); ++i) + m.col(i).swap(m.col(pivots.coeff(i))); + + // ok, we have our trapezoid matrix, we can apply the triangular solver. + // notice that the math behind this suggests that we should apply this to the + // negative of the RHS, but for performance we just put the negative sign elsewhere, see below. + m.corner(TopLeft, rank(), rank()) + .template triangularView().solveInPlace( + m.corner(TopRight, rank(), dimker) + ); + + // now we must undo the column permutation that we had applied! + for(int i = rank()-1; i >= 0; --i) + m.col(i).swap(m.col(pivots.coeff(i))); + + // see the negative sign in the next line, that's what we were talking about above. + for(int i = 0; i < rank(); ++i) dst.row(dec().permutationQ().coeff(i)) = -m.row(i).end(dimker); + for(int i = rank(); i < cols; ++i) dst.row(dec().permutationQ().coeff(i)).setZero(); + for(int k = 0; k < dimker; ++k) dst.coeffRef(dec().permutationQ().coeff(rank()+k), k) = Scalar(1); + } +}; + +/***** Implementation of image() *****************************************************/ + +template +struct ei_image_retval > + : ei_image_retval_base > +{ + EIGEN_MAKE_IMAGE_HELPERS(FullPivLU<_MatrixType>) + + enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( + MatrixType::MaxColsAtCompileTime, + MatrixType::MaxRowsAtCompileTime) + }; + + template void evalTo(Dest& dst) const + { + if(rank() == 0) + { + // The Image is just {0}, so it doesn't have a basis properly speaking, but let's + // avoid crashing/asserting as that depends on floating point calculations. Let's + // just return a single column vector filled with zeros. + dst.setZero(); + return; + } + + Matrix pivots(rank()); + RealScalar premultiplied_threshold = dec().maxPivot() * dec().threshold(); + int p = 0; + for(int i = 0; i < dec().nonzeroPivots(); ++i) + if(ei_abs(dec().matrixLU().coeff(i,i)) > premultiplied_threshold) + pivots.coeffRef(p++) = i; + ei_internal_assert(p == rank()); + + for(int i = 0; i < rank(); ++i) + dst.col(i) = originalMatrix().col(dec().permutationQ().coeff(pivots.coeff(i))); + } +}; + +/***** Implementation of solve() *****************************************************/ + +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> +{ + EIGEN_MAKE_SOLVE_HELPERS(FullPivLU<_MatrixType>,Rhs) + + template void evalTo(Dest& dst) const + { + /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. + * So we proceed as follows: + * Step 1: compute c = P * rhs. + * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible. + * Step 3: replace c by the solution x to Ux = c. May or may not exist. + * Step 4: result = Q * c; + */ + + const int rows = dec().matrixLU().rows(), cols = dec().matrixLU().cols(), + nonzero_pivots = dec().nonzeroPivots(); + ei_assert(rhs().rows() == rows); + const int smalldim = std::min(rows, cols); + + if(nonzero_pivots == 0) + { + dst.setZero(); + return; + } + + typename Rhs::PlainMatrixType c(rhs().rows(), rhs().cols()); + + // Step 1 + for(int i = 0; i < rows; ++i) + c.row(dec().permutationP().coeff(i)) = rhs().row(i); + + // Step 2 + dec().matrixLU() + .corner(Eigen::TopLeft,smalldim,smalldim) + .template triangularView() + .solveInPlace(c.corner(Eigen::TopLeft, smalldim, c.cols())); + if(rows>cols) + { + c.corner(Eigen::BottomLeft, rows-cols, c.cols()) + -= dec().matrixLU().corner(Eigen::BottomLeft, rows-cols, cols) + * c.corner(Eigen::TopLeft, cols, c.cols()); + } + + // Step 3 + dec().matrixLU() + .corner(TopLeft, nonzero_pivots, nonzero_pivots) + .template triangularView() + .solveInPlace(c.corner(TopLeft, nonzero_pivots, c.cols())); + + // Step 4 + for(int i = 0; i < nonzero_pivots; ++i) + dst.row(dec().permutationQ().coeff(i)) = c.row(i); + for(int i = nonzero_pivots; i < dec().matrixLU().cols(); ++i) + dst.row(dec().permutationQ().coeff(i)).setZero(); + } +}; + +/******* MatrixBase methods *****************************************************************/ + +/** \lu_module + * + * \return the full-pivoting LU decomposition of \c *this. + * + * \sa class FullPivLU + */ +template +inline const FullPivLU::PlainMatrixType> +MatrixBase::fullPivLu() const +{ + return FullPivLU(eval()); +} + +#endif // EIGEN_LU_H diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 3255c1022..306b5f60a 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Benoit Jacob +// Copyright (C) 2008-2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,78 +25,165 @@ #ifndef EIGEN_INVERSE_H #define EIGEN_INVERSE_H -/******************************************************************** -*** Part 1 : optimized implementations for fixed-size 2,3,4 cases *** -********************************************************************/ +/********************************** +*** General case implementation *** +**********************************/ -template +template +struct ei_compute_inverse +{ + static inline void run(const MatrixType& matrix, ResultType& result) + { + result = matrix.partialPivLu().inverse(); + } +}; + +template +struct ei_compute_inverse_and_det_with_check { /* nothing! general case not supported. */ }; + +/**************************** +*** Size 1 implementation *** +****************************/ + +template +struct ei_compute_inverse +{ + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename MatrixType::Scalar Scalar; + result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); + } +}; + +template +struct ei_compute_inverse_and_det_with_check +{ + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& result, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + determinant = matrix.coeff(0,0); + invertible = ei_abs(determinant) > absDeterminantThreshold; + if(invertible) result.coeffRef(0,0) = typename ResultType::Scalar(1) / determinant; + } +}; + +/**************************** +*** Size 2 implementation *** +****************************/ + +template inline void ei_compute_inverse_size2_helper( - const XprType& matrix, const typename MatrixType::Scalar& invdet, - MatrixType* result) + const MatrixType& matrix, const typename ResultType::Scalar& invdet, + ResultType& result) { - result->coeffRef(0,0) = matrix.coeff(1,1) * invdet; - result->coeffRef(1,0) = -matrix.coeff(1,0) * invdet; - result->coeffRef(0,1) = -matrix.coeff(0,1) * invdet; - result->coeffRef(1,1) = matrix.coeff(0,0) * invdet; -} - -template -inline void ei_compute_inverse_size2(const MatrixType& matrix, MatrixType* result) -{ - typedef typename MatrixType::Scalar Scalar; - const Scalar invdet = Scalar(1) / matrix.determinant(); - ei_compute_inverse_size2_helper( matrix, invdet, result ); -} - -template -bool ei_compute_inverse_size2_with_check(const XprType& matrix, MatrixType* result) -{ - typedef typename MatrixType::Scalar Scalar; - const Scalar det = matrix.determinant(); - if(ei_isMuchSmallerThan(det, matrix.cwise().abs().maxCoeff())) return false; - const Scalar invdet = Scalar(1) / det; - ei_compute_inverse_size2_helper( matrix, invdet, result ); - return true; -} - -template -void ei_compute_inverse_size3_helper( - const XprType& matrix, - const typename MatrixType::Scalar& invdet, - const typename MatrixType::Scalar& det_minor00, - const typename MatrixType::Scalar& det_minor10, - const typename MatrixType::Scalar& det_minor20, - MatrixType* result) -{ - result->coeffRef(0, 0) = det_minor00 * invdet; - result->coeffRef(0, 1) = -det_minor10 * invdet; - result->coeffRef(0, 2) = det_minor20 * invdet; - result->coeffRef(1, 0) = -matrix.minor(0,1).determinant() * invdet; - result->coeffRef(1, 1) = matrix.minor(1,1).determinant() * invdet; - result->coeffRef(1, 2) = -matrix.minor(2,1).determinant() * invdet; - result->coeffRef(2, 0) = matrix.minor(0,2).determinant() * invdet; - result->coeffRef(2, 1) = -matrix.minor(1,2).determinant() * invdet; - result->coeffRef(2, 2) = matrix.minor(2,2).determinant() * invdet; -} - -template -bool ei_compute_inverse_size3(const XprType& matrix, MatrixType* result) -{ - typedef typename MatrixType::Scalar Scalar; - const Scalar det_minor00 = matrix.minor(0,0).determinant(); - const Scalar det_minor10 = matrix.minor(1,0).determinant(); - const Scalar det_minor20 = matrix.minor(2,0).determinant(); - const Scalar det = ( det_minor00 * matrix.coeff(0,0) - - det_minor10 * matrix.coeff(1,0) - + det_minor20 * matrix.coeff(2,0) ); - if(Check) if(ei_isMuchSmallerThan(det, matrix.cwise().abs().maxCoeff())) return false; - const Scalar invdet = Scalar(1) / det; - ei_compute_inverse_size3_helper( matrix, invdet, det_minor00, det_minor10, det_minor20, result ); - return true; + result.coeffRef(0,0) = matrix.coeff(1,1) * invdet; + result.coeffRef(1,0) = -matrix.coeff(1,0) * invdet; + result.coeffRef(0,1) = -matrix.coeff(0,1) * invdet; + result.coeffRef(1,1) = matrix.coeff(0,0) * invdet; } template -bool ei_compute_inverse_size4_helper(const MatrixType& matrix, ResultType* result) +struct ei_compute_inverse +{ + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename ResultType::Scalar Scalar; + const Scalar invdet = typename MatrixType::Scalar(1) / matrix.determinant(); + ei_compute_inverse_size2_helper(matrix, invdet, result); + } +}; + +template +struct ei_compute_inverse_and_det_with_check +{ + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + typedef typename ResultType::Scalar Scalar; + determinant = matrix.determinant(); + invertible = ei_abs(determinant) > absDeterminantThreshold; + if(!invertible) return; + const Scalar invdet = Scalar(1) / determinant; + ei_compute_inverse_size2_helper(matrix, invdet, inverse); + } +}; + +/**************************** +*** Size 3 implementation *** +****************************/ + +template +void ei_compute_inverse_size3_helper( + const MatrixType& matrix, + const typename ResultType::Scalar& invdet, + const Matrix& cofactors_col0, + ResultType& result) +{ + result.row(0) = cofactors_col0 * invdet; + result.coeffRef(1,0) = -matrix.minor(0,1).determinant() * invdet; + result.coeffRef(1,1) = matrix.minor(1,1).determinant() * invdet; + result.coeffRef(1,2) = -matrix.minor(2,1).determinant() * invdet; + result.coeffRef(2,0) = matrix.minor(0,2).determinant() * invdet; + result.coeffRef(2,1) = -matrix.minor(1,2).determinant() * invdet; + result.coeffRef(2,2) = matrix.minor(2,2).determinant() * invdet; +} + +template +struct ei_compute_inverse +{ + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename ResultType::Scalar Scalar; + Matrix cofactors_col0; + cofactors_col0.coeffRef(0) = matrix.minor(0,0).determinant(); + cofactors_col0.coeffRef(1) = -matrix.minor(1,0).determinant(); + cofactors_col0.coeffRef(2) = matrix.minor(2,0).determinant(); + const Scalar det = (cofactors_col0.cwise()*matrix.col(0)).sum(); + const Scalar invdet = Scalar(1) / det; + ei_compute_inverse_size3_helper(matrix, invdet, cofactors_col0, result); + } +}; + +template +struct ei_compute_inverse_and_det_with_check +{ + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + typedef typename ResultType::Scalar Scalar; + Matrix cofactors_col0; + cofactors_col0.coeffRef(0) = matrix.minor(0,0).determinant(); + cofactors_col0.coeffRef(1) = -matrix.minor(1,0).determinant(); + cofactors_col0.coeffRef(2) = matrix.minor(2,0).determinant(); + determinant = (cofactors_col0.cwise()*matrix.col(0)).sum(); + invertible = ei_abs(determinant) > absDeterminantThreshold; + if(!invertible) return; + const Scalar invdet = Scalar(1) / determinant; + ei_compute_inverse_size3_helper(matrix, invdet, cofactors_col0, inverse); + } +}; + +/**************************** +*** Size 4 implementation *** +****************************/ + +template +void ei_compute_inverse_size4_helper(const MatrixType& matrix, ResultType& result) { /* Let's split M into four 2x2 blocks: * (P Q) @@ -111,257 +198,224 @@ bool ei_compute_inverse_size4_helper(const MatrixType& matrix, ResultType* resul * Q' = -(P_inverse*Q) * S' * R' = -S' * (R*P_inverse) */ - typedef Block XprBlock22; + typedef Block XprBlock22; typedef typename MatrixBase::PlainMatrixType Block22; Block22 P_inverse; - if(ei_compute_inverse_size2_with_check(matrix.template block<2,2>(0,0), &P_inverse)) - { - const Block22 Q = matrix.template block<2,2>(0,2); - const Block22 P_inverse_times_Q = P_inverse * Q; - const XprBlock22 R = matrix.template block<2,2>(2,0); - const Block22 R_times_P_inverse = R * P_inverse; - const Block22 R_times_P_inverse_times_Q = R_times_P_inverse * Q; - const XprBlock22 S = matrix.template block<2,2>(2,2); - const Block22 X = S - R_times_P_inverse_times_Q; - Block22 Y; - ei_compute_inverse_size2(X, &Y); - result->template block<2,2>(2,2) = Y; - result->template block<2,2>(2,0) = - Y * R_times_P_inverse; - const Block22 Z = P_inverse_times_Q * Y; - result->template block<2,2>(0,2) = - Z; - result->template block<2,2>(0,0) = P_inverse + Z * R_times_P_inverse; - return true; - } - else - { - return false; - } + ei_compute_inverse::run(matrix.template block<2,2>(0,0), P_inverse); + const Block22 Q = matrix.template block<2,2>(0,2); + const Block22 P_inverse_times_Q = P_inverse * Q; + const XprBlock22 R = matrix.template block<2,2>(2,0); + const Block22 R_times_P_inverse = R * P_inverse; + const Block22 R_times_P_inverse_times_Q = R_times_P_inverse * Q; + const XprBlock22 S = matrix.template block<2,2>(2,2); + const Block22 X = S - R_times_P_inverse_times_Q; + Block22 Y; + ei_compute_inverse::run(X, Y); + result.template block<2,2>(2,2) = Y; + result.template block<2,2>(2,0) = - Y * R_times_P_inverse; + const Block22 Z = P_inverse_times_Q * Y; + result.template block<2,2>(0,2) = - Z; + result.template block<2,2>(0,0) = P_inverse + Z * R_times_P_inverse; } -template -bool ei_compute_inverse_size4_with_check(const XprType& matrix, MatrixType* result) -{ - if(ei_compute_inverse_size4_helper(matrix, result)) - { - // good ! The topleft 2x2 block was invertible, so the 2x2 blocks approach is successful. - return true; - } - else - { - // rare case: the topleft 2x2 block is not invertible (but the matrix itself is assumed to be). - // since this is a rare case, we don't need to optimize it. We just want to handle it with little - // additional code. - MatrixType m(matrix); - m.row(0).swap(m.row(2)); - m.row(1).swap(m.row(3)); - if(ei_compute_inverse_size4_helper(m, result)) - { - // good, the topleft 2x2 block of m is invertible. Since m is different from matrix in that some - // rows were permuted, the actual inverse of matrix is derived from the inverse of m by permuting - // the corresponding columns. - result->col(0).swap(result->col(2)); - result->col(1).swap(result->col(3)); - return true; - } - else - { - // first, undo the swaps previously made - m.row(0).swap(m.row(2)); - m.row(1).swap(m.row(3)); - // swap row 0 with the the row among 0 and 1 that has the biggest 2 first coeffs - int swap0with = ei_abs(m.coeff(0,0))+ei_abs(m.coeff(0,1))>ei_abs(m.coeff(1,0))+ei_abs(m.coeff(1,1)) ? 0 : 1; - m.row(0).swap(m.row(swap0with)); - // swap row 1 with the the row among 2 and 3 that has the biggest 2 first coeffs - int swap1with = ei_abs(m.coeff(2,0))+ei_abs(m.coeff(2,1))>ei_abs(m.coeff(3,0))+ei_abs(m.coeff(3,1)) ? 2 : 3; - m.row(1).swap(m.row(swap1with)); - if( ei_compute_inverse_size4_helper(m, result) ) - { - result->col(1).swap(result->col(swap1with)); - result->col(0).swap(result->col(swap0with)); - return true; - } - else - { - // non-invertible matrix - return false; - } - } - } -} - - - -/*********************************************** -*** Part 2 : selector and MatrixBase methods *** -***********************************************/ - -template -struct ei_compute_inverse -{ - static inline void run(const MatrixType& matrix, ResultType* result) - { - matrix.partialLu().computeInverse(result); - } -}; - -template -struct ei_compute_inverse -{ - static inline void run(const MatrixType& matrix, ResultType* result) - { - typedef typename MatrixType::Scalar Scalar; - result->coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); - } -}; - -template -struct ei_compute_inverse -{ - static inline void run(const MatrixType& matrix, ResultType* result) - { - ei_compute_inverse_size2(matrix, result); - } -}; - -template -struct ei_compute_inverse -{ - static inline void run(const MatrixType& matrix, ResultType* result) - { - ei_compute_inverse_size3(matrix, result); - } -}; - template struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, ResultType* result) + static inline void run(const MatrixType& _matrix, ResultType& result) { - ei_compute_inverse_size4_with_check(matrix, result); + typedef typename ResultType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + // we will do row permutations on the matrix. This copy should have negligible cost. + // if not, consider working in-place on the matrix (const-cast it, but then undo the permutations + // to nevertheless honor constness) + typename MatrixType::PlainMatrixType matrix(_matrix); + + // let's extract from the 2 first colums a 2x2 block whose determinant is as big as possible. + int good_row0, good_row1, good_i; + Matrix absdet; + + // any 2x2 block with determinant above this threshold will be considered good enough + RealScalar d = (matrix.col(0).squaredNorm()+matrix.col(1).squaredNorm()) * RealScalar(1e-2); + #define ei_inv_size4_helper_macro(i,row0,row1) \ + absdet[i] = ei_abs(matrix.coeff(row0,0)*matrix.coeff(row1,1) \ + - matrix.coeff(row0,1)*matrix.coeff(row1,0)); \ + if(absdet[i] > d) { good_row0=row0; good_row1=row1; goto good; } + ei_inv_size4_helper_macro(0,0,1) + ei_inv_size4_helper_macro(1,0,2) + ei_inv_size4_helper_macro(2,0,3) + ei_inv_size4_helper_macro(3,1,2) + ei_inv_size4_helper_macro(4,1,3) + ei_inv_size4_helper_macro(5,2,3) + + // no 2x2 block has determinant bigger than the threshold. So just take the one that + // has the biggest determinant + absdet.maxCoeff(&good_i); + good_row0 = good_i <= 2 ? 0 : good_i <= 4 ? 1 : 2; + good_row1 = good_i <= 2 ? good_i+1 : good_i <= 4 ? good_i-1 : 3; + + // now good_row0 and good_row1 are correctly set + good: + + // do row permutations to move this 2x2 block to the top + matrix.row(0).swap(matrix.row(good_row0)); + matrix.row(1).swap(matrix.row(good_row1)); + // now applying our helper function is numerically stable + ei_compute_inverse_size4_helper(matrix, result); + // Since we did row permutations on the original matrix, we need to do column permutations + // in the reverse order on the inverse + result.col(1).swap(result.col(good_row1)); + result.col(0).swap(result.col(good_row0)); } }; -/** \lu_module - * - * Computes the matrix inverse of this matrix. - * - * \note This matrix must be invertible, otherwise the result is undefined. If you need an invertibility check, use - * computeInverseWithCheck(). - * - * \param result Pointer to the matrix in which to store the result. - * - * Example: \include MatrixBase_computeInverse.cpp - * Output: \verbinclude MatrixBase_computeInverse.out - * - * \sa inverse(), computeInverseWithCheck() - */ -template -template -inline void MatrixBase::computeInverse(ResultType *result) const +template +struct ei_compute_inverse_and_det_with_check { - ei_assert(rows() == cols()); - EIGEN_STATIC_ASSERT(NumTraits::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) - ei_compute_inverse::run(eval(), result); -} + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + determinant = matrix.determinant(); + invertible = ei_abs(determinant) > absDeterminantThreshold; + if(invertible) ei_compute_inverse::run(matrix, inverse); + } +}; + +/************************* +*** MatrixBase methods *** +*************************/ + +template +struct ei_traits > +{ + typedef typename MatrixType::PlainMatrixType ReturnMatrixType; +}; + +template +struct ei_inverse_impl : public ReturnByValue > +{ + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost and limits code size. + typedef typename ei_meta_if< + MatrixType::RowsAtCompileTime == 2, + typename ei_nested::type, + typename ei_eval::type + >::ret MatrixTypeNested; + typedef typename ei_cleantype::type MatrixTypeNestedCleaned; + const MatrixTypeNested m_matrix; + + ei_inverse_impl(const MatrixType& matrix) + : m_matrix(matrix) + {} + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + + template inline void evalTo(Dest& dst) const + { + ei_compute_inverse::run(m_matrix, dst); + } +}; /** \lu_module * * \returns the matrix inverse of this matrix. * - * \note This matrix must be invertible, otherwise the result is undefined. If you need an invertibility check, use - * computeInverseWithCheck(). + * For small fixed sizes up to 4x4, this method uses ad-hoc methods (cofactors up to 3x3, Euler's trick for 4x4). + * In the general case, this method uses class PartialPivLU. * - * \note This method returns a matrix by value, which can be inefficient. To avoid that overhead, - * use computeInverse() instead. + * \note This matrix must be invertible, otherwise the result is undefined. If you need an + * invertibility check, do the following: + * \li for fixed sizes up to 4x4, use computeInverseAndDetWithCheck(). + * \li for the general case, use class FullPivLU. * * Example: \include MatrixBase_inverse.cpp * Output: \verbinclude MatrixBase_inverse.out * - * \sa computeInverse(), computeInverseWithCheck() + * \sa computeInverseAndDetWithCheck() */ template -inline const typename MatrixBase::PlainMatrixType MatrixBase::inverse() const +inline const ei_inverse_impl MatrixBase::inverse() const { - PlainMatrixType result(rows(), cols()); - computeInverse(&result); - return result; + EIGEN_STATIC_ASSERT(NumTraits::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) + ei_assert(rows() == cols()); + return ei_inverse_impl(derived()); } - -/******************************************** - * Compute inverse with invertibility check * - *******************************************/ - -template -struct ei_compute_inverse_with_check +/** \lu_module + * + * Computation of matrix inverse and determinant, with invertibility check. + * + * This is only for fixed-size square matrices of size up to 4x4. + * + * \param inverse Reference to the matrix in which to store the inverse. + * \param determinant Reference to the variable in which to store the inverse. + * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. + * \param absDeterminantThreshold Optional parameter controlling the invertibility check. + * The matrix will be declared invertible if the absolute value of its + * determinant is greater than this threshold. + * + * Example: \include MatrixBase_computeInverseAndDetWithCheck.cpp + * Output: \verbinclude MatrixBase_computeInverseAndDetWithCheck.out + * + * \sa inverse(), computeInverseWithCheck() + */ +template +template +inline void MatrixBase::computeInverseAndDetWithCheck( + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible, + const RealScalar& absDeterminantThreshold + ) const { - static inline bool run(const MatrixType& matrix, ResultType* result) - { - typedef typename MatrixType::Scalar Scalar; - LU lu( matrix ); - if( !lu.isInvertible() ) return false; - lu.computeInverse(result); - return true; - } -}; - -template -struct ei_compute_inverse_with_check -{ - static inline bool run(const MatrixType& matrix, ResultType* result) - { - typedef typename MatrixType::Scalar Scalar; - if( matrix.coeff(0,0) == Scalar(0) ) return false; - result->coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); - return true; - } -}; - -template -struct ei_compute_inverse_with_check -{ - static inline bool run(const MatrixType& matrix, ResultType* result) - { - return ei_compute_inverse_size2_with_check(matrix, result); - } -}; - -template -struct ei_compute_inverse_with_check -{ - static inline bool run(const MatrixType& matrix, ResultType* result) - { - return ei_compute_inverse_size3(matrix, result); - } -}; - -template -struct ei_compute_inverse_with_check -{ - static inline bool run(const MatrixType& matrix, ResultType* result) - { - return ei_compute_inverse_size4_with_check(matrix, result); - } -}; + // i'd love to put some static assertions there, but SFINAE means that they have no effect... + ei_assert(rows() == cols()); + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost and limits code size. + typedef typename ei_meta_if< + RowsAtCompileTime == 2, + typename ei_cleantype::type>::type, + PlainMatrixType + >::ret MatrixType; + ei_compute_inverse_and_det_with_check::run + (derived(), absDeterminantThreshold, inverse, determinant, invertible); +} /** \lu_module * * Computation of matrix inverse, with invertibility check. * - * \returns true if the matrix is invertible, false otherwise. + * This is only for fixed-size square matrices of size up to 4x4. * - * \param result Pointer to the matrix in which to store the result. + * \param inverse Reference to the matrix in which to store the inverse. + * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. + * \param absDeterminantThreshold Optional parameter controlling the invertibility check. + * The matrix will be declared invertible if the absolute value of its + * determinant is greater than this threshold. * - * \sa inverse(), computeInverse() + * Example: \include MatrixBase_computeInverseWithCheck.cpp + * Output: \verbinclude MatrixBase_computeInverseWithCheck.out + * + * \sa inverse(), computeInverseAndDetWithCheck() */ template template -inline bool MatrixBase::computeInverseWithCheck(ResultType *result) const +inline void MatrixBase::computeInverseWithCheck( + ResultType& inverse, + bool& invertible, + const RealScalar& absDeterminantThreshold + ) const { + RealScalar determinant; + // i'd love to put some static assertions there, but SFINAE means that they have no effect... ei_assert(rows() == cols()); - EIGEN_STATIC_ASSERT(NumTraits::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) - return ei_compute_inverse_with_check::run(eval(), result); + computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold); } - #endif // EIGEN_INVERSE_H diff --git a/Eigen/src/LU/LU.h b/Eigen/src/LU/LU.h deleted file mode 100644 index e848b5454..000000000 --- a/Eigen/src/LU/LU.h +++ /dev/null @@ -1,607 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 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_LU_H -#define EIGEN_LU_H - -/** \ingroup LU_Module - * - * \class LU - * - * \brief LU decomposition of a matrix with complete pivoting, and related features - * - * \param MatrixType the type of the matrix of which we are computing the LU decomposition - * - * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A - * is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q - * are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues (diagonal - * coefficients) of U are sorted in such a way that any zeros are at the end, so that the rank - * of A is the index of the first zero on the diagonal of U (with indices starting at 0) if any. - * - * This decomposition provides the generic approach to solving systems of linear equations, computing - * the rank, invertibility, inverse, kernel, and determinant. - * - * This LU decomposition is very stable and well tested with large matrices. However there are use cases where the SVD - * decomposition is inherently more stable and/or flexible. For example, when computing the kernel of a matrix, - * working with the SVD allows to select the smallest singular values of the matrix, something that - * the LU decomposition doesn't see. - * - * The data of the LU decomposition can be directly accessed through the methods matrixLU(), - * permutationP(), permutationQ(). - * - * As an exemple, here is how the original matrix can be retrieved: - * \include class_LU.cpp - * Output: \verbinclude class_LU.out - * - * \sa MatrixBase::lu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse() - */ -template class LU -{ - public: - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix IntRowVectorType; - typedef Matrix IntColVectorType; - typedef Matrix RowVectorType; - typedef Matrix ColVectorType; - - enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( - MatrixType::MaxColsAtCompileTime, - MatrixType::MaxRowsAtCompileTime) - }; - - typedef Matrix KernelResultType; - - typedef Matrix ImageResultType; - - /** - * \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via LU::compute(const MatrixType&). - */ - LU(); - - /** Constructor. - * - * \param matrix the matrix of which to compute the LU decomposition. - * It is required to be nonzero. - */ - LU(const MatrixType& matrix); - - /** Computes the LU decomposition of the given matrix. - * - * \param matrix the matrix of which to compute the LU decomposition. - * It is required to be nonzero. - * - * \returns a reference to *this - */ - LU& compute(const MatrixType& matrix); - - /** \returns the LU decomposition matrix: the upper-triangular part is U, the - * unit-lower-triangular part is L (at least for square matrices; in the non-square - * case, special care is needed, see the documentation of class LU). - * - * \sa matrixL(), matrixU() - */ - inline const MatrixType& matrixLU() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_lu; - } - - /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, - * representing the P permutation i.e. the permutation of the rows. For its precise meaning, - * see the examples given in the documentation of class LU. - * - * \sa permutationQ() - */ - inline const IntColVectorType& permutationP() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_p; - } - - /** \returns a vector of integers, whose size is the number of columns of the matrix being - * decomposed, representing the Q permutation i.e. the permutation of the columns. - * For its precise meaning, see the examples given in the documentation of class LU. - * - * \sa permutationP() - */ - inline const IntRowVectorType& permutationQ() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_q; - } - - /** Computes a basis of the kernel of the matrix, also called the null-space of the matrix. - * - * \note This method is only allowed on non-invertible matrices, as determined by - * isInvertible(). Calling it on an invertible matrix will make an assertion fail. - * - * \param result a pointer to the matrix in which to store the kernel. The columns of this - * matrix will be set to form a basis of the kernel (it will be resized - * if necessary). - * - * Example: \include LU_computeKernel.cpp - * Output: \verbinclude LU_computeKernel.out - * - * \sa kernel(), computeImage(), image() - */ - template - void computeKernel(KernelMatrixType *result) const; - - /** Computes a basis of the image of the matrix, also called the column-space or range of he matrix. - * - * \note Calling this method on the zero matrix will make an assertion fail. - * - * \param result a pointer to the matrix in which to store the image. The columns of this - * matrix will be set to form a basis of the image (it will be resized - * if necessary). - * - * Example: \include LU_computeImage.cpp - * Output: \verbinclude LU_computeImage.out - * - * \sa image(), computeKernel(), kernel() - */ - template - void computeImage(ImageMatrixType *result) const; - - /** \returns the kernel of the matrix, also called its null-space. The columns of the returned matrix - * will form a basis of the kernel. - * - * \note: this method is only allowed on non-invertible matrices, as determined by - * isInvertible(). Calling it on an invertible matrix will make an assertion fail. - * - * \note: this method returns a matrix by value, which induces some inefficiency. - * If you prefer to avoid this overhead, use computeKernel() instead. - * - * Example: \include LU_kernel.cpp - * Output: \verbinclude LU_kernel.out - * - * \sa computeKernel(), image() - */ - const KernelResultType kernel() const; - - /** \returns the image of the matrix, also called its column-space. The columns of the returned matrix - * will form a basis of the kernel. - * - * \note: Calling this method on the zero matrix will make an assertion fail. - * - * \note: this method returns a matrix by value, which induces some inefficiency. - * If you prefer to avoid this overhead, use computeImage() instead. - * - * Example: \include LU_image.cpp - * Output: \verbinclude LU_image.out - * - * \sa computeImage(), kernel() - */ - const ImageResultType image() const; - - /** This method finds a solution x to the equation Ax=b, where A is the matrix of which - * *this is the LU decomposition, if any exists. - * - * \param b the right-hand-side of the equation to solve. Can be a vector or a matrix, - * the only requirement in order for the equation to make sense is that - * b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition. - * \param result a pointer to the vector or matrix in which to store the solution, if any exists. - * Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols(). - * If no solution exists, *result is left with undefined coefficients. - * - * \returns true if any solution exists, false if no solution exists. - * - * \note If there exist more than one solution, this method will arbitrarily choose one. - * If you need a complete analysis of the space of solutions, take the one solution obtained - * by this method and add to it elements of the kernel, as determined by kernel(). - * - * Example: \include LU_solve.cpp - * Output: \verbinclude LU_solve.out - * - * \sa TriangularView::solve(), kernel(), computeKernel(), inverse(), computeInverse() - */ - template - bool solve(const MatrixBase& b, ResultType *result) const; - - /** \returns the determinant of the matrix of which - * *this is the LU decomposition. It has only linear complexity - * (that is, O(n) where n is the dimension of the square matrix) - * as the LU decomposition has already been computed. - * - * \note This is only for square matrices. - * - * \note For fixed-size matrices of size up to 4, MatrixBase::determinant() offers - * optimized paths. - * - * \warning a determinant can be very big or small, so for matrices - * of large enough dimension, there is a risk of overflow/underflow. - * - * \sa MatrixBase::determinant() - */ - typename ei_traits::Scalar determinant() const; - - /** \returns the rank of the matrix of which *this is the LU decomposition. - * - * \note This is computed at the time of the construction of the LU decomposition. This - * method does not perform any further computation. - */ - inline int rank() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_rank; - } - - /** \returns the dimension of the kernel of the matrix of which *this is the LU decomposition. - * - * \note Since the rank is computed at the time of the construction of the LU decomposition, this - * method almost does not perform any further computation. - */ - inline int dimensionOfKernel() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_lu.cols() - m_rank; - } - - /** \returns true if the matrix of which *this is the LU decomposition represents an injective - * linear map, i.e. has trivial kernel; false otherwise. - * - * \note Since the rank is computed at the time of the construction of the LU decomposition, this - * method almost does not perform any further computation. - */ - inline bool isInjective() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_rank == m_lu.cols(); - } - - /** \returns true if the matrix of which *this is the LU decomposition represents a surjective - * linear map; false otherwise. - * - * \note Since the rank is computed at the time of the construction of the LU decomposition, this - * method almost does not perform any further computation. - */ - inline bool isSurjective() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return m_rank == m_lu.rows(); - } - - /** \returns true if the matrix of which *this is the LU decomposition is invertible. - * - * \note Since the rank is computed at the time of the construction of the LU decomposition, this - * method almost does not perform any further computation. - */ - inline bool isInvertible() const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - return isInjective() && isSurjective(); - } - - /** Computes the inverse of the matrix of which *this is the LU decomposition. - * - * \param result a pointer to the matrix into which to store the inverse. Resized if needed. - * - * \note If this matrix is not invertible, *result is left with undefined coefficients. - * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa MatrixBase::computeInverse(), inverse() - */ - inline void computeInverse(MatrixType *result) const - { - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - ei_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); - solve(MatrixType::Identity(m_lu.rows(), m_lu.cols()), result); - } - - /** \returns the inverse of the matrix of which *this is the LU decomposition. - * - * \note If this matrix is not invertible, the returned matrix has undefined coefficients. - * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa computeInverse(), MatrixBase::inverse() - */ - inline MatrixType inverse() const - { - MatrixType result; - computeInverse(&result); - return result; - } - - protected: - const MatrixType* m_originalMatrix; - MatrixType m_lu; - IntColVectorType m_p; - IntRowVectorType m_q; - int m_det_pq; - int m_rank; - RealScalar m_precision; -}; - -template -LU::LU() - : m_originalMatrix(0), - m_lu(), - m_p(), - m_q(), - m_det_pq(0), - m_rank(-1), - m_precision(precision()) -{ -} - -template -LU::LU(const MatrixType& matrix) - : m_originalMatrix(0), - m_lu(), - m_p(), - m_q(), - m_det_pq(0), - m_rank(-1), - m_precision(precision()) -{ - compute(matrix); -} - -template -LU& LU::compute(const MatrixType& matrix) -{ - m_originalMatrix = &matrix; - m_lu = matrix; - m_p.resize(matrix.rows()); - m_q.resize(matrix.cols()); - - const int size = matrix.diagonalSize(); - const int rows = matrix.rows(); - const int cols = matrix.cols(); - - // this formula comes from experimenting (see "LU precision tuning" thread on the list) - // and turns out to be identical to Higham's formula used already in LDLt. - m_precision = epsilon() * size; - - IntColVectorType rows_transpositions(matrix.rows()); - IntRowVectorType cols_transpositions(matrix.cols()); - int number_of_transpositions = 0; - - RealScalar biggest = RealScalar(0); - m_rank = size; - for(int k = 0; k < size; ++k) - { - int row_of_biggest_in_corner, col_of_biggest_in_corner; - RealScalar biggest_in_corner; - - biggest_in_corner = m_lu.corner(Eigen::BottomRight, rows-k, cols-k) - .cwise().abs() - .maxCoeff(&row_of_biggest_in_corner, &col_of_biggest_in_corner); - row_of_biggest_in_corner += k; - col_of_biggest_in_corner += k; - if(k==0) biggest = biggest_in_corner; - - // if the corner is negligible, then we have less than full rank, and we can finish early - if(ei_isMuchSmallerThan(biggest_in_corner, biggest, m_precision)) - { - m_rank = k; - for(int i = k; i < size; i++) - { - rows_transpositions.coeffRef(i) = i; - cols_transpositions.coeffRef(i) = i; - } - break; - } - - rows_transpositions.coeffRef(k) = row_of_biggest_in_corner; - cols_transpositions.coeffRef(k) = col_of_biggest_in_corner; - if(k != row_of_biggest_in_corner) { - m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner)); - ++number_of_transpositions; - } - if(k != col_of_biggest_in_corner) { - m_lu.col(k).swap(m_lu.col(col_of_biggest_in_corner)); - ++number_of_transpositions; - } - if(k= 0; --k) - std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k))); - - for(int k = 0; k < matrix.cols(); ++k) m_q.coeffRef(k) = k; - for(int k = 0; k < size; ++k) - std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k))); - - m_det_pq = (number_of_transpositions%2) ? -1 : 1; - return *this; -} - -template -typename ei_traits::Scalar LU::determinant() const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - ei_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); - return Scalar(m_det_pq) * m_lu.diagonal().prod(); -} - -template -template -void LU::computeKernel(KernelMatrixType *result) const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - const int dimker = dimensionOfKernel(), cols = m_lu.cols(); - result->resize(cols, dimker); - - /* Let us use the following lemma: - * - * Lemma: If the matrix A has the LU decomposition PAQ = LU, - * then Ker A = Q(Ker U). - * - * Proof: trivial: just keep in mind that P, Q, L are invertible. - */ - - /* Thus, all we need to do is to compute Ker U, and then apply Q. - * - * U is upper triangular, with eigenvalues sorted so that any zeros appear at the end. - * Thus, the diagonal of U ends with exactly - * m_dimKer zero's. Let us use that to construct m_dimKer linearly - * independent vectors in Ker U. - */ - - Matrix - y(-m_lu.corner(TopRight, m_rank, dimker)); - - m_lu.corner(TopLeft, m_rank, m_rank) - .template triangularView().solveInPlace(y); - - for(int i = 0; i < m_rank; ++i) result->row(m_q.coeff(i)) = y.row(i); - for(int i = m_rank; i < cols; ++i) result->row(m_q.coeff(i)).setZero(); - for(int k = 0; k < dimker; ++k) result->coeffRef(m_q.coeff(m_rank+k), k) = Scalar(1); -} - -template -const typename LU::KernelResultType -LU::kernel() const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - KernelResultType result(m_lu.cols(), dimensionOfKernel()); - computeKernel(&result); - return result; -} - -template -template -void LU::computeImage(ImageMatrixType *result) const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - result->resize(m_originalMatrix->rows(), m_rank); - for(int i = 0; i < m_rank; ++i) - result->col(i) = m_originalMatrix->col(m_q.coeff(i)); -} - -template -const typename LU::ImageResultType -LU::image() const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - ImageResultType result(m_originalMatrix->rows(), m_rank); - computeImage(&result); - return result; -} - -template -template -bool LU::solve( - const MatrixBase& b, - ResultType *result -) const -{ - ei_assert(m_originalMatrix != 0 && "LU is not initialized."); - result->resize(m_lu.cols(), b.cols()); - if(m_rank==0) - { - if(b.squaredNorm() == RealScalar(0)) - { - result->setZero(); - return true; - } - else return false; - } - - /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. - * So we proceed as follows: - * Step 1: compute c = Pb. - * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible. - * Step 3: replace c by the solution x to Ux = c. Check if a solution really exists. - * Step 4: result = Qc; - */ - - const int rows = m_lu.rows(), cols = m_lu.cols(); - ei_assert(b.rows() == rows); - const int smalldim = std::min(rows, cols); - - typename OtherDerived::PlainMatrixType c(b.rows(), b.cols()); - - // Step 1 - for(int i = 0; i < rows; ++i) c.row(m_p.coeff(i)) = b.row(i); - - // Step 2 - m_lu.corner(Eigen::TopLeft,smalldim,smalldim) - .template triangularView() - .solveInPlace(c.corner(Eigen::TopLeft, smalldim, c.cols())); - if(rows>cols) - { - c.corner(Eigen::BottomLeft, rows-cols, c.cols()) - -= m_lu.corner(Eigen::BottomLeft, rows-cols, cols) * c.corner(Eigen::TopLeft, cols, c.cols()); - } - - // Step 3 - if(!isSurjective()) - { - // is c is in the image of U ? - RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff(); - RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-m_rank, c.cols()).cwise().abs().maxCoeff(); - if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision)) - return false; - } - m_lu.corner(TopLeft, m_rank, m_rank) - .template triangularView() - .solveInPlace(c.corner(TopLeft, m_rank, c.cols())); - - // Step 4 - for(int i = 0; i < m_rank; ++i) result->row(m_q.coeff(i)) = c.row(i); - for(int i = m_rank; i < m_lu.cols(); ++i) result->row(m_q.coeff(i)).setZero(); - return true; -} - -/** \lu_module - * - * \return the LU decomposition of \c *this. - * - * \sa class LU - */ -template -inline const LU::PlainMatrixType> -MatrixBase::lu() const -{ - return LU(eval()); -} - -#endif // EIGEN_LU_H diff --git a/Eigen/src/LU/PartialLU.h b/Eigen/src/LU/PartialPivLU.h similarity index 61% rename from Eigen/src/LU/PartialLU.h rename to Eigen/src/LU/PartialPivLU.h index e467c62f0..03c91456a 100644 --- a/Eigen/src/LU/PartialLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -28,7 +28,7 @@ /** \ingroup LU_Module * - * \class PartialLU + * \class PartialPivLU * * \brief LU decomposition of a matrix with partial pivoting, and related features * @@ -38,27 +38,30 @@ * is decomposed as A = PLU where L is unit-lower-triangular, U is upper-triangular, and P * is a permutation matrix. * - * Typically, partial pivoting LU decomposition is only considered numerically stable for square invertible matrices. - * So in this class, we plainly require that and take advantage of that to do some simplifications and optimizations. - * This class will assert that the matrix is square, but it won't (actually it can't) check that the matrix is invertible: - * it is your task to check that you only use this decomposition on invertible matrices. + * Typically, partial pivoting LU decomposition is only considered numerically stable for square invertible + * matrices. Thus LAPACK's dgesv and dgesvx require the matrix to be square and invertible. The present class + * does the same. It will assert that the matrix is square, but it won't (actually it can't) check that the + * matrix is invertible: it is your task to check that you only use this decomposition on invertible matrices. * - * The guaranteed safe alternative, working for all matrices, is the full pivoting LU decomposition, provided by class LU. + * The guaranteed safe alternative, working for all matrices, is the full pivoting LU decomposition, provided + * by class FullPivLU. * * This is \b not a rank-revealing LU decomposition. Many features are intentionally absent from this class, - * such as rank computation. If you need these features, use class LU. + * such as rank computation. If you need these features, use class FullPivLU. * - * This LU decomposition is suitable to invert invertible matrices. It is what MatrixBase::inverse() uses. On the other hand, - * it is \b not suitable to determine whether a given matrix is invertible. + * This LU decomposition is suitable to invert invertible matrices. It is what MatrixBase::inverse() uses + * in the general case. + * On the other hand, it is \b not suitable to determine whether a given matrix is invertible. * * The data of the LU decomposition can be directly accessed through the methods matrixLU(), permutationP(). * - * \sa MatrixBase::partialLu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse(), class LU + * \sa MatrixBase::partialPivLu(), MatrixBase::determinant(), MatrixBase::inverse(), MatrixBase::computeInverse(), class FullPivLU */ -template class PartialLU +template class PartialPivLU { public: + typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix IntRowVectorType; @@ -75,63 +78,81 @@ template class PartialLU * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via PartialLU::compute(const MatrixType&). + * perform decompositions via PartialPivLU::compute(const MatrixType&). */ - PartialLU(); + PartialPivLU(); /** Constructor. * * \param matrix the matrix of which to compute the LU decomposition. * * \warning The matrix should have full rank (e.g. if it's square, it should be invertible). - * If you need to deal with non-full rank, use class LU instead. + * If you need to deal with non-full rank, use class FullPivLU instead. */ - PartialLU(const MatrixType& matrix); + PartialPivLU(const MatrixType& matrix); - PartialLU& compute(const MatrixType& matrix); + PartialPivLU& compute(const MatrixType& matrix); /** \returns the LU decomposition matrix: the upper-triangular part is U, the * unit-lower-triangular part is L (at least for square matrices; in the non-square - * case, special care is needed, see the documentation of class LU). + * case, special care is needed, see the documentation of class FullPivLU). * * \sa matrixL(), matrixU() */ inline const MatrixType& matrixLU() const { - ei_assert(m_isInitialized && "PartialLU is not initialized."); + ei_assert(m_isInitialized && "PartialPivLU is not initialized."); return m_lu; } /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, * representing the P permutation i.e. the permutation of the rows. For its precise meaning, - * see the examples given in the documentation of class LU. + * see the examples given in the documentation of class FullPivLU. */ inline const IntColVectorType& permutationP() const { - ei_assert(m_isInitialized && "PartialLU is not initialized."); + ei_assert(m_isInitialized && "PartialPivLU is not initialized."); return m_p; } - /** This method finds the solution x to the equation Ax=b, where A is the matrix of which - * *this is the LU decomposition. Since if this partial pivoting decomposition the matrix is assumed - * to have full rank, such a solution is assumed to exist and to be unique. - * - * \warning Again, if your matrix may not have full rank, use class LU instead. See LU::solve(). + /** This method returns the solution x to the equation Ax=b, where A is the matrix of which + * *this is the LU decomposition. * * \param b the right-hand-side of the equation to solve. Can be a vector or a matrix, * the only requirement in order for the equation to make sense is that * b.rows()==A.rows(), where A is the matrix of which *this is the LU decomposition. - * \param result a pointer to the vector or matrix in which to store the solution, if any exists. - * Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols(). - * If no solution exists, *result is left with undefined coefficients. * - * Example: \include PartialLU_solve.cpp - * Output: \verbinclude PartialLU_solve.out + * \returns the solution. + * + * Example: \include PartialPivLU_solve.cpp + * Output: \verbinclude PartialPivLU_solve.out + * + * Since this PartialPivLU class assumes anyway that the matrix A is invertible, the solution + * theoretically exists and is unique regardless of b. * * \sa TriangularView::solve(), inverse(), computeInverse() */ - template - void solve(const MatrixBase& b, ResultType *result) const; + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "PartialPivLU is not initialized."); + return ei_solve_retval(*this, b.derived()); + } + + /** \returns the inverse of the matrix of which *this is the LU decomposition. + * + * \warning The matrix being decomposed here is assumed to be invertible. If you need to check for + * invertibility, use class FullPivLU instead. + * + * \sa MatrixBase::inverse(), LU::inverse() + */ + inline const ei_solve_retval > inverse() const + { + ei_assert(m_isInitialized && "PartialPivLU is not initialized."); + return ei_solve_retval > + (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols()).nestByValue()); + } /** \returns the determinant of the matrix of which * *this is the LU decomposition. It has only linear complexity @@ -148,33 +169,8 @@ template class PartialLU */ typename ei_traits::Scalar determinant() const; - /** Computes the inverse of the matrix of which *this is the LU decomposition. - * - * \param result a pointer to the matrix into which to store the inverse. Resized if needed. - * - * \warning The matrix being decomposed here is assumed to be invertible. If you need to check for - * invertibility, use class LU instead. - * - * \sa MatrixBase::computeInverse(), inverse() - */ - inline void computeInverse(MatrixType *result) const - { - solve(MatrixType::Identity(m_lu.rows(), m_lu.cols()), result); - } - - /** \returns the inverse of the matrix of which *this is the LU decomposition. - * - * \warning The matrix being decomposed here is assumed to be invertible. If you need to check for - * invertibility, use class LU instead. - * - * \sa computeInverse(), MatrixBase::inverse() - */ - inline MatrixType inverse() const - { - MatrixType result; - computeInverse(&result); - return result; - } + inline int rows() const { return m_lu.rows(); } + inline int cols() const { return m_lu.cols(); } protected: MatrixType m_lu; @@ -184,7 +180,7 @@ template class PartialLU }; template -PartialLU::PartialLU() +PartialPivLU::PartialPivLU() : m_lu(), m_p(), m_det_p(0), @@ -193,7 +189,7 @@ PartialLU::PartialLU() } template -PartialLU::PartialLU(const MatrixType& matrix) +PartialPivLU::PartialPivLU(const MatrixType& matrix) : m_lu(), m_p(), m_det_p(0), @@ -202,9 +198,7 @@ PartialLU::PartialLU(const MatrixType& matrix) compute(matrix); } - - -/** This is the blocked version of ei_lu_unblocked() */ +/** This is the blocked version of ei_fullpivlu_unblocked() */ template struct ei_partial_lu_impl { @@ -216,6 +210,7 @@ struct ei_partial_lu_impl typedef Map > MapLU; typedef Block MatrixType; typedef Block BlockType; + typedef typename MatrixType::RealScalar RealScalar; /** \internal performs the LU decomposition in-place of the matrix \a lu * using an unblocked algorithm. @@ -224,8 +219,12 @@ struct ei_partial_lu_impl * vector \a row_transpositions which must have a size equal to the number * of columns of the matrix \a lu, and an integer \a nb_transpositions * which returns the actual number of transpositions. + * + * \returns false if some pivot is exactly zero, in which case the matrix is left with + * undefined coefficients (to avoid generating inf/nan values). Returns true + * otherwise. */ - static void unblocked_lu(MatrixType& lu, int* row_transpositions, int& nb_transpositions) + static bool unblocked_lu(MatrixType& lu, int* row_transpositions, int& nb_transpositions) { const int rows = lu.rows(); const int size = std::min(lu.rows(),lu.cols()); @@ -233,9 +232,22 @@ struct ei_partial_lu_impl for(int k = 0; k < size; ++k) { int row_of_biggest_in_col; - lu.col(k).end(rows-k).cwise().abs().maxCoeff(&row_of_biggest_in_col); + RealScalar biggest_in_corner + = lu.col(k).end(rows-k).cwise().abs().maxCoeff(&row_of_biggest_in_col); row_of_biggest_in_col += k; + if(biggest_in_corner == 0) // the pivot is exactly zero: the matrix is singular + { + // end quickly, avoid generating inf/nan values. Although in this unblocked_lu case + // the result is still valid, there's no need to boast about it because + // the blocked_lu code can't guarantee the same. + // before exiting, make sure to initialize the still uninitialized row_transpositions + // in a sane state without destroying what we already have. + for(int i = k; i < size; i++) + row_transpositions[i] = i; + return false; + } + row_transpositions[k] = row_of_biggest_in_col; if(k != row_of_biggest_in_col) @@ -252,6 +264,7 @@ struct ei_partial_lu_impl lu.corner(BottomRight,rrows,rsize).noalias() -= lu.col(k).end(rrows) * lu.row(k).end(rsize); } } + return true; } /** \internal performs the LU decomposition in-place of the matrix represented @@ -263,11 +276,15 @@ struct ei_partial_lu_impl * of columns of the matrix \a lu, and an integer \a nb_transpositions * which returns the actual number of transpositions. * + * \returns false if some pivot is exactly zero, in which case the matrix is left with + * undefined coefficients (to avoid generating inf/nan values). Returns true + * otherwise. + * * \note This very low level interface using pointers, etc. is to: * 1 - reduce the number of instanciations to the strict minimum * 2 - avoid infinite recursion of the instanciations with Block > > */ - static void blocked_lu(int rows, int cols, Scalar* lu_data, int luStride, int* row_transpositions, int& nb_transpositions, int maxBlockSize=256) + static bool blocked_lu(int rows, int cols, Scalar* lu_data, int luStride, int* row_transpositions, int& nb_transpositions, int maxBlockSize=256) { MapLU lu1(lu_data,StorageOrder==RowMajor?rows:luStride,StorageOrder==RowMajor?luStride:cols); MatrixType lu(lu1,0,0,rows,cols); @@ -277,8 +294,7 @@ struct ei_partial_lu_impl // if the matrix is too small, no blocking: if(size<=16) { - unblocked_lu(lu, row_transpositions, nb_transpositions); - return; + return unblocked_lu(lu, row_transpositions, nb_transpositions); } // automatically adjust the number of subdivisions to the size @@ -311,12 +327,20 @@ struct ei_partial_lu_impl int nb_transpositions_in_panel; // recursively calls the blocked LU algorithm with a very small // blocking size: - blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride, - row_transpositions+k, nb_transpositions_in_panel, 16); + if(!blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride, + row_transpositions+k, nb_transpositions_in_panel, 16)) + { + // end quickly with undefined coefficients, just avoid generating inf/nan values. + // before exiting, make sure to initialize the still uninitialized row_transpositions + // in a sane state without destroying what we already have. + for(int i=k; i -PartialLU& PartialLU::compute(const MatrixType& matrix) +PartialPivLU& PartialPivLU::compute(const MatrixType& matrix) { m_lu = matrix; m_p.resize(matrix.rows()); - ei_assert(matrix.rows() == matrix.cols() && "PartialLU is only for square (and moreover invertible) matrices"); + ei_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices"); const int size = matrix.rows(); IntColVectorType rows_transpositions(size); @@ -374,54 +399,73 @@ PartialLU& PartialLU::compute(const MatrixType& matrix) } template -typename ei_traits::Scalar PartialLU::determinant() const +typename ei_traits::Scalar PartialPivLU::determinant() const { - ei_assert(m_isInitialized && "PartialLU is not initialized."); + ei_assert(m_isInitialized && "PartialPivLU is not initialized."); return Scalar(m_det_p) * m_lu.diagonal().prod(); } -template -template -void PartialLU::solve( - const MatrixBase& b, - ResultType *result -) const +/***** Implementation of solve() *****************************************************/ + +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "PartialLU is not initialized."); + EIGEN_MAKE_SOLVE_HELPERS(PartialPivLU<_MatrixType>,Rhs) + + template void evalTo(Dest& dst) const + { + /* The decomposition PA = LU can be rewritten as A = P^{-1} L U. + * So we proceed as follows: + * Step 1: compute c = Pb. + * Step 2: replace c by the solution x to Lx = c. + * Step 3: replace c by the solution x to Ux = c. + */ + + const int size = dec().matrixLU().rows(); + ei_assert(rhs().rows() == size); - /* The decomposition PA = LU can be rewritten as A = P^{-1} L U. - * So we proceed as follows: - * Step 1: compute c = Pb. - * Step 2: replace c by the solution x to Lx = c. - * Step 3: replace c by the solution x to Ux = c. - */ + dst.resize(size, rhs().cols()); - const int size = m_lu.rows(); - ei_assert(b.rows() == size); + // Step 1 + for(int i = 0; i < size; ++i) dst.row(dec().permutationP().coeff(i)) = rhs().row(i); - result->resize(size, b.cols()); + // Step 2 + dec().matrixLU().template triangularView().solveInPlace(dst); - // Step 1 - for(int i = 0; i < size; ++i) result->row(m_p.coeff(i)) = b.row(i); + // Step 3 + dec().matrixLU().template triangularView().solveInPlace(dst); + } +}; - // Step 2 - m_lu.template triangularView().solveInPlace(*result); +/******** MatrixBase methods *******/ - // Step 3 - m_lu.template triangularView().solveInPlace(*result); +/** \lu_module + * + * \return the partial-pivoting LU decomposition of \c *this. + * + * \sa class PartialPivLU + */ +template +inline const PartialPivLU::PlainMatrixType> +MatrixBase::partialPivLu() const +{ + return PartialPivLU(eval()); } /** \lu_module * - * \return the LU decomposition of \c *this. + * Synonym of partialPivLu(). * - * \sa class LU + * \return the partial-pivoting LU decomposition of \c *this. + * + * \sa class PartialPivLU */ template -inline const PartialLU::PlainMatrixType> -MatrixBase::partialLu() const +inline const PartialPivLU::PlainMatrixType> +MatrixBase::lu() const { - return PartialLU(eval()); + return PartialPivLU(eval()); } #endif // EIGEN_PARTIALLU_H diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h similarity index 67% rename from Eigen/src/QR/ColPivotingHouseholderQR.h rename to Eigen/src/QR/ColPivHouseholderQR.h index b141da0aa..d6be9a506 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -29,7 +29,7 @@ /** \ingroup QR_Module * \nonstableyet * - * \class ColPivotingHouseholderQR + * \class ColPivHouseholderQR * * \brief Householder rank-revealing QR decomposition of a matrix with column-pivoting * @@ -38,21 +38,21 @@ * This class performs a rank-revealing QR decomposition using Householder transformations. * * This decomposition performs column pivoting in order to be rank-revealing and improve - * numerical stability. It is slower than HouseholderQR, and faster than FullPivotingHouseholderQR. + * numerical stability. It is slower than HouseholderQR, and faster than FullPivHouseholderQR. * - * \sa MatrixBase::colPivotingHouseholderQr() + * \sa MatrixBase::colPivHouseholderQr() */ -template class ColPivotingHouseholderQR +template class ColPivHouseholderQR { public: + typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; @@ -68,11 +68,11 @@ template class ColPivotingHouseholderQR * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via ColPivotingHouseholderQR::compute(const MatrixType&). + * perform decompositions via ColPivHouseholderQR::compute(const MatrixType&). */ - ColPivotingHouseholderQR() : m_qr(), m_hCoeffs(), m_isInitialized(false) {} + ColPivHouseholderQR() : m_qr(), m_hCoeffs(), m_isInitialized(false) {} - ColPivotingHouseholderQR(const MatrixType& matrix) + ColPivHouseholderQR(const MatrixType& matrix) : m_qr(matrix.rows(), matrix.cols()), m_hCoeffs(std::min(matrix.rows(),matrix.cols())), m_isInitialized(false) @@ -83,22 +83,27 @@ template class ColPivotingHouseholderQR /** This method finds a solution x to the equation Ax=b, where A is the matrix of which * *this is the QR decomposition, if any exists. * - * \returns \c true if a solution exists, \c false if no solution exists. - * * \param b the right-hand-side of the equation to solve. * - * \param result a pointer to the vector/matrix in which to store the solution, if any exists. - * Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols(). - * If no solution exists, *result is left with undefined coefficients. + * \returns a solution. * * \note The case where b is a matrix is not yet implemented. Also, this * code is space inefficient. * - * Example: \include ColPivotingHouseholderQR_solve.cpp - * Output: \verbinclude ColPivotingHouseholderQR_solve.out + * \note_about_checking_solutions + * + * \note_about_arbitrary_choice_of_solution + * + * Example: \include ColPivHouseholderQR_solve.cpp + * Output: \verbinclude ColPivHouseholderQR_solve.out */ - template - bool solve(const MatrixBase& b, ResultType *result) const; + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + return ei_solve_retval(*this, b.derived()); + } HouseholderSequenceType matrixQ(void) const; @@ -106,15 +111,15 @@ template class ColPivotingHouseholderQR */ const MatrixType& matrixQR() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_qr; } - ColPivotingHouseholderQR& compute(const MatrixType& matrix); + ColPivHouseholderQR& compute(const MatrixType& matrix); const IntRowVectorType& colsPermutation() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_cols_permutation; } @@ -154,7 +159,7 @@ template class ColPivotingHouseholderQR */ inline int rank() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_rank; } @@ -165,7 +170,7 @@ template class ColPivotingHouseholderQR */ inline int dimensionOfKernel() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_qr.cols() - m_rank; } @@ -177,7 +182,7 @@ template class ColPivotingHouseholderQR */ inline bool isInjective() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_rank == m_qr.cols(); } @@ -189,7 +194,7 @@ template class ColPivotingHouseholderQR */ inline bool isSurjective() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return m_rank == m_qr.rows(); } @@ -200,40 +205,28 @@ template class ColPivotingHouseholderQR */ inline bool isInvertible() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return isInjective() && isSurjective(); } - /** Computes the inverse of the matrix of which *this is the QR decomposition. - * - * \param result a pointer to the matrix into which to store the inverse. Resized if needed. - * - * \note If this matrix is not invertible, *result is left with undefined coefficients. - * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa inverse() - */ - inline void computeInverse(MatrixType *result) const - { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); - ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the inverse of a non-square matrix!"); - solve(MatrixType::Identity(m_qr.rows(), m_qr.cols()), result); - } - /** \returns the inverse of the matrix of which *this is the QR decomposition. * * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa computeInverse() */ - inline MatrixType inverse() const + inline const + ei_solve_retval > + inverse() const { - MatrixType result; - computeInverse(&result); - return result; + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + return ei_solve_retval > + (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()).nestByValue()); } + inline int rows() const { return m_qr.rows(); } + inline int cols() const { return m_qr.cols(); } + const HCoeffsType& hCoeffs() const { return m_hCoeffs; } + protected: MatrixType m_qr; HCoeffsType m_hCoeffs; @@ -247,23 +240,23 @@ template class ColPivotingHouseholderQR #ifndef EIGEN_HIDE_HEAVY_CODE template -typename MatrixType::RealScalar ColPivotingHouseholderQR::absDeterminant() const +typename MatrixType::RealScalar ColPivHouseholderQR::absDeterminant() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); return ei_abs(m_qr.diagonal().prod()); } template -typename MatrixType::RealScalar ColPivotingHouseholderQR::logAbsDeterminant() const +typename MatrixType::RealScalar ColPivHouseholderQR::logAbsDeterminant() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); return m_qr.diagonal().cwise().abs().cwise().log().sum(); } template -ColPivotingHouseholderQR& ColPivotingHouseholderQR::compute(const MatrixType& matrix) +ColPivHouseholderQR& ColPivHouseholderQR::compute(const MatrixType& matrix) { int rows = matrix.rows(); int cols = matrix.cols(); @@ -331,56 +324,60 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp return *this; } -template -template -bool ColPivotingHouseholderQR::solve( - const MatrixBase& b, - ResultType *result -) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); - result->resize(m_qr.cols(), b.cols()); - if(m_rank==0) + EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs) + + template void evalTo(Dest& dst) const { - if(b.squaredNorm() == RealScalar(0)) + const int rows = dec().rows(), cols = dec().cols(); + dst.resize(cols, rhs().cols()); + ei_assert(rhs().rows() == rows); + + // FIXME introduce nonzeroPivots() and use it here. and more generally, + // make the same improvements in this dec as in FullPivLU. + if(dec().rank()==0) { - result->setZero(); - return true; + dst.setZero(); + return; } - else return false; + + typename Rhs::PlainMatrixType c(rhs()); + + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(makeHouseholderSequence( + dec().matrixQR().corner(TopLeft,rows,dec().rank()), + dec().hCoeffs().start(dec().rank())).transpose() + ); + + if(!dec().isSurjective()) + { + // is c is in the image of R ? + RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, dec().rank(), c.cols()).cwise().abs().maxCoeff(); + RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-dec().rank(), c.cols()).cwise().abs().maxCoeff(); + // FIXME brain dead + const RealScalar m_precision = epsilon() * std::min(rows,cols); + if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision*4)) + return; + } + + dec().matrixQR() + .corner(TopLeft, dec().rank(), dec().rank()) + .template triangularView() + .solveInPlace(c.corner(TopLeft, dec().rank(), c.cols())); + + for(int i = 0; i < dec().rank(); ++i) dst.row(dec().colsPermutation().coeff(i)) = c.row(i); + for(int i = dec().rank(); i < cols; ++i) dst.row(dec().colsPermutation().coeff(i)).setZero(); } - - const int rows = m_qr.rows(); - ei_assert(b.rows() == rows); - - typename OtherDerived::PlainMatrixType c(b); - - // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T - c.applyOnTheLeft(makeHouseholderSequence(m_qr.corner(TopLeft,rows,m_rank), m_hCoeffs.start(m_rank)).transpose()); - - if(!isSurjective()) - { - // is c is in the image of R ? - RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff(); - RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-m_rank, c.cols()).cwise().abs().maxCoeff(); - if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision*4)) - return false; - } - - m_qr.corner(TopLeft, m_rank, m_rank) - .template triangularView() - .solveInPlace(c.corner(TopLeft, m_rank, c.cols())); - - for(int i = 0; i < m_rank; ++i) result->row(m_cols_permutation.coeff(i)) = c.row(i); - for(int i = m_rank; i < m_qr.cols(); ++i) result->row(m_cols_permutation.coeff(i)).setZero(); - return true; -} +}; /** \returns the matrix Q as a sequence of householder transformations */ template -typename ColPivotingHouseholderQR::HouseholderSequenceType ColPivotingHouseholderQR::matrixQ() const +typename ColPivHouseholderQR::HouseholderSequenceType ColPivHouseholderQR::matrixQ() const { - ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); } @@ -388,13 +385,13 @@ typename ColPivotingHouseholderQR::HouseholderSequenceType ColPivoti /** \return the column-pivoting Householder QR decomposition of \c *this. * - * \sa class ColPivotingHouseholderQR + * \sa class ColPivHouseholderQR */ template -const ColPivotingHouseholderQR::PlainMatrixType> -MatrixBase::colPivotingHouseholderQr() const +const ColPivHouseholderQR::PlainMatrixType> +MatrixBase::colPivHouseholderQr() const { - return ColPivotingHouseholderQR(eval()); + return ColPivHouseholderQR(eval()); } diff --git a/Eigen/src/QR/FullPivotingHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h similarity index 67% rename from Eigen/src/QR/FullPivotingHouseholderQR.h rename to Eigen/src/QR/FullPivHouseholderQR.h index 9fee77803..8be90a3c9 100644 --- a/Eigen/src/QR/FullPivotingHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -29,7 +29,7 @@ /** \ingroup QR_Module * \nonstableyet * - * \class FullPivotingHouseholderQR + * \class FullPivHouseholderQR * * \brief Householder rank-revealing QR decomposition of a matrix with full pivoting * @@ -38,21 +38,21 @@ * This class performs a rank-revealing QR decomposition using Householder transformations. * * This decomposition performs a very prudent full pivoting in order to be rank-revealing and achieve optimal - * numerical stability. The trade-off is that it is slower than HouseholderQR and ColPivotingHouseholderQR. + * numerical stability. The trade-off is that it is slower than HouseholderQR and ColPivHouseholderQR. * - * \sa MatrixBase::fullPivotingHouseholderQr() + * \sa MatrixBase::fullPivHouseholderQr() */ -template class FullPivotingHouseholderQR +template class FullPivHouseholderQR { public: + typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; @@ -65,11 +65,11 @@ template class FullPivotingHouseholderQR /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via FullPivotingHouseholderQR::compute(const MatrixType&). + * perform decompositions via FullPivHouseholderQR::compute(const MatrixType&). */ - FullPivotingHouseholderQR() : m_isInitialized(false) {} + FullPivHouseholderQR() : m_isInitialized(false) {} - FullPivotingHouseholderQR(const MatrixType& matrix) + FullPivHouseholderQR(const MatrixType& matrix) : m_isInitialized(false) { compute(matrix); @@ -78,22 +78,27 @@ template class FullPivotingHouseholderQR /** This method finds a solution x to the equation Ax=b, where A is the matrix of which * *this is the QR decomposition, if any exists. * - * \returns \c true if a solution exists, \c false if no solution exists. - * * \param b the right-hand-side of the equation to solve. * - * \param result a pointer to the vector/matrix in which to store the solution, if any exists. - * Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols(). - * If no solution exists, *result is left with undefined coefficients. + * \returns a solution. * * \note The case where b is a matrix is not yet implemented. Also, this * code is space inefficient. * - * Example: \include FullPivotingHouseholderQR_solve.cpp - * Output: \verbinclude FullPivotingHouseholderQR_solve.out + * \note_about_checking_solutions + * + * \note_about_arbitrary_choice_of_solution + * + * Example: \include FullPivHouseholderQR_solve.cpp + * Output: \verbinclude FullPivHouseholderQR_solve.out */ - template - bool solve(const MatrixBase& b, ResultType *result) const; + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + return ei_solve_retval(*this, b.derived()); + } MatrixQType matrixQ(void) const; @@ -101,21 +106,21 @@ template class FullPivotingHouseholderQR */ const MatrixType& matrixQR() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_qr; } - FullPivotingHouseholderQR& compute(const MatrixType& matrix); + FullPivHouseholderQR& compute(const MatrixType& matrix); const IntRowVectorType& colsPermutation() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_cols_permutation; } const IntColVectorType& rowsTranspositions() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_rows_transpositions; } @@ -155,7 +160,7 @@ template class FullPivotingHouseholderQR */ inline int rank() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_rank; } @@ -166,7 +171,7 @@ template class FullPivotingHouseholderQR */ inline int dimensionOfKernel() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_qr.cols() - m_rank; } @@ -178,7 +183,7 @@ template class FullPivotingHouseholderQR */ inline bool isInjective() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_rank == m_qr.cols(); } @@ -190,7 +195,7 @@ template class FullPivotingHouseholderQR */ inline bool isSurjective() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return m_rank == m_qr.rows(); } @@ -201,40 +206,27 @@ template class FullPivotingHouseholderQR */ inline bool isInvertible() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return isInjective() && isSurjective(); } - /** Computes the inverse of the matrix of which *this is the QR decomposition. - * - * \param result a pointer to the matrix into which to store the inverse. Resized if needed. - * - * \note If this matrix is not invertible, *result is left with undefined coefficients. - * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa inverse() - */ - inline void computeInverse(MatrixType *result) const - { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); - ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the inverse of a non-square matrix!"); - solve(MatrixType::Identity(m_qr.rows(), m_qr.cols()), result); - } - /** \returns the inverse of the matrix of which *this is the QR decomposition. * * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. - * - * \sa computeInverse() - */ - inline MatrixType inverse() const + */ inline const + ei_solve_retval > + inverse() const { - MatrixType result; - computeInverse(&result); - return result; + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + return ei_solve_retval > + (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols()).nestByValue()); } + inline int rows() const { return m_qr.rows(); } + inline int cols() const { return m_qr.cols(); } + const HCoeffsType& hCoeffs() const { return m_hCoeffs; } + protected: MatrixType m_qr; HCoeffsType m_hCoeffs; @@ -249,23 +241,23 @@ template class FullPivotingHouseholderQR #ifndef EIGEN_HIDE_HEAVY_CODE template -typename MatrixType::RealScalar FullPivotingHouseholderQR::absDeterminant() const +typename MatrixType::RealScalar FullPivHouseholderQR::absDeterminant() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); return ei_abs(m_qr.diagonal().prod()); } template -typename MatrixType::RealScalar FullPivotingHouseholderQR::logAbsDeterminant() const +typename MatrixType::RealScalar FullPivHouseholderQR::logAbsDeterminant() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); ei_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); return m_qr.diagonal().cwise().abs().cwise().log().sum(); } template -FullPivotingHouseholderQR& FullPivotingHouseholderQR::compute(const MatrixType& matrix) +FullPivHouseholderQR& FullPivHouseholderQR::compute(const MatrixType& matrix) { int rows = matrix.rows(); int cols = matrix.cols(); @@ -340,62 +332,63 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co return *this; } -template -template -bool FullPivotingHouseholderQR::solve( - const MatrixBase& b, - ResultType *result -) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); - result->resize(m_qr.cols(), b.cols()); - if(m_rank==0) + EIGEN_MAKE_SOLVE_HELPERS(FullPivHouseholderQR<_MatrixType>,Rhs) + + template void evalTo(Dest& dst) const { - if(b.squaredNorm() == RealScalar(0)) + const int rows = dec().rows(), cols = dec().cols(); + dst.resize(cols, rhs().cols()); + ei_assert(rhs().rows() == rows); + + // FIXME introduce nonzeroPivots() and use it here. and more generally, + // make the same improvements in this dec as in FullPivLU. + if(dec().rank()==0) { - result->setZero(); - return true; + dst.setZero(); + return; } - else return false; + + typename Rhs::PlainMatrixType c(rhs()); + + Matrix temp(rhs().cols()); + for (int k = 0; k < dec().rank(); ++k) + { + int remainingSize = rows-k; + c.row(k).swap(c.row(dec().rowsTranspositions().coeff(k))); + c.corner(BottomRight, remainingSize, rhs().cols()) + .applyHouseholderOnTheLeft(dec().matrixQR().col(k).end(remainingSize-1), + dec().hCoeffs().coeff(k), &temp.coeffRef(0)); + } + + if(!dec().isSurjective()) + { + // is c is in the image of R ? + RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, dec().rank(), c.cols()).cwise().abs().maxCoeff(); + RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-dec().rank(), c.cols()).cwise().abs().maxCoeff(); + // FIXME brain dead + const RealScalar m_precision = epsilon() * std::min(rows,cols); + if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision)) + return; + } + dec().matrixQR() + .corner(TopLeft, dec().rank(), dec().rank()) + .template triangularView() + .solveInPlace(c.corner(TopLeft, dec().rank(), c.cols())); + + for(int i = 0; i < dec().rank(); ++i) dst.row(dec().colsPermutation().coeff(i)) = c.row(i); + for(int i = dec().rank(); i < cols; ++i) dst.row(dec().colsPermutation().coeff(i)).setZero(); } - - const int rows = m_qr.rows(); - const int cols = b.cols(); - ei_assert(b.rows() == rows); - - typename OtherDerived::PlainMatrixType c(b); - - Matrix temp(cols); - for (int k = 0; k < m_rank; ++k) - { - int remainingSize = rows-k; - c.row(k).swap(c.row(m_rows_transpositions.coeff(k))); - c.corner(BottomRight, remainingSize, cols) - .applyHouseholderOnTheLeft(m_qr.col(k).end(remainingSize-1), m_hCoeffs.coeff(k), &temp.coeffRef(0)); - } - - if(!isSurjective()) - { - // is c is in the image of R ? - RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff(); - RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-m_rank, c.cols()).cwise().abs().maxCoeff(); - if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision)) - return false; - } - m_qr.corner(TopLeft, m_rank, m_rank) - .template triangularView() - .solveInPlace(c.corner(TopLeft, m_rank, c.cols())); - - for(int i = 0; i < m_rank; ++i) result->row(m_cols_permutation.coeff(i)) = c.row(i); - for(int i = m_rank; i < m_qr.cols(); ++i) result->row(m_cols_permutation.coeff(i)).setZero(); - return true; -} +}; /** \returns the matrix Q */ template -typename FullPivotingHouseholderQR::MatrixQType FullPivotingHouseholderQR::matrixQ() const +typename FullPivHouseholderQR::MatrixQType FullPivHouseholderQR::matrixQ() const { - ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); + ei_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); // compute the product H'_0 H'_1 ... H'_n-1, // where H_k is the k-th Householder transformation I - h_k v_k v_k' // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...] @@ -417,13 +410,13 @@ typename FullPivotingHouseholderQR::MatrixQType FullPivotingHousehol /** \return the full-pivoting Householder QR decomposition of \c *this. * - * \sa class FullPivotingHouseholderQR + * \sa class FullPivHouseholderQR */ template -const FullPivotingHouseholderQR::PlainMatrixType> -MatrixBase::fullPivotingHouseholderQr() const +const FullPivHouseholderQR::PlainMatrixType> +MatrixBase::fullPivHouseholderQr() const { - return FullPivotingHouseholderQR(eval()); + return FullPivHouseholderQR(eval()); } #endif // EIGEN_FULLPIVOTINGHOUSEHOLDERQR_H diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 01cd2adb5..04b153cc4 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -39,24 +39,24 @@ * stored in a compact way compatible with LAPACK. * * Note that no pivoting is performed. This is \b not a rank-revealing decomposition. - * If you want that feature, use FullPivotingHouseholderQR or ColPivotingHouseholderQR instead. + * If you want that feature, use FullPivHouseholderQR or ColPivHouseholderQR instead. * * This Householder QR decomposition is faster, but less numerically stable and less feature-full than - * FullPivotingHouseholderQR or ColPivotingHouseholderQR. + * FullPivHouseholderQR or ColPivHouseholderQR. * * \sa MatrixBase::householderQr() */ -template class HouseholderQR +template class HouseholderQR { public: + typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix::Flags&RowMajorBit ? RowMajor : ColMajor)> MatrixQType; @@ -85,19 +85,26 @@ template class HouseholderQR * * \param b the right-hand-side of the equation to solve. * - * \param result a pointer to the vector/matrix in which to store the solution, if any exists. - * Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols(). - * If no solution exists, *result is left with undefined coefficients. + * \returns a solution. * * \note The case where b is a matrix is not yet implemented. Also, this * code is space inefficient. * + * \note_about_checking_solutions + * + * \note_about_arbitrary_choice_of_solution + * * Example: \include HouseholderQR_solve.cpp * Output: \verbinclude HouseholderQR_solve.out */ - template - void solve(const MatrixBase& b, ResultType *result) const; - + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "HouseholderQR is not initialized."); + return ei_solve_retval(*this, b.derived()); + } + MatrixQType matrixQ() const; HouseholderSequenceType matrixQAsHouseholderSequence() const @@ -145,6 +152,10 @@ template class HouseholderQR */ typename MatrixType::RealScalar logAbsDeterminant() const; + inline int rows() const { return m_qr.rows(); } + inline int cols() const { return m_qr.cols(); } + const HCoeffsType& hCoeffs() const { return m_hCoeffs; } + protected: MatrixType m_qr; HCoeffsType m_hCoeffs; @@ -198,31 +209,36 @@ HouseholderQR& HouseholderQR::compute(const MatrixType& return *this; } -template -template -void HouseholderQR::solve( - const MatrixBase& b, - ResultType *result -) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "HouseholderQR is not initialized."); - result->derived().resize(m_qr.cols(), b.cols()); - const int rows = m_qr.rows(); - const int rank = std::min(m_qr.rows(), m_qr.cols()); - ei_assert(b.rows() == rows); + EIGEN_MAKE_SOLVE_HELPERS(HouseholderQR<_MatrixType>,Rhs) - typename OtherDerived::PlainMatrixType c(b); + template void evalTo(Dest& dst) const + { + const int rows = dec().rows(), cols = dec().cols(); + dst.resize(cols, rhs().cols()); + const int rank = std::min(rows, cols); + ei_assert(rhs().rows() == rows); - // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T - c.applyOnTheLeft(makeHouseholderSequence(m_qr.corner(TopLeft,rows,rank), m_hCoeffs.start(rank)).transpose()); + typename Rhs::PlainMatrixType c(rhs()); - m_qr.corner(TopLeft, rank, rank) - .template triangularView() - .solveInPlace(c.corner(TopLeft, rank, c.cols())); + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(makeHouseholderSequence( + dec().matrixQR().corner(TopLeft,rows,rank), + dec().hCoeffs().start(rank)).transpose() + ); - result->corner(TopLeft, rank, c.cols()) = c.corner(TopLeft,rank, c.cols()); - result->corner(BottomLeft, result->rows()-rank, c.cols()).setZero(); -} + dec().matrixQR() + .corner(TopLeft, rank, rank) + .template triangularView() + .solveInPlace(c.corner(TopLeft, rank, c.cols())); + + dst.corner(TopLeft, rank, c.cols()) = c.corner(TopLeft, rank, c.cols()); + dst.corner(BottomLeft, cols-rank, c.cols()).setZero(); + } +}; /** \returns the matrix Q */ template diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 6a0597893..927ef6591 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -233,7 +233,7 @@ struct ei_svd_precondition_if_more_rows_than_cols int diagSize = cols; if(rows > cols) { - FullPivotingHouseholderQR qr(matrix); + FullPivHouseholderQR qr(matrix); work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView(); if(ComputeU) svd.m_matrixU = qr.matrixQ(); if(ComputeV) @@ -278,7 +278,7 @@ struct ei_svd_precondition_if_more_cols_than_rows typedef Matrix TransposeTypeWithSameStorageOrder; - FullPivotingHouseholderQR qr(matrix.adjoint()); + FullPivHouseholderQR qr(matrix.adjoint()); work_matrix = qr.matrixQR().block(0,0,diagSize,diagSize).template triangularView().adjoint(); if(ComputeV) svd.m_matrixV = qr.matrixQ(); if(ComputeU) diff --git a/Eigen/src/SVD/SVD.h b/Eigen/src/SVD/SVD.h index 99272258e..254885873 100644 --- a/Eigen/src/SVD/SVD.h +++ b/Eigen/src/SVD/SVD.h @@ -25,6 +25,8 @@ #ifndef EIGEN_SVD_H #define EIGEN_SVD_H +template struct ei_svd_solve_impl; + /** \ingroup SVD_Module * \nonstableyet * @@ -38,26 +40,27 @@ * * \sa MatrixBase::SVD() */ -template class SVD +template class SVD { - private: + public: + typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, PacketSize = ei_packet_traits::size, AlignmentMask = int(PacketSize)-1, - MinSize = EIGEN_ENUM_MIN(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime) + MinSize = EIGEN_ENUM_MIN(RowsAtCompileTime, ColsAtCompileTime) }; - typedef Matrix ColVector; - typedef Matrix RowVector; + typedef Matrix ColVector; + typedef Matrix RowVector; - typedef Matrix MatrixUType; - typedef Matrix MatrixVType; - typedef Matrix SingularValuesType; - - public: + typedef Matrix MatrixUType; + typedef Matrix MatrixVType; + typedef Matrix SingularValuesType; /** * \brief Default Constructor. @@ -76,8 +79,23 @@ template class SVD compute(matrix); } - template - bool solve(const MatrixBase &b, ResultType* result) const; + /** \returns a solution of \f$ A x = b \f$ using the current SVD decomposition of A. + * + * \param b the right-hand-side of the equation to solve. + * + * \note_about_checking_solutions + * + * \note_about_arbitrary_choice_of_solution + * + * \sa MatrixBase::svd(), + */ + template + inline const ei_solve_retval + solve(const MatrixBase& b) const + { + ei_assert(m_isInitialized && "SVD is not initialized."); + return ei_solve_retval(*this, b.derived()); + } const MatrixUType& matrixU() const { @@ -108,6 +126,18 @@ template class SVD template void computeScalingRotation(ScalingType *positive, RotationType *unitary) const; + inline int rows() const + { + ei_assert(m_isInitialized && "SVD is not initialized."); + return m_rows; + } + + inline int cols() const + { + ei_assert(m_isInitialized && "SVD is not initialized."); + return m_cols; + } + protected: // Computes (a^2 + b^2)^(1/2) without destructive underflow or overflow. inline static Scalar pythag(Scalar a, Scalar b) @@ -133,6 +163,7 @@ template class SVD /** \internal */ SingularValuesType m_sigma; bool m_isInitialized; + int m_rows, m_cols; }; /** Computes / recomputes the SVD decomposition A = U S V^* of \a matrix @@ -144,8 +175,8 @@ template class SVD template SVD& SVD::compute(const MatrixType& matrix) { - const int m = matrix.rows(); - const int n = matrix.cols(); + const int m = m_rows = matrix.rows(); + const int n = m_cols = matrix.cols(); m_matU.resize(m, m); m_matU.setZero(); @@ -397,43 +428,35 @@ SVD& SVD::compute(const MatrixType& matrix) return *this; } -/** \returns the solution of \f$ A x = b \f$ using the current SVD decomposition of A. - * The parts of the solution corresponding to zero singular values are ignored. - * - * \sa MatrixBase::svd(), LU::solve(), LLT::solve() - */ -template -template -bool SVD::solve(const MatrixBase &b, ResultType* result) const +template +struct ei_solve_retval, Rhs> + : ei_solve_retval_base, Rhs> { - ei_assert(m_isInitialized && "SVD is not initialized."); + EIGEN_MAKE_SOLVE_HELPERS(SVD<_MatrixType>,Rhs) - const int rows = m_matU.rows(); - ei_assert(b.rows() == rows); - - result->resize(m_matV.rows(), b.cols()); - - Scalar maxVal = m_sigma.cwise().abs().maxCoeff(); - for (int j=0; j void evalTo(Dest& dst) const { - Matrix aux = m_matU.transpose() * b.col(j); + ei_assert(rhs().rows() == dec().rows()); - for (int i = 0; i aux = dec().matrixU().adjoint() * rhs().col(j); + + for (int i = 0; i < dec().rows(); ++i) + { + Scalar si = dec().singularValues().coeff(i); + if(si == RealScalar(0)) + aux.coeffRef(i) = Scalar(0); + else + aux.coeffRef(i) /= si; + } + const int minsize = std::min(dec().rows(),dec().cols()); + dst.col(j).start(minsize) = aux.start(minsize); + if(dec().cols()>dec().rows()) dst.col(j).end(cols()-minsize).setZero(); + dst.col(j) = dec().matrixV() * dst.col(j); } - const int cols = m_matV.rows(); - const int minsize = std::min(rows,cols); - result->col(j).start(minsize) = aux.start(minsize); - if(cols>rows) result->col(j).end(cols-minsize).setZero(); - result->col(j) = m_matV * result->col(j); } - return true; -} +}; /** Computes the polar decomposition of the matrix, as a product unitary x positive. * diff --git a/Eigen/src/Sparse/SparseLU.h b/Eigen/src/Sparse/SparseLU.h index e7191b7ab..3f8d0f8db 100644 --- a/Eigen/src/Sparse/SparseLU.h +++ b/Eigen/src/Sparse/SparseLU.h @@ -39,7 +39,7 @@ enum { * * \param MatrixType the type of the matrix of which we are computing the LU factorization * - * \sa class LU, class SparseLLT + * \sa class FullPivLU, class SparseLLT */ template class SparseLU diff --git a/Eigen/src/misc/CMakeLists.txt b/Eigen/src/misc/CMakeLists.txt new file mode 100644 index 000000000..a58ffb745 --- /dev/null +++ b/Eigen/src/misc/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_misc_SRCS "*.h") + +INSTALL(FILES + ${Eigen_misc_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/misc COMPONENT Devel + ) diff --git a/Eigen/src/misc/Image.h b/Eigen/src/misc/Image.h new file mode 100644 index 000000000..9ed5d5f70 --- /dev/null +++ b/Eigen/src/misc/Image.h @@ -0,0 +1,88 @@ +// 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_MISC_IMAGE_H +#define EIGEN_MISC_IMAGE_H + +/** \class ei_image_retval_base + * + */ +template +struct ei_traits > +{ + typedef typename DecompositionType::MatrixType MatrixType; + typedef Matrix< + typename MatrixType::Scalar, + MatrixType::RowsAtCompileTime, // the image is a subspace of the destination space, whose + // dimension is the number of rows of the original matrix + Dynamic, // we don't know at compile time the dimension of the image (the rank) + MatrixType::Options, + MatrixType::MaxRowsAtCompileTime, // the image matrix will consist of columns from the original matrix, + MatrixType::MaxColsAtCompileTime // so it has the same number of rows and at most as many columns. + > ReturnMatrixType; +}; + +template struct ei_image_retval_base + : public ReturnByValue > +{ + typedef _DecompositionType DecompositionType; + typedef typename DecompositionType::MatrixType MatrixType; + + ei_image_retval_base(const DecompositionType& dec, const MatrixType& originalMatrix) + : m_dec(dec), m_rank(dec.rank()), + m_cols(m_rank == 0 ? 1 : m_rank), + m_originalMatrix(originalMatrix) + {} + + inline int rows() const { return m_dec.rows(); } + inline int cols() const { return m_cols; } + inline int rank() const { return m_rank; } + inline const DecompositionType& dec() const { return m_dec; } + inline const MatrixType& originalMatrix() const { return m_originalMatrix; } + + template inline void evalTo(Dest& dst) const + { + static_cast*>(this)->evalTo(dst); + } + + protected: + const DecompositionType& m_dec; + int m_rank, m_cols; + const MatrixType& m_originalMatrix; +}; + +#define EIGEN_MAKE_IMAGE_HELPERS(DecompositionType) \ + typedef typename DecompositionType::MatrixType MatrixType; \ + typedef typename MatrixType::Scalar Scalar; \ + typedef typename MatrixType::RealScalar RealScalar; \ + typedef ei_image_retval_base Base; \ + using Base::dec; \ + using Base::originalMatrix; \ + using Base::rank; \ + using Base::rows; \ + using Base::cols; \ + ei_image_retval(const DecompositionType& dec, const MatrixType& originalMatrix) \ + : Base(dec, originalMatrix) {} + +#endif // EIGEN_MISC_IMAGE_H diff --git a/Eigen/src/misc/Kernel.h b/Eigen/src/misc/Kernel.h new file mode 100644 index 000000000..717eef450 --- /dev/null +++ b/Eigen/src/misc/Kernel.h @@ -0,0 +1,85 @@ +// 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_MISC_KERNEL_H +#define EIGEN_MISC_KERNEL_H + +/** \class ei_kernel_retval_base + * + */ +template +struct ei_traits > +{ + typedef typename DecompositionType::MatrixType MatrixType; + typedef Matrix< + typename MatrixType::Scalar, + MatrixType::ColsAtCompileTime, // the number of rows in the "kernel matrix" + // is the number of cols of the original matrix + // so that the product "matrix * kernel = zero" makes sense + Dynamic, // we don't know at compile-time the dimension of the kernel + MatrixType::Options, + MatrixType::MaxColsAtCompileTime, // see explanation for 2nd template parameter + MatrixType::MaxColsAtCompileTime // the kernel is a subspace of the domain space, + // whose dimension is the number of columns of the original matrix + > ReturnMatrixType; +}; + +template struct ei_kernel_retval_base + : public ReturnByValue > +{ + typedef _DecompositionType DecompositionType; + + ei_kernel_retval_base(const DecompositionType& dec) + : m_dec(dec), + m_rank(dec.rank()), + m_cols(m_rank==dec.cols() ? 1 : dec.cols() - m_rank) + {} + + inline int rows() const { return m_dec.cols(); } + inline int cols() const { return m_cols; } + inline int rank() const { return m_rank; } + inline const DecompositionType& dec() const { return m_dec; } + + template inline void evalTo(Dest& dst) const + { + static_cast*>(this)->evalTo(dst); + } + + protected: + const DecompositionType& m_dec; + int m_rank, m_cols; +}; + +#define EIGEN_MAKE_KERNEL_HELPERS(DecompositionType) \ + typedef typename DecompositionType::MatrixType MatrixType; \ + typedef typename MatrixType::Scalar Scalar; \ + typedef typename MatrixType::RealScalar RealScalar; \ + typedef ei_kernel_retval_base Base; \ + using Base::dec; \ + using Base::rank; \ + using Base::rows; \ + using Base::cols; \ + ei_kernel_retval(const DecompositionType& dec) : Base(dec) {} + +#endif // EIGEN_MISC_KERNEL_H diff --git a/Eigen/src/misc/Solve.h b/Eigen/src/misc/Solve.h new file mode 100644 index 000000000..d93869121 --- /dev/null +++ b/Eigen/src/misc/Solve.h @@ -0,0 +1,80 @@ +// 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_MISC_SOLVE_H +#define EIGEN_MISC_SOLVE_H + +/** \class ei_solve_retval_base + * + */ +template +struct ei_traits > +{ + typedef typename DecompositionType::MatrixType MatrixType; + typedef Matrix ReturnMatrixType; +}; + +template struct ei_solve_retval_base + : public ReturnByValue > +{ + typedef typename ei_cleantype::type RhsNestedCleaned; + typedef _DecompositionType DecompositionType; + + ei_solve_retval_base(const DecompositionType& dec, const Rhs& rhs) + : m_dec(dec), m_rhs(rhs) + {} + + inline int rows() const { return m_dec.cols(); } + inline int cols() const { return m_rhs.cols(); } + inline const DecompositionType& dec() const { return m_dec; } + inline const RhsNestedCleaned& rhs() const { return m_rhs; } + + template inline void evalTo(Dest& dst) const + { + static_cast*>(this)->evalTo(dst); + } + + protected: + const DecompositionType& m_dec; + const typename Rhs::Nested m_rhs; +}; + +#define EIGEN_MAKE_SOLVE_HELPERS(DecompositionType,Rhs) \ + typedef typename DecompositionType::MatrixType MatrixType; \ + typedef typename MatrixType::Scalar Scalar; \ + typedef typename MatrixType::RealScalar RealScalar; \ + typedef ei_solve_retval_base Base; \ + using Base::dec; \ + using Base::rhs; \ + using Base::rows; \ + using Base::cols; \ + ei_solve_retval(const DecompositionType& dec, const Rhs& rhs) \ + : Base(dec, rhs) {} + +#endif // EIGEN_MISC_SOLVE_H diff --git a/bench/btl/libs/eigen2/eigen2_interface.hh b/bench/btl/libs/eigen2/eigen2_interface.hh index 1a5f89834..f93ccad58 100644 --- a/bench/btl/libs/eigen2/eigen2_interface.hh +++ b/bench/btl/libs/eigen2/eigen2_interface.hh @@ -218,7 +218,7 @@ public : } static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ - C = X.partialLu().matrixLU(); + C = X.partialPivLu().matrixLU(); } static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){ diff --git a/bench/sparse_lu.cpp b/bench/sparse_lu.cpp index bb73d481d..5c7500182 100644 --- a/bench/sparse_lu.cpp +++ b/bench/sparse_lu.cpp @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) BenchTimer timer; timer.start(); - LU lu(m1); + FullPivLU lu(m1); timer.stop(); std::cout << "Eigen/dense:\t" << timer.value() << endl; diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index b8e159be7..bb272a8cc 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -1,5 +1,3 @@ - - option(EIGEN_NO_ASSERTION_CHECKING "Disable checking of assertions" OFF) # similar to set_target_properties but append the property instead of overwriting it @@ -18,30 +16,11 @@ macro(ei_add_property prop value) set_property(GLOBAL PROPERTY ${prop} "${previous} ${value}") endmacro(ei_add_property) -# Macro to add a test -# -# the unique parameter testname must correspond to a file -# .cpp which follows this pattern: -# -# #include "main.h" -# void test_() { ... } -# -# this macro add an executable test_ as well as a ctest test -# named . -# -# it also adds another executable debug_ that compiles in full debug mode -# and is not added to the test target. The idea is that when a test fails you want -# a quick way of rebuilding this specific test in full debug mode. -# -# On platforms with bash simply run: -# "ctest -V" or "ctest -V -R " -# On other platform use ctest as usual -# -macro(ei_add_test testname) - - set(targetname test_${testname}) +#internal. See documentation of ei_add_test for details. +macro(ei_add_test_internal testname testname_with_suffix) + set(targetname test_${testname_with_suffix}) if(NOT MSVC_IDE) - set(debug_targetname debug_${testname}) + set(debug_targetname debug_${testname_with_suffix}) endif(NOT MSVC_IDE) set(filename ${testname}.cpp) @@ -80,13 +59,21 @@ macro(ei_add_test testname) endif(NOT EIGEN_NO_ASSERTION_CHECKING) - # let the user pass e.g. optimization flags, but don't apply them to the debug target - if(${ARGC} GREATER 1) - ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV1}") - endif(${ARGC} GREATER 1) + # let the user pass flags. Note that if the user passes an optimization flag here, it's important that + # we counter it by a no-optimization flag! + if(${ARGC} GREATER 2) + ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV2}") + if(NOT MSVC_IDE) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "${ARGV2} ${EI_NO_OPTIMIZATION_FLAG}") + endif(NOT MSVC_IDE) + endif(${ARGC} GREATER 2) # for the debug target, add full debug options if(CMAKE_COMPILER_IS_GNUCXX) + # disable debug symbols: i get 2 GB of them! + # the user can still use the debug targets as needed. + # for MSVC, the equivalent (release mode) does the same. + ei_add_target_property(${targetname} COMPILE_FLAGS "-g0") # O0 is in principle redundant here, but doesn't hurt ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-O0 -g3") elseif(MSVC) @@ -101,27 +88,109 @@ macro(ei_add_test testname) endif(NOT MSVC_IDE) target_link_libraries(${targetname} ${EXTERNAL_LIBS}) - if(${ARGC} GREATER 2) - string(STRIP "${ARGV2}" ARGV2_stripped) - string(LENGTH "${ARGV2_stripped}" ARGV2_stripped_length) - if(${ARGV2_stripped_length} GREATER 0) - target_link_libraries(${targetname} ${ARGV2}) + if(${ARGC} GREATER 3) + string(STRIP "${ARGV3}" ARGV3_stripped) + string(LENGTH "${ARGV3_stripped}" ARGV3_stripped_length) + if(${ARGV3_stripped_length} GREATER 0) + target_link_libraries(${targetname} ${ARGV3}) if(NOT MSVC_IDE) - target_link_libraries(${debug_targetname} ${ARGV2}) + target_link_libraries(${debug_targetname} ${ARGV3}) endif(NOT MSVC_IDE) - endif(${ARGV2_stripped_length} GREATER 0) - endif(${ARGC} GREATER 2) + endif(${ARGV3_stripped_length} GREATER 0) + endif(${ARGC} GREATER 3) if(WIN32) if(CYGWIN) - add_test(${testname} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname}") + add_test(${testname_with_suffix} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname_with_suffix}") else(CYGWIN) - add_test(${testname} "${targetname}") + add_test(${testname_with_suffix} "${targetname}") endif(CYGWIN) else(WIN32) - add_test(${testname} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname}") + add_test(${testname_with_suffix} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname_with_suffix}") endif(WIN32) +endmacro(ei_add_test_internal) + + +# Macro to add a test +# +# the unique mandatory parameter testname must correspond to a file +# .cpp which follows this pattern: +# +# #include "main.h" +# void test_() { ... } +# +# Depending on the contents of that file, this macro can have 2 behaviors, +# see below. +# +# Optional parameters can be passed: the 2nd parameter is additional compile flags +# (optimization will be explicitly disabled for the debug test targets) and the 3rd +# parameter is libraries to link to. +# +# A. Default behavior +# +# this macro add an executable test_ as well as a ctest test +# named . +# +# it also adds another executable debug_ that compiles in full debug mode +# and is not added to the test target. The idea is that when a test fails you want +# a quick way of rebuilding this specific test in full debug mode. +# +# On platforms with bash simply run: +# "ctest -V" or "ctest -V -R " +# On other platform use ctest as usual +# +# B. Multi-part behavior +# +# If the source file matches the regexp +# CALL_SUBTEST(-9]+|EIGEN_TEST_PART_[0-9]+ +# then it is interpreted as a multi-part test. The behavior then depends on the +# CMake option EIGEN_SPLIT_LARGE_TESTS, which is ON by default. +# +# If EIGEN_SPLIT_LARGE_TESTS is OFF, the behavior is the same as in A (the multi-part +# aspect is ignored). +# +# If EIGEN_SPLIT_LARGE_TESTS is ON, the test is split into multiple executables +# test__ +# where N runs from 1 to the greatest occurence found in the source file. Each of these +# executables is built passing -DEIGEN_TEST_PART_N. This allows to split large tests +# into smaller executables. +# +# The same holds for the debug executables. +# +# Moreover, targets test_ and debug_ are still generated, they +# have the effect of building all the parts of the test. +# +# Again, ctest -R allows to run all matching tests. +# +macro(ei_add_test testname) + file(READ "${testname}.cpp" test_source) + set(parts 0) + string(REGEX MATCHALL "CALL_SUBTEST_[0-9]+|EIGEN_TEST_PART_[0-9]+" + occurences "${test_source}") + string(REGEX REPLACE "CALL_SUBTEST_|EIGEN_TEST_PART_" "" suffixes "${occurences}") + list(REMOVE_DUPLICATES suffixes) + if(EIGEN_SPLIT_LARGE_TESTS AND suffixes) + add_custom_target(test_${testname}) + if(NOT MSVC_IDE) + add_custom_target(debug_${testname}) + endif(NOT MSVC_IDE) + foreach(suffix ${suffixes}) + ei_add_test_internal(${testname} ${testname}_${suffix} + "${ARGV1} -DEIGEN_TEST_PART_${suffix}=1" "${ARGV2}") + add_dependencies(test_${testname} test_${testname}_${suffix}) + if(NOT MSVC_IDE) + add_dependencies(debug_${testname} debug_${testname}_${suffix}) + endif(NOT MSVC_IDE) + endforeach(suffix) + else(EIGEN_SPLIT_LARGE_TESTS AND suffixes) + set(symbols_to_enable_all_parts "") + foreach(suffix ${suffixes}) + set(symbols_to_enable_all_parts + "${symbols_to_enable_all_parts} -DEIGEN_TEST_PART_${suffix}=1") + endforeach(suffix) + ei_add_test_internal(${testname} ${testname} "${ARGV1} ${symbols_to_enable_all_parts}" "${ARGV2}") + endif(EIGEN_SPLIT_LARGE_TESTS AND suffixes) endmacro(ei_add_test) # print a summary of the different options @@ -204,12 +273,15 @@ if(CMAKE_COMPILER_IS_GNUCXX) 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") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g3") endif(CMAKE_SYSTEM_NAME MATCHES Linux) set(EI_OFLAG "-O2") + set(EI_NO_OPTIMIZATION_FLAG "-O0") elseif(MSVC) set(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Zi /Ob0 /Od" CACHE STRING "Flags used by the compiler during debug builds." FORCE) set(EI_OFLAG "/O2") + set(EI_NO_OPTIMIZATION_FLAG "/O0") else(CMAKE_COMPILER_IS_GNUCXX) set(EI_OFLAG "") + set(EI_NO_OPTIMIZATION_FLAG "") endif(CMAKE_COMPILER_IS_GNUCXX) diff --git a/doc/C05_TutorialLinearAlgebra.dox b/doc/C05_TutorialLinearAlgebra.dox index fbf809d58..c50e9c6bc 100644 --- a/doc/C05_TutorialLinearAlgebra.dox +++ b/doc/C05_TutorialLinearAlgebra.dox @@ -55,8 +55,8 @@ matrix with a vector or another matrix: \f$ A^{-1} \mathbf{v} \f$ or \f$ A^{-1} This is a general-purpose algorithm which performs well in most cases (provided the matrix \f$ A \f$ is invertible), so if you are unsure about which algorithm to pick, choose this. The method proceeds in two steps. First, the %LU decomposition with partial pivoting is computed using the -MatrixBase::partialLu() function. This yields an object of the class PartialLU. Then, the -PartialLU::solve() method is called to compute a solution. +MatrixBase::partialPivLu() function. This yields an object of the class PartialPivLU. Then, the +PartialPivLU::solve() method is called to compute a solution. As an example, suppose we want to solve the following system of linear equations: @@ -69,9 +69,9 @@ As an example, suppose we want to solve the following system of linear equations The following program solves this system:
-\include Tutorial_PartialLU_solve.cpp +\include Tutorial_PartialPivLU_solve.cpp -output: \include Tutorial_PartialLU_solve.out +output: \include Tutorial_PartialPivLU_solve.out
There are many situations in which we want to solve the same system of equations with different @@ -91,7 +91,7 @@ problem, and whether you want to solve it at all, after you solved the first pro case, it's best to save the %LU decomposition and reuse it to solve the second problem. This is worth the effort because computing the %LU decomposition is much more expensive than using it to solve the equation. Here is some code to illustrate the procedure. It uses the constructor -PartialLU::PartialLU(const MatrixType&) to compute the %LU decomposition. +PartialPivLU::PartialPivLU(const MatrixType&) to compute the %LU decomposition.
\include Tutorial_solve_reuse_decomposition.cpp @@ -102,7 +102,7 @@ output: \include Tutorial_solve_reuse_decomposition.out \b Warning: All this code presumes that the matrix \f$ A \f$ is invertible, so that the system \f$ A \mathbf{x} = \mathbf{b} \f$ has a unique solution. If the matrix \f$ A \f$ is not invertible, then the system \f$ A \mathbf{x} = \mathbf{b} \f$ has either zero or infinitely many solutions. In -both cases, PartialLU::solve() will give nonsense results. For example, suppose that we want to +both cases, PartialPivLU::solve() will give nonsense results. For example, suppose that we want to solve the same system as above, but with the 10 in the last equation replaced by 9. Then the system of equations is inconsistent: adding the first and the third equation gives \f$ 8x + 10y + 12z = 7 \f$, which implies \f$ 4x + 5y + 6z = 3\frac12 \f$, in contradiction with the second equation. If we try @@ -114,10 +114,10 @@ to solve this inconsistent system with Eigen, we find: output: \include Tutorial_solve_singular.out
-The %LU decomposition with \b full pivoting (class LU) and the singular value decomposition (class +The %LU decomposition with \b full pivoting (class FullPivLU) and the singular value decomposition (class SVD) may be helpful in this case, as explained in the section \ref TutorialAdvSolvers_Misc below. -\sa LU_Module, MatrixBase::partialLu(), PartialLU::solve(), class PartialLU. +\sa LU_Module, MatrixBase::partialPivLu(), PartialPivLU::solve(), class PartialPivLU. \subsection TutorialAdvSolvers_Cholesky Cholesky decomposition @@ -228,7 +228,7 @@ Note that the function inverse() is defined in the \ref LU_Module. Finally, Eigen also offer solvers based on a singular value decomposition (%SVD) or the %LU decomposition with full pivoting. These have the same API as the solvers based on the %LU -decomposition with partial pivoting (PartialLU). +decomposition with partial pivoting (PartialPivLU). The solver based on the %SVD uses the class SVD. It can handle singular matrices. Here is an example of its use: @@ -245,7 +245,7 @@ svdOfA.solve(b, &x); \endcode %LU decomposition with full pivoting has better numerical stability than %LU decomposition with -partial pivoting. It is defined in the class LU. The solver can also handle singular matrices. +partial pivoting. It is defined in the class FullPivLU. The solver can also handle singular matrices. \code #include @@ -254,13 +254,13 @@ MatrixXf A = MatrixXf::Random(20,20); VectorXf b = VectorXf::Random(20); VectorXf x; A.lu().solve(b, &x); -LU luOfA(A); +FullPivLU luOfA(A); luOfA.solve(b, &x); \endcode See the section \ref TutorialAdvLU below. -\sa class SVD, SVD::solve(), SVD_Module, class LU, LU::solve(), LU_Module. +\sa class SVD, SVD::solve(), SVD_Module, class FullPivLU, LU::solve(), LU_Module. @@ -281,7 +281,7 @@ Alternatively, you can construct a named LU decomposition, which allows you to r \code #include MatrixXf A = MatrixXf::Random(20,20); -Eigen::LU lu(A); +Eigen::FullPivLU lu(A); cout << "The rank of A is" << lu.rank() << endl; if(lu.isInvertible()) { cout << "A is invertible, its inverse is:" << endl << lu.inverse() << endl; @@ -292,7 +292,7 @@ else { } \endcode -\sa LU_Module, LU::solve(), class LU +\sa LU_Module, LU::solve(), class FullPivLU top\section TutorialAdvCholesky Cholesky todo diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 5b055ed11..412831e14 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -215,7 +215,10 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "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\"" + "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\"" \ + "note_about_arbitrary_choice_of_solution=If there exists more than one solution, this method will arbitrarily choose one." \ + "note_about_using_kernel_to_study_multiple_solutions=If you need a complete analysis of the space of solutions, take the one solution obtained by this method and add to it elements of the kernel, as determined by kernel()." \ + "note_about_checking_solutions=This method just tries to find as good a solution as possible. If you want to check whether a solution exists or if it is accurate, just call this function to get a result and then compute the error of this result, or use MatrixBase::isApprox() directly, for instance like this: \code bool a_solution_exists = (A*result).isApprox(b, precision); \endcode This method avoids dividing by zero, so that the non-existence of a solution doesn't by itself mean that you'll get \c inf or \c nan values." # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. diff --git a/doc/examples/Tutorial_PartialLU_solve.cpp b/doc/examples/Tutorial_PartialLU_solve.cpp index 80c393f9a..98f9d6dac 100644 --- a/doc/examples/Tutorial_PartialLU_solve.cpp +++ b/doc/examples/Tutorial_PartialLU_solve.cpp @@ -12,7 +12,6 @@ int main(int, char *[]) b << 3, 3, 4; cout << "Here is the matrix A:" << endl << A << endl; cout << "Here is the vector b:" << endl << b << endl; - Vector3f x; - A.partialLu().solve(b, &x); + Vector3f x = A.lu().solve(b); cout << "The solution is:" << endl << x << endl; } diff --git a/doc/snippets/LU_image.cpp b/doc/snippets/FullPivLU_image.cpp similarity index 86% rename from doc/snippets/LU_image.cpp rename to doc/snippets/FullPivLU_image.cpp index 0d1088a2f..817bc1e2d 100644 --- a/doc/snippets/LU_image.cpp +++ b/doc/snippets/FullPivLU_image.cpp @@ -6,4 +6,4 @@ cout << "Here is the matrix m:" << endl << m << endl; cout << "Notice that the middle column is the sum of the two others, so the " << "columns are linearly dependent." << endl; cout << "Here is a matrix whose columns have the same span but are linearly independent:" - << endl << m.lu().image() << endl; + << endl << m.fullPivLu().image(m) << endl; diff --git a/doc/snippets/LU_kernel.cpp b/doc/snippets/FullPivLU_kernel.cpp similarity index 87% rename from doc/snippets/LU_kernel.cpp rename to doc/snippets/FullPivLU_kernel.cpp index e01186d38..7086e01e2 100644 --- a/doc/snippets/LU_kernel.cpp +++ b/doc/snippets/FullPivLU_kernel.cpp @@ -1,6 +1,6 @@ MatrixXf m = MatrixXf::Random(3,5); cout << "Here is the matrix m:" << endl << m << endl; -MatrixXf ker = m.lu().kernel(); +MatrixXf ker = m.fullPivLu().kernel(); cout << "Here is a matrix whose columns form a basis of the kernel of m:" << endl << ker << endl; cout << "By definition of the kernel, m*ker is zero:" diff --git a/doc/snippets/LU_solve.cpp b/doc/snippets/FullPivLU_solve.cpp similarity index 62% rename from doc/snippets/LU_solve.cpp rename to doc/snippets/FullPivLU_solve.cpp index 7323338c3..c1f88235e 100644 --- a/doc/snippets/LU_solve.cpp +++ b/doc/snippets/FullPivLU_solve.cpp @@ -1,15 +1,11 @@ -typedef Matrix Matrix2x3; -typedef Matrix Matrix3x2; -Matrix2x3 m = Matrix2x3::Random(); +Matrix m = Matrix::Random(); Matrix2f y = Matrix2f::Random(); cout << "Here is the matrix m:" << endl << m << endl; cout << "Here is the matrix y:" << endl << y << endl; -Matrix3x2 x; -if(m.lu().solve(y, &x)) +Matrix x = m.fullPivLu().solve(y); +if((m*x).isApprox(y)) { - assert(y.isApprox(m*x)); cout << "Here is a solution x to the equation mx=y:" << endl << x << endl; } else cout << "The equation mx=y does not have any solution." << endl; - diff --git a/doc/snippets/HouseholderQR_solve.cpp b/doc/snippets/HouseholderQR_solve.cpp index 429bd81e3..8cce6ce6c 100644 --- a/doc/snippets/HouseholderQR_solve.cpp +++ b/doc/snippets/HouseholderQR_solve.cpp @@ -4,6 +4,6 @@ Matrix3f y = Matrix3f::Random(); cout << "Here is the matrix m:" << endl << m << endl; cout << "Here is the matrix y:" << endl << y << endl; Matrix3f x; -m.householderQr().solve(y, &x); +x = m.householderQr().solve(y); assert(y.isApprox(m*x)); cout << "Here is a solution x to the equation mx=y:" << endl << x << endl; diff --git a/doc/snippets/LLT_solve.cpp b/doc/snippets/LLT_solve.cpp index 76ab09ec5..7095d2cc3 100644 --- a/doc/snippets/LLT_solve.cpp +++ b/doc/snippets/LLT_solve.cpp @@ -3,6 +3,6 @@ typedef Matrix DataMatrix; DataMatrix samples = DataMatrix::Random(12,2); VectorXf elevations = 2*samples.col(0) + 3*samples.col(1) + VectorXf::Random(12)*0.1; // and let's solve samples * [x y]^T = elevations in least square sense: -Matrix xy; -(samples.adjoint() * samples).llt().solve((samples.adjoint()*elevations), &xy); +Matrix xy + = (samples.adjoint() * samples).llt().solve((samples.adjoint()*elevations)); cout << xy << endl; diff --git a/doc/snippets/LU_computeImage.cpp b/doc/snippets/LU_computeImage.cpp deleted file mode 100644 index 5c812cc4c..000000000 --- a/doc/snippets/LU_computeImage.cpp +++ /dev/null @@ -1,13 +0,0 @@ -MatrixXd m(3,3); -m << 1,1,0, - 1,3,2, - 0,1,1; -cout << "Here is the matrix m:" << endl << m << endl; -LU lu(m); -// allocate the matrix img with the correct size to avoid reallocation -MatrixXd img(m.rows(), lu.rank()); -lu.computeImage(&img); -cout << "Notice that the middle column is the sum of the two others, so the " - << "columns are linearly dependent." << endl; -cout << "Here is a matrix whose columns have the same span but are linearly independent:" - << endl << img << endl; diff --git a/doc/snippets/LU_computeKernel.cpp b/doc/snippets/LU_computeKernel.cpp deleted file mode 100644 index b08f7f1ea..000000000 --- a/doc/snippets/LU_computeKernel.cpp +++ /dev/null @@ -1,10 +0,0 @@ -MatrixXf m = MatrixXf::Random(3,5); -cout << "Here is the matrix m:" << endl << m << endl; -LU lu(m); -// allocate the matrix ker with the correct size to avoid reallocation -MatrixXf ker(m.rows(), lu.dimensionOfKernel()); -lu.computeKernel(&ker); -cout << "Here is a matrix whose columns form a basis of the kernel of m:" - << endl << ker << endl; -cout << "By definition of the kernel, m*ker is zero:" - << endl << m*ker << endl; diff --git a/doc/snippets/MatrixBase_computeInverse.cpp b/doc/snippets/MatrixBase_computeInverse.cpp deleted file mode 100644 index ba7377a4a..000000000 --- a/doc/snippets/MatrixBase_computeInverse.cpp +++ /dev/null @@ -1,5 +0,0 @@ -Matrix3d m = Matrix3d::Random(); -cout << "Here is the matrix m:" << endl << m << endl; -Matrix3d inv; -m.computeInverse(&inv); -cout << "Its inverse is:" << endl << inv << endl; diff --git a/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp b/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp new file mode 100644 index 000000000..a7b084fd0 --- /dev/null +++ b/doc/snippets/MatrixBase_computeInverseAndDetWithCheck.cpp @@ -0,0 +1,13 @@ +Matrix3d m = Matrix3d::Random(); +cout << "Here is the matrix m:" << endl << m << endl; +Matrix3d inverse; +bool invertible; +double determinant; +m.computeInverseAndDetWithCheck(inverse,determinant,invertible); +cout << "Its determinant is " << determinant << endl; +if(invertible) { + cout << "It is invertible, and its inverse is:" << endl << inverse << endl; +} +else { + cout << "It is not invertible." << endl; +} diff --git a/doc/snippets/MatrixBase_computeInverseWithCheck.cpp b/doc/snippets/MatrixBase_computeInverseWithCheck.cpp index 19e24c90b..873a9f870 100644 --- a/doc/snippets/MatrixBase_computeInverseWithCheck.cpp +++ b/doc/snippets/MatrixBase_computeInverseWithCheck.cpp @@ -1,8 +1,10 @@ Matrix3d m = Matrix3d::Random(); cout << "Here is the matrix m:" << endl << m << endl; -Matrix3d inv; -if(m.computeInverseWithCheck(&inv)) { - cout << "It is invertible, and its inverse is:" << endl << inv << endl; +Matrix3d inverse; +bool invertible; +m.computeInverseWithCheck(inverse,invertible); +if(invertible) { + cout << "It is invertible, and its inverse is:" << endl << inverse << endl; } else { cout << "It is not invertible." << endl; diff --git a/doc/snippets/PartialLU_solve.cpp b/doc/snippets/PartialLU_solve.cpp index 12441437f..fa3570ab8 100644 --- a/doc/snippets/PartialLU_solve.cpp +++ b/doc/snippets/PartialLU_solve.cpp @@ -2,7 +2,6 @@ MatrixXd A = MatrixXd::Random(3,3); MatrixXd B = MatrixXd::Random(3,2); cout << "Here is the invertible matrix A:" << endl << A << endl; cout << "Here is the matrix B:" << endl << B << endl; -MatrixXd X; -if(A.lu().solve(B, &X)) +MatrixXd X = A.lu().solve(B); cout << "Here is the (unique) solution X to the equation AX=B:" << endl << X << endl; cout << "Relative error: " << (A*X-B).norm() / B.norm() << endl; diff --git a/doc/snippets/Tutorial_solve_multiple_rhs.cpp b/doc/snippets/Tutorial_solve_multiple_rhs.cpp index fbb15165a..72dab9075 100644 --- a/doc/snippets/Tutorial_solve_multiple_rhs.cpp +++ b/doc/snippets/Tutorial_solve_multiple_rhs.cpp @@ -3,7 +3,7 @@ A << 1,2,3, 4,5,6, 7,8,10; Matrix B; B << 3,1, 3,1, 4,1; Matrix X; -A.partialLu().solve(B, &X); +X = A.lu().solve(B); cout << "The solution with right-hand side (3,3,4) is:" << endl; cout << X.col(0) << endl; cout << "The solution with right-hand side (1,1,1) is:" << endl; diff --git a/doc/snippets/Tutorial_solve_reuse_decomposition.cpp b/doc/snippets/Tutorial_solve_reuse_decomposition.cpp index b4112adc4..3ca06453a 100644 --- a/doc/snippets/Tutorial_solve_reuse_decomposition.cpp +++ b/doc/snippets/Tutorial_solve_reuse_decomposition.cpp @@ -1,13 +1,13 @@ Matrix3f A(3,3); A << 1,2,3, 4,5,6, 7,8,10; -PartialLU luOfA(A); // compute LU decomposition of A +PartialPivLU luOfA(A); // compute LU decomposition of A Vector3f b; b << 3,3,4; Vector3f x; -luOfA.solve(b, &x); +x = luOfA.solve(b); cout << "The solution with right-hand side (3,3,4) is:" << endl; cout << x << endl; b << 1,1,1; -luOfA.solve(b, &x); +x = luOfA.solve(b); cout << "The solution with right-hand side (1,1,1) is:" << endl; cout << x << endl; diff --git a/doc/snippets/Tutorial_solve_singular.cpp b/doc/snippets/Tutorial_solve_singular.cpp index da94ad445..abff1ef73 100644 --- a/doc/snippets/Tutorial_solve_singular.cpp +++ b/doc/snippets/Tutorial_solve_singular.cpp @@ -5,5 +5,5 @@ b << 3, 3, 4; cout << "Here is the matrix A:" << endl << A << endl; cout << "Here is the vector b:" << endl << b << endl; Vector3f x; -A.partialLu().solve(b, &x); +x = A.lu().solve(b); cout << "The solution is:" << endl << x << endl; diff --git a/doc/snippets/class_LU.cpp b/doc/snippets/class_FullPivLU.cpp similarity index 95% rename from doc/snippets/class_LU.cpp rename to doc/snippets/class_FullPivLU.cpp index 9958368f1..40d76e8e6 100644 --- a/doc/snippets/class_LU.cpp +++ b/doc/snippets/class_FullPivLU.cpp @@ -2,7 +2,7 @@ typedef Matrix Matrix5x3; typedef Matrix Matrix5x5; Matrix5x3 m = Matrix5x3::Random(); cout << "Here is the matrix m:" << endl << m << endl; -Eigen::LU lu(m); +Eigen::FullPivLU lu(m); cout << "Here is, up to permutations, its LU decomposition matrix:" << endl << lu.matrixLU() << endl; cout << "Here is the L part:" << endl; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b46971493..0139f2d0b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,6 +3,8 @@ add_custom_target(btest) include(EigenTesting) ei_init_testing() +option(EIGEN_SPLIT_LARGE_TESTS "Split large tests into smaller executables" ON) + find_package(GSL) if(GSL_FOUND AND GSL_VERSION_MINOR LESS 9) set(GSL_FOUND "") diff --git a/test/adjoint.cpp b/test/adjoint.cpp index bebf47ac3..344399257 100644 --- a/test/adjoint.cpp +++ b/test/adjoint.cpp @@ -108,16 +108,17 @@ template void adjoint(const MatrixType& m) void test_adjoint() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( adjoint(Matrix()) ); - CALL_SUBTEST( adjoint(Matrix3d()) ); - CALL_SUBTEST( adjoint(Matrix4f()) ); - CALL_SUBTEST( adjoint(MatrixXcf(4, 4)) ); - CALL_SUBTEST( adjoint(MatrixXi(8, 12)) ); - CALL_SUBTEST( adjoint(MatrixXf(21, 21)) ); + CALL_SUBTEST_1( adjoint(Matrix()) ); + CALL_SUBTEST_2( adjoint(Matrix3d()) ); + CALL_SUBTEST_3( adjoint(Matrix4f()) ); + CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) ); + CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) ); + CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) ); } // test a large matrix only once - CALL_SUBTEST( adjoint(Matrix()) ); + CALL_SUBTEST_7( adjoint(Matrix()) ); +#ifdef EIGEN_TEST_PART_4 { MatrixXcf a(10,10), b(10,10); VERIFY_RAISES_ASSERT(a = a.transpose()); @@ -128,5 +129,6 @@ void test_adjoint() VERIFY_RAISES_ASSERT(a = a.adjoint() + b); VERIFY_RAISES_ASSERT(a = b + a.adjoint()); } +#endif } diff --git a/test/array.cpp b/test/array.cpp index a308f7366..a18724d3a 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -146,26 +146,26 @@ template void lpNorm(const VectorType& v) void test_array() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( array(Matrix()) ); - CALL_SUBTEST( array(Matrix2f()) ); - CALL_SUBTEST( array(Matrix4d()) ); - CALL_SUBTEST( array(MatrixXcf(3, 3)) ); - CALL_SUBTEST( array(MatrixXf(8, 12)) ); - CALL_SUBTEST( array(MatrixXi(8, 12)) ); + CALL_SUBTEST_1( array(Matrix()) ); + CALL_SUBTEST_2( array(Matrix2f()) ); + CALL_SUBTEST_3( array(Matrix4d()) ); + CALL_SUBTEST_4( array(MatrixXcf(3, 3)) ); + CALL_SUBTEST_5( array(MatrixXf(8, 12)) ); + CALL_SUBTEST_6( array(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( comparisons(Matrix()) ); - CALL_SUBTEST( comparisons(Matrix2f()) ); - CALL_SUBTEST( comparisons(Matrix4d()) ); - CALL_SUBTEST( comparisons(MatrixXf(8, 12)) ); - CALL_SUBTEST( comparisons(MatrixXi(8, 12)) ); + CALL_SUBTEST_1( comparisons(Matrix()) ); + CALL_SUBTEST_2( comparisons(Matrix2f()) ); + CALL_SUBTEST_3( comparisons(Matrix4d()) ); + CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) ); + CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( lpNorm(Matrix()) ); - CALL_SUBTEST( lpNorm(Vector2f()) ); - CALL_SUBTEST( lpNorm(Vector3d()) ); - CALL_SUBTEST( lpNorm(Vector4f()) ); - CALL_SUBTEST( lpNorm(VectorXf(16)) ); - CALL_SUBTEST( lpNorm(VectorXcd(10)) ); + CALL_SUBTEST_1( lpNorm(Matrix()) ); + CALL_SUBTEST_2( lpNorm(Vector2f()) ); + CALL_SUBTEST_7( lpNorm(Vector3d()) ); + CALL_SUBTEST_8( lpNorm(Vector4f()) ); + CALL_SUBTEST_5( lpNorm(VectorXf(16)) ); + CALL_SUBTEST_4( lpNorm(VectorXcf(10)) ); } } diff --git a/test/array_replicate.cpp b/test/array_replicate.cpp index cd0f65f26..a23ac7c6f 100644 --- a/test/array_replicate.cpp +++ b/test/array_replicate.cpp @@ -76,11 +76,11 @@ template void replicate(const MatrixType& m) void test_array_replicate() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( replicate(Matrix()) ); - CALL_SUBTEST( replicate(Vector2f()) ); - CALL_SUBTEST( replicate(Vector3d()) ); - CALL_SUBTEST( replicate(Vector4f()) ); - CALL_SUBTEST( replicate(VectorXf(16)) ); - CALL_SUBTEST( replicate(VectorXcd(10)) ); + CALL_SUBTEST_1( replicate(Matrix()) ); + CALL_SUBTEST_2( replicate(Vector2f()) ); + CALL_SUBTEST_3( replicate(Vector3d()) ); + CALL_SUBTEST_4( replicate(Vector4f()) ); + CALL_SUBTEST_5( replicate(VectorXf(16)) ); + CALL_SUBTEST_6( replicate(VectorXcd(10)) ); } } diff --git a/test/array_reverse.cpp b/test/array_reverse.cpp index e77842c7d..ccf8dcc87 100644 --- a/test/array_reverse.cpp +++ b/test/array_reverse.cpp @@ -163,19 +163,20 @@ template void reverse(const MatrixType& m) void test_array_reverse() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( reverse(Matrix()) ); - CALL_SUBTEST( reverse(Matrix2f()) ); - CALL_SUBTEST( reverse(Matrix4f()) ); - CALL_SUBTEST( reverse(Matrix4d()) ); - CALL_SUBTEST( reverse(MatrixXcf(3, 3)) ); - CALL_SUBTEST( reverse(MatrixXi(6, 3)) ); - CALL_SUBTEST( reverse(MatrixXcd(20, 20)) ); - CALL_SUBTEST( reverse(Matrix()) ); - CALL_SUBTEST( reverse(Matrix(6,3)) ); + CALL_SUBTEST_1( reverse(Matrix()) ); + CALL_SUBTEST_2( reverse(Matrix2f()) ); + CALL_SUBTEST_3( reverse(Matrix4f()) ); + CALL_SUBTEST_4( reverse(Matrix4d()) ); + CALL_SUBTEST_5( reverse(MatrixXcf(3, 3)) ); + CALL_SUBTEST_6( reverse(MatrixXi(6, 3)) ); + CALL_SUBTEST_7( reverse(MatrixXcd(20, 20)) ); + CALL_SUBTEST_8( reverse(Matrix()) ); + CALL_SUBTEST_9( reverse(Matrix(6,3)) ); } +#ifdef EIGEN_TEST_PART_3 Vector4f x; x << 1, 2, 3, 4; Vector4f y; y << 4, 3, 2, 1; VERIFY(x.reverse()[1] == 3); VERIFY(x.reverse() == y); - +#endif } diff --git a/test/bandmatrix.cpp b/test/bandmatrix.cpp index 2bdc67e28..ecb7304db 100644 --- a/test/bandmatrix.cpp +++ b/test/bandmatrix.cpp @@ -79,6 +79,6 @@ void test_bandmatrix() int cols = ei_random(1,10); int sups = ei_random(0,cols-1); int subs = ei_random(0,rows-1); - CALL_SUBTEST( bandmatrix(BandMatrix(rows,cols,sups,subs)) ); + CALL_SUBTEST(bandmatrix(BandMatrix(rows,cols,sups,subs)) ); } } diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp index 29df99f9e..4678439d5 100644 --- a/test/basicstuff.cpp +++ b/test/basicstuff.cpp @@ -146,17 +146,17 @@ void casting() void test_basicstuff() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( basicStuff(Matrix()) ); - CALL_SUBTEST( basicStuff(Matrix4d()) ); - CALL_SUBTEST( basicStuff(MatrixXcf(3, 3)) ); - CALL_SUBTEST( basicStuff(MatrixXi(8, 12)) ); - CALL_SUBTEST( basicStuff(MatrixXcd(20, 20)) ); - CALL_SUBTEST( basicStuff(Matrix()) ); - CALL_SUBTEST( basicStuff(Matrix(10,10)) ); + CALL_SUBTEST_1( basicStuff(Matrix()) ); + CALL_SUBTEST_2( basicStuff(Matrix4d()) ); + CALL_SUBTEST_3( basicStuff(MatrixXcf(3, 3)) ); + CALL_SUBTEST_4( basicStuff(MatrixXi(8, 12)) ); + CALL_SUBTEST_5( basicStuff(MatrixXcd(20, 20)) ); + CALL_SUBTEST_6( basicStuff(Matrix()) ); + CALL_SUBTEST_7( basicStuff(Matrix(10,10)) ); - CALL_SUBTEST( basicStuffComplex(MatrixXcf(21, 17)) ); - CALL_SUBTEST( basicStuffComplex(MatrixXcd(2, 3)) ); + CALL_SUBTEST_3( basicStuffComplex(MatrixXcf(21, 17)) ); + CALL_SUBTEST_5( basicStuffComplex(MatrixXcd(2, 3)) ); } - CALL_SUBTEST(casting()); + CALL_SUBTEST_2(casting()); } diff --git a/test/cholesky.cpp b/test/cholesky.cpp index 526a9f9d0..c3ef96752 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -22,7 +22,10 @@ // License and a copy of the GNU General Public License along with // Eigen. If not, see . +#ifndef EIGEN_NO_ASSERTION_CHECKING #define EIGEN_NO_ASSERTION_CHECKING +#endif + #include "main.h" #include #include @@ -93,17 +96,17 @@ template void cholesky(const MatrixType& m) { LLT chollo(symmLo); VERIFY_IS_APPROX(symm, chollo.matrixL().toDense() * chollo.matrixL().adjoint().toDense()); - chollo.solve(vecB, &vecX); + vecX = chollo.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); - chollo.solve(matB, &matX); + matX = chollo.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); // test the upper mode LLT cholup(symmUp); VERIFY_IS_APPROX(symm, cholup.matrixL().toDense() * cholup.matrixL().adjoint().toDense()); - cholup.solve(vecB, &vecX); + vecX = cholup.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); - cholup.solve(matB, &matX); + matX = cholup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); } @@ -118,9 +121,9 @@ template void cholesky(const MatrixType& m) LDLT ldlt(symm); // TODO(keir): This doesn't make sense now that LDLT pivots. //VERIFY_IS_APPROX(symm, ldlt.matrixL() * ldlt.vectorD().asDiagonal() * ldlt.matrixL().adjoint()); - ldlt.solve(vecB, &vecX); + vecX = ldlt.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); - ldlt.solve(matB, &matX); + matX = ldlt.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); } @@ -132,7 +135,7 @@ template void cholesky_verify_assert() LLT llt; VERIFY_RAISES_ASSERT(llt.matrixL()) - VERIFY_RAISES_ASSERT(llt.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(llt.solve(tmp)) VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp)) LDLT ldlt; @@ -141,24 +144,24 @@ template void cholesky_verify_assert() VERIFY_RAISES_ASSERT(ldlt.vectorD()) VERIFY_RAISES_ASSERT(ldlt.isPositive()) VERIFY_RAISES_ASSERT(ldlt.isNegative()) - VERIFY_RAISES_ASSERT(ldlt.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(ldlt.solve(tmp)) VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp)) } 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(200,200)) ); - CALL_SUBTEST( cholesky(MatrixXcd(100,100)) ); + CALL_SUBTEST_1( cholesky(Matrix()) ); + CALL_SUBTEST_2( cholesky(MatrixXd(1,1)) ); + CALL_SUBTEST_3( cholesky(Matrix2d()) ); + CALL_SUBTEST_4( cholesky(Matrix3f()) ); + CALL_SUBTEST_5( cholesky(Matrix4d()) ); + CALL_SUBTEST_2( cholesky(MatrixXd(200,200)) ); + CALL_SUBTEST_6( 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_4( cholesky_verify_assert() ); + CALL_SUBTEST_7( cholesky_verify_assert() ); + CALL_SUBTEST_8( cholesky_verify_assert() ); + CALL_SUBTEST_2( cholesky_verify_assert() ); } diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp index b92dd5449..a7b1f78ff 100644 --- a/test/conservative_resize.cpp +++ b/test/conservative_resize.cpp @@ -110,20 +110,20 @@ void run_vector_tests() 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>(); + CALL_SUBTEST_1((run_matrix_tests())); + CALL_SUBTEST_1((run_matrix_tests())); + CALL_SUBTEST_2((run_matrix_tests())); + CALL_SUBTEST_2((run_matrix_tests())); + CALL_SUBTEST_3((run_matrix_tests())); + CALL_SUBTEST_3((run_matrix_tests())); + CALL_SUBTEST_4((run_matrix_tests, Eigen::RowMajor>())); + CALL_SUBTEST_4((run_matrix_tests, Eigen::ColMajor>())); + CALL_SUBTEST_5((run_matrix_tests, Eigen::RowMajor>())); + CALL_SUBTEST_6((run_matrix_tests, Eigen::ColMajor>())); - run_vector_tests(); - run_vector_tests(); - run_vector_tests(); - run_vector_tests >(); - run_vector_tests >(); + CALL_SUBTEST_1((run_vector_tests())); + CALL_SUBTEST_2((run_vector_tests())); + CALL_SUBTEST_3((run_vector_tests())); + CALL_SUBTEST_4((run_vector_tests >())); + CALL_SUBTEST_5((run_vector_tests >())); } diff --git a/test/cwiseop.cpp b/test/cwiseop.cpp index 10784b0f5..7574bcc4a 100644 --- a/test/cwiseop.cpp +++ b/test/cwiseop.cpp @@ -163,11 +163,11 @@ template void cwiseops(const MatrixType& m) void test_cwiseop() { for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST( cwiseops(Matrix()) ); - CALL_SUBTEST( cwiseops(Matrix4d()) ); - CALL_SUBTEST( cwiseops(MatrixXf(3, 3)) ); - CALL_SUBTEST( cwiseops(MatrixXf(22, 22)) ); - CALL_SUBTEST( cwiseops(MatrixXi(8, 12)) ); - CALL_SUBTEST( cwiseops(MatrixXd(20, 20)) ); + CALL_SUBTEST_1( cwiseops(Matrix()) ); + CALL_SUBTEST_2( cwiseops(Matrix4d()) ); + CALL_SUBTEST_3( cwiseops(MatrixXf(3, 3)) ); + CALL_SUBTEST_4( cwiseops(MatrixXf(22, 22)) ); + CALL_SUBTEST_5( cwiseops(MatrixXi(8, 12)) ); + CALL_SUBTEST_6( cwiseops(MatrixXd(20, 20)) ); } } diff --git a/test/determinant.cpp b/test/determinant.cpp index d9de5f6ce..7aa9a870d 100644 --- a/test/determinant.cpp +++ b/test/determinant.cpp @@ -65,12 +65,12 @@ template void determinant(const MatrixType& m) void test_determinant() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( determinant(Matrix()) ); - CALL_SUBTEST( determinant(Matrix()) ); - CALL_SUBTEST( determinant(Matrix()) ); - CALL_SUBTEST( determinant(Matrix()) ); - CALL_SUBTEST( determinant(Matrix, 10, 10>()) ); - CALL_SUBTEST( determinant(MatrixXd(20, 20)) ); + CALL_SUBTEST_1( determinant(Matrix()) ); + CALL_SUBTEST_2( determinant(Matrix()) ); + CALL_SUBTEST_3( determinant(Matrix()) ); + CALL_SUBTEST_4( determinant(Matrix()) ); + CALL_SUBTEST_5( determinant(Matrix, 10, 10>()) ); + CALL_SUBTEST_6( determinant(MatrixXd(20, 20)) ); } - CALL_SUBTEST( determinant(MatrixXd(200, 200)) ); + CALL_SUBTEST_6( determinant(MatrixXd(200, 200)) ); } diff --git a/test/diagonalmatrices.cpp b/test/diagonalmatrices.cpp index 9eb0f10f2..c24c66d03 100644 --- a/test/diagonalmatrices.cpp +++ b/test/diagonalmatrices.cpp @@ -95,14 +95,14 @@ template void diagonalmatrices(const MatrixType& m) void test_diagonalmatrices() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( diagonalmatrices(Matrix()) ); - CALL_SUBTEST( diagonalmatrices(Matrix3f()) ); - CALL_SUBTEST( diagonalmatrices(Matrix()) ); - CALL_SUBTEST( diagonalmatrices(Matrix4d()) ); - CALL_SUBTEST( diagonalmatrices(Matrix()) ); - CALL_SUBTEST( diagonalmatrices(MatrixXcf(3, 5)) ); - CALL_SUBTEST( diagonalmatrices(MatrixXi(10, 8)) ); - CALL_SUBTEST( diagonalmatrices(Matrix(20, 20)) ); - CALL_SUBTEST( diagonalmatrices(MatrixXf(21, 24)) ); + CALL_SUBTEST_1( diagonalmatrices(Matrix()) ); + CALL_SUBTEST_2( diagonalmatrices(Matrix3f()) ); + CALL_SUBTEST_3( diagonalmatrices(Matrix()) ); + CALL_SUBTEST_4( diagonalmatrices(Matrix4d()) ); + CALL_SUBTEST_5( diagonalmatrices(Matrix()) ); + CALL_SUBTEST_6( diagonalmatrices(MatrixXcf(3, 5)) ); + CALL_SUBTEST_7( diagonalmatrices(MatrixXi(10, 8)) ); + CALL_SUBTEST_8( diagonalmatrices(Matrix(20, 20)) ); + CALL_SUBTEST_9( diagonalmatrices(MatrixXf(21, 24)) ); } } diff --git a/test/dynalloc.cpp b/test/dynalloc.cpp index 08fc0369d..e0a9f9f86 100644 --- a/test/dynalloc.cpp +++ b/test/dynalloc.cpp @@ -112,11 +112,11 @@ void test_dynalloc() for (int i=0; i() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); + CALL_SUBTEST(check_dynaligned() ); + CALL_SUBTEST(check_dynaligned() ); + CALL_SUBTEST(check_dynaligned() ); + CALL_SUBTEST(check_dynaligned() ); + CALL_SUBTEST(check_dynaligned() ); } // check static allocation, who knows ? diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index e1ce575e1..756527d57 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -58,7 +58,7 @@ 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(14,14)) ); + CALL_SUBTEST_1( eigensolver(Matrix4cf()) ); + CALL_SUBTEST_2( eigensolver(MatrixXcd(14,14)) ); } } diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index e2b2055b4..5dc18f141 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -75,18 +75,18 @@ template void eigensolver_verify_assert() void test_eigensolver_generic() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( eigensolver(Matrix4f()) ); - CALL_SUBTEST( eigensolver(MatrixXd(17,17)) ); + CALL_SUBTEST_1( eigensolver(Matrix4f()) ); + CALL_SUBTEST_2( eigensolver(MatrixXd(17,17)) ); // some trivial but implementation-wise tricky cases - CALL_SUBTEST( eigensolver(MatrixXd(1,1)) ); - CALL_SUBTEST( eigensolver(MatrixXd(2,2)) ); - CALL_SUBTEST( eigensolver(Matrix()) ); - CALL_SUBTEST( eigensolver(Matrix()) ); + CALL_SUBTEST_2( eigensolver(MatrixXd(1,1)) ); + CALL_SUBTEST_2( eigensolver(MatrixXd(2,2)) ); + CALL_SUBTEST_3( eigensolver(Matrix()) ); + CALL_SUBTEST_4( eigensolver(Matrix2d()) ); } - CALL_SUBTEST( eigensolver_verify_assert() ); - CALL_SUBTEST( eigensolver_verify_assert() ); - CALL_SUBTEST( eigensolver_verify_assert() ); - CALL_SUBTEST( eigensolver_verify_assert() ); + CALL_SUBTEST_1( eigensolver_verify_assert() ); + CALL_SUBTEST_2( eigensolver_verify_assert() ); + CALL_SUBTEST_4( eigensolver_verify_assert() ); + CALL_SUBTEST_5( eigensolver_verify_assert() ); } diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 3836c074b..632c1d2e7 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -117,17 +117,17 @@ void test_eigensolver_selfadjoint() { for(int i = 0; i < g_repeat; i++) { // very important to test a 3x3 matrix since we provide a special path for it - CALL_SUBTEST( selfadjointeigensolver(Matrix3f()) ); - CALL_SUBTEST( selfadjointeigensolver(Matrix4d()) ); - CALL_SUBTEST( selfadjointeigensolver(MatrixXf(10,10)) ); - CALL_SUBTEST( selfadjointeigensolver(MatrixXd(19,19)) ); - CALL_SUBTEST( selfadjointeigensolver(MatrixXcd(17,17)) ); + CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) ); + CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) ); + CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(10,10)) ); + CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(19,19)) ); + CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(17,17)) ); // some trivial but implementation-wise tricky cases - CALL_SUBTEST( selfadjointeigensolver(MatrixXd(1,1)) ); - CALL_SUBTEST( selfadjointeigensolver(MatrixXd(2,2)) ); - CALL_SUBTEST( selfadjointeigensolver(Matrix()) ); - CALL_SUBTEST( selfadjointeigensolver(Matrix()) ); + CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) ); + CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(2,2)) ); + CALL_SUBTEST_6( selfadjointeigensolver(Matrix()) ); + CALL_SUBTEST_7( selfadjointeigensolver(Matrix()) ); } } diff --git a/test/geo_alignedbox.cpp b/test/geo_alignedbox.cpp index 07b3e59e6..d496578da 100644 --- a/test/geo_alignedbox.cpp +++ b/test/geo_alignedbox.cpp @@ -75,8 +75,8 @@ template void alignedbox(const BoxType& _box) void test_geo_alignedbox() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( alignedbox(AlignedBox()) ); - CALL_SUBTEST( alignedbox(AlignedBox()) ); - CALL_SUBTEST( alignedbox(AlignedBox()) ); + CALL_SUBTEST_1( alignedbox(AlignedBox()) ); + CALL_SUBTEST_2( alignedbox(AlignedBox()) ); + CALL_SUBTEST_3( alignedbox(AlignedBox()) ); } } diff --git a/test/geo_eulerangles.cpp b/test/geo_eulerangles.cpp index f11c8e8ef..98cdf6a86 100644 --- a/test/geo_eulerangles.cpp +++ b/test/geo_eulerangles.cpp @@ -64,7 +64,7 @@ template void eulerangles(void) void test_geo_eulerangles() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( eulerangles() ); - CALL_SUBTEST( eulerangles() ); + CALL_SUBTEST_1( eulerangles() ); + CALL_SUBTEST_2( eulerangles() ); } } diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp index 4b66e488c..48d8cbcdf 100644 --- a/test/geo_homogeneous.cpp +++ b/test/geo_homogeneous.cpp @@ -104,8 +104,8 @@ template void homogeneous(void) void test_geo_homogeneous() { for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST(( homogeneous() )); - CALL_SUBTEST(( homogeneous() )); -// CALL_SUBTEST(( homogeneous() )); + CALL_SUBTEST_1(( homogeneous() )); + CALL_SUBTEST_2(( homogeneous() )); + CALL_SUBTEST_3(( homogeneous() )); } } diff --git a/test/geo_hyperplane.cpp b/test/geo_hyperplane.cpp index 010989feb..3cf5655c2 100644 --- a/test/geo_hyperplane.cpp +++ b/test/geo_hyperplane.cpp @@ -131,11 +131,11 @@ template void lines() void test_geo_hyperplane() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( hyperplane(Hyperplane()) ); - CALL_SUBTEST( hyperplane(Hyperplane()) ); - CALL_SUBTEST( hyperplane(Hyperplane()) ); - CALL_SUBTEST( hyperplane(Hyperplane,5>()) ); - CALL_SUBTEST( lines() ); - CALL_SUBTEST( lines() ); + CALL_SUBTEST_1( hyperplane(Hyperplane()) ); + CALL_SUBTEST_2( hyperplane(Hyperplane()) ); + CALL_SUBTEST_3( hyperplane(Hyperplane()) ); + CALL_SUBTEST_4( hyperplane(Hyperplane,5>()) ); + CALL_SUBTEST_1( lines() ); + CALL_SUBTEST_2( lines() ); } } diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp index 540a63b82..54a6febab 100644 --- a/test/geo_orthomethods.cpp +++ b/test/geo_orthomethods.cpp @@ -113,15 +113,15 @@ template void orthomethods(int size=Size) void test_geo_orthomethods() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( orthomethods_3() ); - CALL_SUBTEST( orthomethods_3() ); - CALL_SUBTEST( (orthomethods()) ); - CALL_SUBTEST( (orthomethods()) ); - CALL_SUBTEST( (orthomethods()) ); - CALL_SUBTEST( (orthomethods()) ); - CALL_SUBTEST( (orthomethods()) ); - CALL_SUBTEST( (orthomethods,8>()) ); - CALL_SUBTEST( (orthomethods(36)) ); - CALL_SUBTEST( (orthomethods(35)) ); + CALL_SUBTEST_1( orthomethods_3() ); + CALL_SUBTEST_2( orthomethods_3() ); + CALL_SUBTEST_1( (orthomethods()) ); + CALL_SUBTEST_2( (orthomethods()) ); + CALL_SUBTEST_1( (orthomethods()) ); + CALL_SUBTEST_2( (orthomethods()) ); + CALL_SUBTEST_3( (orthomethods()) ); + CALL_SUBTEST_4( (orthomethods,8>()) ); + CALL_SUBTEST_5( (orthomethods(36)) ); + CALL_SUBTEST_6( (orthomethods(35)) ); } } diff --git a/test/geo_parametrizedline.cpp b/test/geo_parametrizedline.cpp index c90d59d3e..137324a98 100644 --- a/test/geo_parametrizedline.cpp +++ b/test/geo_parametrizedline.cpp @@ -69,9 +69,9 @@ template void parametrizedline(const LineType& _line) void test_geo_parametrizedline() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST( parametrizedline(ParametrizedLine,5>()) ); + CALL_SUBTEST_1( parametrizedline(ParametrizedLine()) ); + CALL_SUBTEST_2( parametrizedline(ParametrizedLine()) ); + CALL_SUBTEST_3( parametrizedline(ParametrizedLine()) ); + CALL_SUBTEST_4( parametrizedline(ParametrizedLine,5>()) ); } } diff --git a/test/geo_quaternion.cpp b/test/geo_quaternion.cpp index 762743fba..7dbf890f4 100644 --- a/test/geo_quaternion.cpp +++ b/test/geo_quaternion.cpp @@ -92,9 +92,12 @@ template void quaternion(void) VERIFY_IS_APPROX( v2.normalized(),(q2.setFromTwoVectors(v1, v2)*v1).normalized()); VERIFY_IS_APPROX( v1.normalized(),(q2.setFromTwoVectors(v1, v1)*v1).normalized()); VERIFY_IS_APPROX(-v1.normalized(),(q2.setFromTwoVectors(v1,-v1)*v1).normalized()); - v3 = v1.cwise()+eps; - VERIFY_IS_APPROX( v3.normalized(),(q2.setFromTwoVectors(v1, v3)*v1).normalized()); - VERIFY_IS_APPROX(-v3.normalized(),(q2.setFromTwoVectors(v1,-v3)*v1).normalized()); + if (ei_is_same_type::ret) + { + v3 = v1.cwise()+eps; + VERIFY_IS_APPROX( v3.normalized(),(q2.setFromTwoVectors(v1, v3)*v1).normalized()); + VERIFY_IS_APPROX(-v3.normalized(),(q2.setFromTwoVectors(v1,-v3)*v1).normalized()); + } // inverse and conjugate VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1); @@ -110,7 +113,7 @@ template void quaternion(void) void test_geo_quaternion() { for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST( quaternion() ); - CALL_SUBTEST( quaternion() ); + CALL_SUBTEST_1( quaternion() ); + CALL_SUBTEST_2( quaternion() ); } } diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index 23b297314..f1d068b83 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -298,16 +298,19 @@ template void transformations(void) VERIFY_IS_APPROX((t0 * v1).template start<3>(), AlignedScaling3(v0) * v1); // test transform inversion - if(Mode!=AffineCompact) - { - t0.setIdentity(); - t0.translate(v0); - t0.linear().setRandom(); - VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t0.matrix().inverse()); - t0.setIdentity(); - t0.translate(v0).rotate(q1); - VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t0.matrix().inverse()); - } + t0.setIdentity(); + t0.translate(v0); + t0.linear().setRandom(); + Matrix4 t044 = Matrix4::Zero(); + t044(3,3) = 1; + t044.block(0,0,t0.matrix().rows(),4) = t0.matrix(); + VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4)); + t0.setIdentity(); + t0.translate(v0).rotate(q1); + t044 = Matrix4::Zero(); + t044(3,3) = 1; + t044.block(0,0,t0.matrix().rows(),4) = t0.matrix(); + VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4)); // test extract rotation and aligned scaling // t0.setIdentity(); @@ -354,9 +357,8 @@ template void transformations(void) void test_geo_transformations() { for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST( transformations() ); - CALL_SUBTEST(( transformations() )); - CALL_SUBTEST(( transformations() )); - CALL_SUBTEST(( transformations() )); + CALL_SUBTEST_1(( transformations() )); + CALL_SUBTEST_2(( transformations() )); + CALL_SUBTEST_3(( transformations() )); } } diff --git a/test/householder.cpp b/test/householder.cpp index b27279479..c9b07622d 100644 --- a/test/householder.cpp +++ b/test/householder.cpp @@ -92,12 +92,12 @@ template void householder(const MatrixType& m) void test_householder() { for(int i = 0; i < 2*g_repeat; i++) { - CALL_SUBTEST( householder(Matrix()) ); - CALL_SUBTEST( householder(Matrix()) ); - CALL_SUBTEST( householder(Matrix()) ); - CALL_SUBTEST( householder(Matrix()) ); - CALL_SUBTEST( householder(MatrixXd(10,12)) ); - CALL_SUBTEST( householder(MatrixXcf(16,17)) ); + CALL_SUBTEST_1( householder(Matrix()) ); + CALL_SUBTEST_2( householder(Matrix()) ); + CALL_SUBTEST_3( householder(Matrix()) ); + CALL_SUBTEST_4( householder(Matrix()) ); + CALL_SUBTEST_5( householder(MatrixXd(10,12)) ); + CALL_SUBTEST_6( householder(MatrixXcf(16,17)) ); } } diff --git a/test/inverse.cpp b/test/inverse.cpp index 65dfbc73e..3ed61d356 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -53,9 +53,6 @@ template void inverse(const MatrixType& m) m2 = m1.inverse(); VERIFY_IS_APPROX(m1, m2.inverse() ); - m1.computeInverse(&m2); - VERIFY_IS_APPROX(m1, m2.inverse() ); - VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5)); VERIFY_IS_APPROX(identity, m1.inverse() * m1 ); @@ -66,36 +63,53 @@ template void inverse(const MatrixType& m) // since for the general case we implement separately row-major and col-major, test that VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose()); - //computeInverseWithCheck tests +#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6) + //computeInverseAndDetWithCheck tests //First: an invertible matrix - bool invertible = m1.computeInverseWithCheck(&m2); + bool invertible; + RealScalar det; + + m2.setZero(); + m1.computeInverseAndDetWithCheck(m2, det, invertible); + VERIFY(invertible); + VERIFY_IS_APPROX(identity, m1*m2); + VERIFY_IS_APPROX(det, m1.determinant()); + + m2.setZero(); + m1.computeInverseWithCheck(m2, invertible); VERIFY(invertible); VERIFY_IS_APPROX(identity, m1*m2); //Second: a rank one matrix (not invertible, except for 1x1 matrices) VectorType v3 = VectorType::Random(rows); MatrixType m3 = v3*v3.transpose(), m4(rows,cols); - invertible = m3.computeInverseWithCheck( &m4 ); + m3.computeInverseAndDetWithCheck(m4, det, invertible); VERIFY( rows==1 ? invertible : !invertible ); + VERIFY_IS_APPROX(det, m3.determinant()); + m3.computeInverseWithCheck(m4, invertible); + VERIFY( rows==1 ? invertible : !invertible ); +#endif } void test_inverse() { int s; for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( inverse(Matrix()) ); - CALL_SUBTEST( inverse(Matrix2d()) ); - CALL_SUBTEST( inverse(Matrix3f()) ); - CALL_SUBTEST( inverse(Matrix4f()) ); + CALL_SUBTEST_1( inverse(Matrix()) ); + CALL_SUBTEST_2( inverse(Matrix2d()) ); + CALL_SUBTEST_3( inverse(Matrix3f()) ); + CALL_SUBTEST_4( inverse(Matrix4f()) ); s = ei_random(50,320); - CALL_SUBTEST( inverse(MatrixXf(s,s)) ); + CALL_SUBTEST_5( inverse(MatrixXf(s,s)) ); s = ei_random(25,100); - CALL_SUBTEST( inverse(MatrixXcd(s,s)) ); + CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) ); } +#ifdef EIGEN_TEST_PART_4 // test some tricky cases for 4x4 matrices VERIFY_IS_APPROX((Matrix4f() << 0,0,1,0, 1,0,0,0, 0,1,0,0, 0,0,0,1).finished().inverse(), (Matrix4f() << 0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,1).finished()); VERIFY_IS_APPROX((Matrix4f() << 1,0,0,0, 0,0,1,0, 0,0,0,1, 0,1,0,0).finished().inverse(), (Matrix4f() << 1,0,0,0, 0,0,0,1, 0,1,0,0, 0,0,1,0).finished()); +#endif } diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 2e3f089a0..f3a143e3c 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -80,27 +80,27 @@ void test_jacobisvd() Matrix2cd m; m << 0, 1, 0, 1; - CALL_SUBTEST(( svd(m, false) )); + CALL_SUBTEST_1(( svd(m, false) )); m << 1, 0, 1, 0; - CALL_SUBTEST(( svd(m, false) )); + CALL_SUBTEST_1(( svd(m, false) )); Matrix2d n; n << 1, 1, 1, -1; - CALL_SUBTEST(( svd(n, false) )); - CALL_SUBTEST(( svd() )); - CALL_SUBTEST(( svd() )); - CALL_SUBTEST(( svd , AtLeastAsManyColsAsRows>() )); - CALL_SUBTEST(( svd , AtLeastAsManyRowsAsCols>(Matrix(10,2)) )); + CALL_SUBTEST_2(( svd(n, false) )); + CALL_SUBTEST_3(( svd() )); + CALL_SUBTEST_4(( svd() )); + CALL_SUBTEST_5(( svd , AtLeastAsManyColsAsRows>() )); + CALL_SUBTEST_6(( svd , AtLeastAsManyRowsAsCols>(Matrix(10,2)) )); - CALL_SUBTEST(( svd(MatrixXf(50,50)) )); - CALL_SUBTEST(( svd(MatrixXcd(14,7)) )); + CALL_SUBTEST_7(( svd(MatrixXf(50,50)) )); + CALL_SUBTEST_8(( svd(MatrixXcd(14,7)) )); } - CALL_SUBTEST(( svd(MatrixXf(300,200)) )); - CALL_SUBTEST(( svd(MatrixXcd(100,150)) )); + CALL_SUBTEST_9(( svd(MatrixXf(300,200)) )); + CALL_SUBTEST_10(( 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_3(( svd_verify_assert() )); + CALL_SUBTEST_3(( svd_verify_assert() )); + CALL_SUBTEST_9(( svd_verify_assert() )); + CALL_SUBTEST_11(( svd_verify_assert() )); } diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp index 8827c40d1..f2ffc33bd 100644 --- a/test/linearstructure.cpp +++ b/test/linearstructure.cpp @@ -87,13 +87,13 @@ template void linearStructure(const MatrixType& m) void test_linearstructure() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( linearStructure(Matrix()) ); - CALL_SUBTEST( linearStructure(Matrix2f()) ); - CALL_SUBTEST( linearStructure(Vector3d()) ); - CALL_SUBTEST( linearStructure(Matrix4d()) ); - CALL_SUBTEST( linearStructure(MatrixXcf(3, 3)) ); - CALL_SUBTEST( linearStructure(MatrixXf(8, 12)) ); - CALL_SUBTEST( linearStructure(MatrixXi(8, 12)) ); - CALL_SUBTEST( linearStructure(MatrixXcd(20, 20)) ); + CALL_SUBTEST_1( linearStructure(Matrix()) ); + CALL_SUBTEST_2( linearStructure(Matrix2f()) ); + CALL_SUBTEST_3( linearStructure(Vector3d()) ); + CALL_SUBTEST_4( linearStructure(Matrix4d()) ); + CALL_SUBTEST_5( linearStructure(MatrixXcf(3, 3)) ); + CALL_SUBTEST_6( linearStructure(MatrixXf(8, 12)) ); + CALL_SUBTEST_7( linearStructure(MatrixXi(8, 12)) ); + CALL_SUBTEST_8( linearStructure(MatrixXcd(20, 20)) ); } } diff --git a/test/lu.cpp b/test/lu.cpp index 75680b96b..9dcebbeaa 100644 --- a/test/lu.cpp +++ b/test/lu.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Benoit Jacob +// Copyright (C) 2008-2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -30,15 +30,44 @@ template void lu_non_invertible() /* this test covers the following files: LU.h */ - int rows = ei_random(20,200), cols = ei_random(20,200), cols2 = ei_random(20,200); + int rows, cols, cols2; + if(MatrixType::RowsAtCompileTime==Dynamic) + { + rows = ei_random(20,200); + } + else + { + rows = MatrixType::RowsAtCompileTime; + } + if(MatrixType::ColsAtCompileTime==Dynamic) + { + cols = ei_random(20,200); + cols2 = ei_random(20,200); + } + else + { + cols2 = cols = MatrixType::ColsAtCompileTime; + } + + typedef typename ei_kernel_retval_base >::ReturnMatrixType KernelMatrixType; + typedef typename ei_image_retval_base >::ReturnMatrixType ImageMatrixType; + typedef Matrix DynamicMatrixType; + typedef Matrix + CMatrixType; + int rank = ei_random(1, std::min(rows, cols)-1); - MatrixType m1(rows, cols), m2(cols, cols2), m3(rows, cols2), k(1,1); + // The image of the zero matrix should consist of a single (zero) column vector + VERIFY((MatrixType::Zero(rows,cols).fullPivLu().image(MatrixType::Zero(rows,cols)).cols() == 1)); + + MatrixType m1(rows, cols), m3(rows, cols2); + CMatrixType m2(cols, cols2); createRandomMatrixOfRank(rank, rows, cols, m1); - LU lu(m1); - typename LU::KernelResultType m1kernel = lu.kernel(); - typename LU::ImageResultType m1image = lu.image(); + FullPivLU lu(m1); + std::cout << lu.kernel().rows() << " " << lu.kernel().cols() << std::endl; + KernelMatrixType m1kernel = lu.kernel(); + ImageMatrixType m1image = lu.image(m1); VERIFY(rank == lu.rank()); VERIFY(cols - lu.rank() == lu.dimensionOfKernel()); @@ -46,22 +75,16 @@ template void lu_non_invertible() VERIFY(!lu.isInvertible()); VERIFY(!lu.isSurjective()); VERIFY((m1 * m1kernel).isMuchSmallerThan(m1)); - VERIFY(m1image.lu().rank() == rank); - MatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols()); + VERIFY(m1image.fullPivLu().rank() == rank); + DynamicMatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols()); sidebyside << m1, m1image; - VERIFY(sidebyside.lu().rank() == rank); - m2 = MatrixType::Random(cols,cols2); + VERIFY(sidebyside.fullPivLu().rank() == rank); + m2 = CMatrixType::Random(cols,cols2); m3 = m1*m2; - m2 = MatrixType::Random(cols,cols2); - VERIFY(lu.solve(m3, &m2)); + m2 = CMatrixType::Random(cols,cols2); + // test that the code, which does resize(), may be applied to an xpr + m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); - m3 = MatrixType::Random(rows,cols2); - VERIFY(!lu.solve(m3, &m2)); - - typedef Matrix SquareMatrixType; - SquareMatrixType m4(rows, rows), m5(rows, rows); - createRandomMatrixOfRank(rows/2, rows, rows, m4); - VERIFY(!m4.computeInverseWithCheck(&m5)); } template void lu_invertible() @@ -82,69 +105,70 @@ template void lu_invertible() m1 += a * a.adjoint(); } - LU lu(m1); + FullPivLU lu(m1); VERIFY(0 == lu.dimensionOfKernel()); + VERIFY(lu.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector VERIFY(size == lu.rank()); VERIFY(lu.isInjective()); VERIFY(lu.isSurjective()); VERIFY(lu.isInvertible()); - VERIFY(lu.image().lu().isInvertible()); + VERIFY(lu.image(m1).fullPivLu().isInvertible()); m3 = MatrixType::Random(size,size); - lu.solve(m3, &m2); + m2 = lu.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); VERIFY_IS_APPROX(m2, lu.inverse()*m3); - m3 = MatrixType::Random(size,size); - VERIFY(lu.solve(m3, &m2)); } template void lu_verify_assert() { MatrixType tmp; - LU lu; + FullPivLU lu; VERIFY_RAISES_ASSERT(lu.matrixLU()) VERIFY_RAISES_ASSERT(lu.permutationP()) VERIFY_RAISES_ASSERT(lu.permutationQ()) - VERIFY_RAISES_ASSERT(lu.computeKernel(&tmp)) - VERIFY_RAISES_ASSERT(lu.computeImage(&tmp)) VERIFY_RAISES_ASSERT(lu.kernel()) - VERIFY_RAISES_ASSERT(lu.image()) - VERIFY_RAISES_ASSERT(lu.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(lu.image(tmp)) + VERIFY_RAISES_ASSERT(lu.solve(tmp)) VERIFY_RAISES_ASSERT(lu.determinant()) VERIFY_RAISES_ASSERT(lu.rank()) VERIFY_RAISES_ASSERT(lu.dimensionOfKernel()) VERIFY_RAISES_ASSERT(lu.isInjective()) VERIFY_RAISES_ASSERT(lu.isSurjective()) VERIFY_RAISES_ASSERT(lu.isInvertible()) - VERIFY_RAISES_ASSERT(lu.computeInverse(&tmp)) VERIFY_RAISES_ASSERT(lu.inverse()) - PartialLU plu; + PartialPivLU plu; VERIFY_RAISES_ASSERT(plu.matrixLU()) VERIFY_RAISES_ASSERT(plu.permutationP()) - VERIFY_RAISES_ASSERT(plu.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(plu.solve(tmp)) VERIFY_RAISES_ASSERT(plu.determinant()) - VERIFY_RAISES_ASSERT(plu.computeInverse(&tmp)) VERIFY_RAISES_ASSERT(plu.inverse()) } void test_lu() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( lu_non_invertible() ); - CALL_SUBTEST( lu_non_invertible() ); - CALL_SUBTEST( lu_non_invertible() ); - CALL_SUBTEST( lu_non_invertible() ); - CALL_SUBTEST( lu_invertible() ); - CALL_SUBTEST( lu_invertible() ); - CALL_SUBTEST( lu_invertible() ); - CALL_SUBTEST( lu_invertible() ); - } + CALL_SUBTEST_1( lu_non_invertible() ); + CALL_SUBTEST_1( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); - CALL_SUBTEST( lu_verify_assert() ); + CALL_SUBTEST_2( (lu_non_invertible >()) ); + CALL_SUBTEST_2( (lu_verify_assert >()) ); + + CALL_SUBTEST_3( lu_non_invertible() ); + CALL_SUBTEST_3( lu_invertible() ); + CALL_SUBTEST_3( lu_verify_assert() ); + + CALL_SUBTEST_4( lu_non_invertible() ); + CALL_SUBTEST_4( lu_invertible() ); + CALL_SUBTEST_4( lu_verify_assert() ); + + CALL_SUBTEST_5( lu_non_invertible() ); + CALL_SUBTEST_5( lu_invertible() ); + CALL_SUBTEST_5( lu_verify_assert() ); + + CALL_SUBTEST_6( lu_non_invertible() ); + CALL_SUBTEST_6( lu_invertible() ); + CALL_SUBTEST_6( lu_verify_assert() ); + } } diff --git a/test/main.h b/test/main.h index 51b719814..0b9b0bc4c 100644 --- a/test/main.h +++ b/test/main.h @@ -170,6 +170,102 @@ namespace Eigen g_test_stack.pop_back(); \ } while (0) +#ifdef EIGEN_TEST_PART_1 +#define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_1(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_2 +#define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_2(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_3 +#define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_3(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_4 +#define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_4(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_5 +#define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_5(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_6 +#define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_6(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_7 +#define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_7(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_8 +#define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_8(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_9 +#define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_9(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_10 +#define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_10(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_11 +#define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_11(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_12 +#define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_12(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_13 +#define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_13(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_14 +#define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_14(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_15 +#define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_15(FUNC) +#endif + +#ifdef EIGEN_TEST_PART_16 +#define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC) +#else +#define CALL_SUBTEST_16(FUNC) +#endif + namespace Eigen { template inline typename NumTraits::Real test_precision(); diff --git a/test/map.cpp b/test/map.cpp index fbff647f6..18c6b2694 100644 --- a/test/map.cpp +++ b/test/map.cpp @@ -81,16 +81,16 @@ template void map_static_methods(const VectorType& m) void test_map() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( map_class(Matrix()) ); - CALL_SUBTEST( map_class(Vector4d()) ); - CALL_SUBTEST( map_class(RowVector4f()) ); - CALL_SUBTEST( map_class(VectorXcf(8)) ); - CALL_SUBTEST( map_class(VectorXi(12)) ); + CALL_SUBTEST_1( map_class(Matrix()) ); + CALL_SUBTEST_2( map_class(Vector4d()) ); + CALL_SUBTEST_3( map_class(RowVector4f()) ); + CALL_SUBTEST_4( map_class(VectorXcf(8)) ); + CALL_SUBTEST_5( map_class(VectorXi(12)) ); - CALL_SUBTEST( map_static_methods(Matrix()) ); - CALL_SUBTEST( map_static_methods(Vector3f()) ); - CALL_SUBTEST( map_static_methods(RowVector3d()) ); - CALL_SUBTEST( map_static_methods(VectorXcd(8)) ); - CALL_SUBTEST( map_static_methods(VectorXf(12)) ); + CALL_SUBTEST_6( map_static_methods(Matrix()) ); + CALL_SUBTEST_7( map_static_methods(Vector3f()) ); + CALL_SUBTEST_8( map_static_methods(RowVector3d()) ); + CALL_SUBTEST_9( map_static_methods(VectorXcd(8)) ); + CALL_SUBTEST_10( map_static_methods(VectorXf(12)) ); } } diff --git a/test/miscmatrices.cpp b/test/miscmatrices.cpp index bf885e252..0adccf5ce 100644 --- a/test/miscmatrices.cpp +++ b/test/miscmatrices.cpp @@ -54,10 +54,10 @@ template void miscMatrices(const MatrixType& m) void test_miscmatrices() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( miscMatrices(Matrix()) ); - CALL_SUBTEST( miscMatrices(Matrix4d()) ); - CALL_SUBTEST( miscMatrices(MatrixXcf(3, 3)) ); - CALL_SUBTEST( miscMatrices(MatrixXi(8, 12)) ); - CALL_SUBTEST( miscMatrices(MatrixXcd(20, 20)) ); + CALL_SUBTEST_1( miscMatrices(Matrix()) ); + CALL_SUBTEST_2( miscMatrices(Matrix4d()) ); + CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) ); + CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) ); + CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) ); } } diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 3e322c7fe..1dcd77a8a 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -174,10 +174,10 @@ template void mixingtypes_small() 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_1(mixingtypes<3>()); + CALL_SUBTEST_2(mixingtypes<4>()); + CALL_SUBTEST_3(mixingtypes(20)); - CALL_SUBTEST(mixingtypes_small<4>()); - CALL_SUBTEST(mixingtypes_large(20)); + CALL_SUBTEST_4(mixingtypes_small<4>()); + CALL_SUBTEST_5(mixingtypes_large(20)); } diff --git a/test/nomalloc.cpp b/test/nomalloc.cpp index a96bb23da..1a917192b 100644 --- a/test/nomalloc.cpp +++ b/test/nomalloc.cpp @@ -77,7 +77,7 @@ void test_nomalloc() { // check that our operator new is indeed called: VERIFY_RAISES_ASSERT(MatrixXd dummy = MatrixXd::Random(3,3)); - CALL_SUBTEST( nomalloc(Matrix()) ); - CALL_SUBTEST( nomalloc(Matrix4d()) ); - CALL_SUBTEST( nomalloc(Matrix()) ); + CALL_SUBTEST(nomalloc(Matrix()) ); + CALL_SUBTEST(nomalloc(Matrix4d()) ); + CALL_SUBTEST(nomalloc(Matrix()) ); } diff --git a/test/packetmath.cpp b/test/packetmath.cpp index 1745ae5c6..7d863e616 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -233,12 +233,12 @@ template void packetmath_real() void test_packetmath() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( packetmath() ); - CALL_SUBTEST( packetmath() ); - CALL_SUBTEST( packetmath() ); - CALL_SUBTEST( packetmath >() ); + CALL_SUBTEST_1( packetmath() ); + CALL_SUBTEST_2( packetmath() ); + CALL_SUBTEST_3( packetmath() ); + CALL_SUBTEST_1( packetmath >() ); - CALL_SUBTEST( packetmath_real() ); - CALL_SUBTEST( packetmath_real() ); + CALL_SUBTEST_1( packetmath_real() ); + CALL_SUBTEST_2( packetmath_real() ); } } diff --git a/test/product_extra.cpp b/test/product_extra.cpp index 8e55c6010..e4c853461 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -119,8 +119,8 @@ template void product_extra(const MatrixType& m) void test_product_extra() { for(int i = 0; i < g_repeat; i++) { - 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(2,50), ei_random(2,50))) ); + CALL_SUBTEST_1( product_extra(MatrixXf(ei_random(2,320), ei_random(2,320))) ); + CALL_SUBTEST_2( product_extra(MatrixXcf(ei_random(50,50), ei_random(50,50))) ); + CALL_SUBTEST_3( product_extra(Matrix,Dynamic,Dynamic,RowMajor>(ei_random(2,50), ei_random(2,50))) ); } } diff --git a/test/product_large.cpp b/test/product_large.cpp index 9b53e7b89..519213236 100644 --- a/test/product_large.cpp +++ b/test/product_large.cpp @@ -27,13 +27,14 @@ void test_product_large() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( product(MatrixXf(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST( product(MatrixXd(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST( product(MatrixXi(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST( product(MatrixXcf(ei_random(1,50), ei_random(1,50))) ); - CALL_SUBTEST( product(Matrix(ei_random(1,320), ei_random(1,320))) ); + CALL_SUBTEST_1( product(MatrixXf(ei_random(1,320), ei_random(1,320))) ); + CALL_SUBTEST_2( product(MatrixXd(ei_random(1,320), ei_random(1,320))) ); + CALL_SUBTEST_3( product(MatrixXi(ei_random(1,320), ei_random(1,320))) ); + CALL_SUBTEST_4( product(MatrixXcf(ei_random(1,50), ei_random(1,50))) ); + CALL_SUBTEST_5( product(Matrix(ei_random(1,320), ei_random(1,320))) ); } +#if defined EIGEN_TEST_PART_6 { // test a specific issue in DiagonalProduct int N = 1000000; @@ -48,4 +49,5 @@ void test_product_large() MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a; VERIFY_IS_APPROX((a = a * b), (c * b).eval()); } +#endif } diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 1a3d65291..e592afff7 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -117,8 +117,8 @@ void test_product_notemporary() int s; for(int i = 0; i < g_repeat; i++) { s = ei_random(16,320); - CALL_SUBTEST( product_notemporary(MatrixXf(s, s)) ); + CALL_SUBTEST_1( product_notemporary(MatrixXf(s, s)) ); s = ei_random(16,120); - CALL_SUBTEST( product_notemporary(MatrixXcd(s,s)) ); + CALL_SUBTEST_2( product_notemporary(MatrixXcd(s,s)) ); } } diff --git a/test/product_selfadjoint.cpp b/test/product_selfadjoint.cpp index e47358197..aa8da37bd 100644 --- a/test/product_selfadjoint.cpp +++ b/test/product_selfadjoint.cpp @@ -78,13 +78,13 @@ template void product_selfadjoint(const MatrixType& m) void test_product_selfadjoint() { for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST( product_selfadjoint(Matrix()) ); - CALL_SUBTEST( product_selfadjoint(Matrix()) ); - CALL_SUBTEST( product_selfadjoint(Matrix3d()) ); - CALL_SUBTEST( product_selfadjoint(MatrixXcf(4, 4)) ); - CALL_SUBTEST( product_selfadjoint(MatrixXcd(21,21)) ); - CALL_SUBTEST( product_selfadjoint(MatrixXd(14,14)) ); - CALL_SUBTEST( product_selfadjoint(Matrix(17,17)) ); - CALL_SUBTEST( product_selfadjoint(Matrix,Dynamic,Dynamic,RowMajor>(19, 19)) ); + CALL_SUBTEST_1( product_selfadjoint(Matrix()) ); + CALL_SUBTEST_2( product_selfadjoint(Matrix()) ); + CALL_SUBTEST_3( product_selfadjoint(Matrix3d()) ); + CALL_SUBTEST_4( product_selfadjoint(MatrixXcf(4, 4)) ); + CALL_SUBTEST_5( product_selfadjoint(MatrixXcd(21,21)) ); + CALL_SUBTEST_6( product_selfadjoint(MatrixXd(14,14)) ); + CALL_SUBTEST_7( product_selfadjoint(Matrix(17,17)) ); + CALL_SUBTEST_8( product_selfadjoint(Matrix,Dynamic,Dynamic,RowMajor>(19, 19)) ); } } diff --git a/test/product_small.cpp b/test/product_small.cpp index 182af71db..d7f1c09ff 100644 --- a/test/product_small.cpp +++ b/test/product_small.cpp @@ -28,16 +28,18 @@ void test_product_small() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( product(Matrix()) ); - CALL_SUBTEST( product(Matrix()) ); - CALL_SUBTEST( product(Matrix3d()) ); - CALL_SUBTEST( product(Matrix4d()) ); - CALL_SUBTEST( product(Matrix4f()) ); + CALL_SUBTEST_1( product(Matrix()) ); + CALL_SUBTEST_2( product(Matrix()) ); + CALL_SUBTEST_3( product(Matrix3d()) ); + CALL_SUBTEST_4( product(Matrix4d()) ); + CALL_SUBTEST_5( product(Matrix4f()) ); } +#ifdef EIGEN_TEST_PART_6 { // test compilation of (outer_product) * vector Vector3f v = Vector3f::Random(); VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v); } +#endif } diff --git a/test/product_symm.cpp b/test/product_symm.cpp index cf0299c64..a9e055bd3 100644 --- a/test/product_symm.cpp +++ b/test/product_symm.cpp @@ -108,10 +108,10 @@ void test_product_symm() { for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST(( symm(ei_random(10,320),ei_random(10,320)) )); - CALL_SUBTEST(( symm,Dynamic,Dynamic>(ei_random(10,320),ei_random(10,320)) )); + CALL_SUBTEST_1(( symm(ei_random(10,320),ei_random(10,320)) )); + CALL_SUBTEST_2(( symm,Dynamic,Dynamic>(ei_random(10,320),ei_random(10,320)) )); - CALL_SUBTEST(( symm(ei_random(10,320)) )); - CALL_SUBTEST(( symm,Dynamic,1>(ei_random(10,320)) )); + CALL_SUBTEST_3(( symm(ei_random(10,320)) )); + CALL_SUBTEST_4(( symm,Dynamic,1>(ei_random(10,320)) )); } } diff --git a/test/product_syrk.cpp b/test/product_syrk.cpp index 657dec9bc..37d54bf16 100644 --- a/test/product_syrk.cpp +++ b/test/product_syrk.cpp @@ -75,8 +75,8 @@ void test_product_syrk() { int s; s = ei_random(10,320); - CALL_SUBTEST( syrk(MatrixXf(s, s)) ); + CALL_SUBTEST_1( syrk(MatrixXf(s, s)) ); s = ei_random(10,320); - CALL_SUBTEST( syrk(MatrixXcd(s, s)) ); + CALL_SUBTEST_2( syrk(MatrixXcd(s, s)) ); } } diff --git a/test/product_trmm.cpp b/test/product_trmm.cpp index 734d8c970..5f92391e6 100644 --- a/test/product_trmm.cpp +++ b/test/product_trmm.cpp @@ -63,7 +63,7 @@ void test_product_trmm() { for(int i = 0; i < g_repeat ; i++) { - trmm(ei_random(1,320),ei_random(1,320)); - trmm >(ei_random(1,320),ei_random(1,320)); + CALL_SUBTEST_1((trmm(ei_random(1,320),ei_random(1,320)))); + CALL_SUBTEST_2((trmm >(ei_random(1,320),ei_random(1,320)))); } } diff --git a/test/product_trmv.cpp b/test/product_trmv.cpp index b4d45cca2..5016a5b1f 100644 --- a/test/product_trmv.cpp +++ b/test/product_trmv.cpp @@ -82,11 +82,11 @@ template void trmv(const MatrixType& m) void test_product_trmv() { for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST( trmv(Matrix()) ); - CALL_SUBTEST( trmv(Matrix()) ); - CALL_SUBTEST( trmv(Matrix3d()) ); - CALL_SUBTEST( trmv(Matrix,23, 23>()) ); - CALL_SUBTEST( trmv(MatrixXcd(17,17)) ); - CALL_SUBTEST( trmv(Matrix(19, 19)) ); + CALL_SUBTEST_1( trmv(Matrix()) ); + CALL_SUBTEST_2( trmv(Matrix()) ); + CALL_SUBTEST_3( trmv(Matrix3d()) ); + CALL_SUBTEST_4( trmv(Matrix,23, 23>()) ); + CALL_SUBTEST_5( trmv(MatrixXcd(17,17)) ); + CALL_SUBTEST_6( trmv(Matrix(19, 19)) ); } } diff --git a/test/product_trsm.cpp b/test/product_trsm.cpp index 756034df9..f850e031a 100644 --- a/test/product_trsm.cpp +++ b/test/product_trsm.cpp @@ -59,7 +59,7 @@ void test_product_trsm() { for(int i = 0; i < g_repeat ; i++) { - trsm(ei_random(1,320),ei_random(1,320)); - trsm >(ei_random(1,320),ei_random(1,320)); + CALL_SUBTEST_1((trsm(ei_random(1,320),ei_random(1,320)))); + CALL_SUBTEST_2((trsm >(ei_random(1,320),ei_random(1,320)))); } } diff --git a/test/qr.cpp b/test/qr.cpp index 864828750..90b5c4446 100644 --- a/test/qr.cpp +++ b/test/qr.cpp @@ -63,7 +63,7 @@ template void qr_fixedsize() Matrix m2 = Matrix::Random(Cols,Cols2); Matrix m3 = m1*m2; m2 = Matrix::Random(Cols,Cols2); - qr.solve(m3, &m2); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); } @@ -86,7 +86,7 @@ template void qr_invertible() HouseholderQR qr(m1); m3 = MatrixType::Random(size,size); - qr.solve(m3, &m2); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); // now construct a matrix with prescribed determinant @@ -106,7 +106,7 @@ template void qr_verify_assert() HouseholderQR qr; VERIFY_RAISES_ASSERT(qr.matrixQR()) - VERIFY_RAISES_ASSERT(qr.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(qr.solve(tmp)) VERIFY_RAISES_ASSERT(qr.matrixQ()) VERIFY_RAISES_ASSERT(qr.absDeterminant()) VERIFY_RAISES_ASSERT(qr.logAbsDeterminant()) @@ -115,24 +115,24 @@ template void qr_verify_assert() void test_qr() { for(int i = 0; i < 1; i++) { - CALL_SUBTEST( qr(MatrixXf(47,40)) ); - CALL_SUBTEST( qr(MatrixXcd(17,7)) ); - CALL_SUBTEST(( qr_fixedsize, 2 >() )); - CALL_SUBTEST(( qr_fixedsize, 4 >() )); - CALL_SUBTEST(( qr_fixedsize, 7 >() )); + CALL_SUBTEST_1( qr(MatrixXf(47,40)) ); + CALL_SUBTEST_2( qr(MatrixXcd(17,7)) ); + CALL_SUBTEST_3(( qr_fixedsize, 2 >() )); + CALL_SUBTEST_4(( qr_fixedsize, 4 >() )); + CALL_SUBTEST_5(( qr_fixedsize, 7 >() )); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); + CALL_SUBTEST_1( qr_invertible() ); + CALL_SUBTEST_6( qr_invertible() ); + CALL_SUBTEST_7( qr_invertible() ); + CALL_SUBTEST_8( qr_invertible() ); } - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); + CALL_SUBTEST_9(qr_verify_assert()); + CALL_SUBTEST_10(qr_verify_assert()); + CALL_SUBTEST_1(qr_verify_assert()); + CALL_SUBTEST_6(qr_verify_assert()); + CALL_SUBTEST_7(qr_verify_assert()); + CALL_SUBTEST_8(qr_verify_assert()); } diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index 5c5c5d259..763c12067 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -36,7 +36,7 @@ template void qr() typedef Matrix VectorType; MatrixType m1; createRandomMatrixOfRank(rank,rows,cols,m1); - ColPivotingHouseholderQR qr(m1); + ColPivHouseholderQR qr(m1); VERIFY_IS_APPROX(rank, qr.rank()); VERIFY(cols - qr.rank() == qr.dimensionOfKernel()); VERIFY(!qr.isInjective()); @@ -61,10 +61,8 @@ template void qr() MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); - VERIFY(qr.solve(m3, &m2)); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); - m3 = MatrixType::Random(rows,cols2); - VERIFY(!qr.solve(m3, &m2)); } template void qr_fixedsize() @@ -74,7 +72,7 @@ template void qr_fixedsize() int rank = ei_random(1, std::min(int(Rows), int(Cols))-1); Matrix m1; createRandomMatrixOfRank(rank,Rows,Cols,m1); - ColPivotingHouseholderQR > qr(m1); + ColPivHouseholderQR > qr(m1); VERIFY_IS_APPROX(rank, qr.rank()); VERIFY(Cols - qr.rank() == qr.dimensionOfKernel()); VERIFY(!qr.isInjective()); @@ -95,10 +93,8 @@ template void qr_fixedsize() Matrix m2 = Matrix::Random(Cols,Cols2); Matrix m3 = m1*m2; m2 = Matrix::Random(Cols,Cols2); - VERIFY(qr.solve(m3, &m2)); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); - m3 = Matrix::Random(Rows,Cols2); - VERIFY(!qr.solve(m3, &m2)); } template void qr_invertible() @@ -118,9 +114,9 @@ template void qr_invertible() m1 += a * a.adjoint(); } - ColPivotingHouseholderQR qr(m1); + ColPivHouseholderQR qr(m1); m3 = MatrixType::Random(size,size); - qr.solve(m3, &m2); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); // now construct a matrix with prescribed determinant @@ -138,15 +134,14 @@ template void qr_verify_assert() { MatrixType tmp; - ColPivotingHouseholderQR qr; + ColPivHouseholderQR qr; VERIFY_RAISES_ASSERT(qr.matrixQR()) - VERIFY_RAISES_ASSERT(qr.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(qr.solve(tmp)) VERIFY_RAISES_ASSERT(qr.matrixQ()) VERIFY_RAISES_ASSERT(qr.dimensionOfKernel()) VERIFY_RAISES_ASSERT(qr.isInjective()) VERIFY_RAISES_ASSERT(qr.isSurjective()) VERIFY_RAISES_ASSERT(qr.isInvertible()) - VERIFY_RAISES_ASSERT(qr.computeInverse(&tmp)) VERIFY_RAISES_ASSERT(qr.inverse()) VERIFY_RAISES_ASSERT(qr.absDeterminant()) VERIFY_RAISES_ASSERT(qr.logAbsDeterminant()) @@ -155,24 +150,24 @@ template void qr_verify_assert() void test_qr_colpivoting() { for(int i = 0; i < 1; i++) { - CALL_SUBTEST( qr() ); - CALL_SUBTEST( qr() ); - CALL_SUBTEST( qr() ); - CALL_SUBTEST(( qr_fixedsize, 4 >() )); - CALL_SUBTEST(( qr_fixedsize, 3 >() )); + CALL_SUBTEST_1( qr() ); + CALL_SUBTEST_2( qr() ); + CALL_SUBTEST_3( qr() ); + CALL_SUBTEST_4(( qr_fixedsize, 4 >() )); + CALL_SUBTEST_5(( qr_fixedsize, 3 >() )); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); + CALL_SUBTEST_1( qr_invertible() ); + CALL_SUBTEST_2( qr_invertible() ); + CALL_SUBTEST_6( qr_invertible() ); + CALL_SUBTEST_3( qr_invertible() ); } - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); + CALL_SUBTEST_7(qr_verify_assert()); + CALL_SUBTEST_8(qr_verify_assert()); + CALL_SUBTEST_1(qr_verify_assert()); + CALL_SUBTEST_2(qr_verify_assert()); + CALL_SUBTEST_6(qr_verify_assert()); + CALL_SUBTEST_3(qr_verify_assert()); } diff --git a/test/qr_fullpivoting.cpp b/test/qr_fullpivoting.cpp index 891c2a527..65d9a071f 100644 --- a/test/qr_fullpivoting.cpp +++ b/test/qr_fullpivoting.cpp @@ -36,7 +36,7 @@ template void qr() typedef Matrix VectorType; MatrixType m1; createRandomMatrixOfRank(rank,rows,cols,m1); - FullPivotingHouseholderQR qr(m1); + FullPivHouseholderQR qr(m1); VERIFY_IS_APPROX(rank, qr.rank()); VERIFY(cols - qr.rank() == qr.dimensionOfKernel()); VERIFY(!qr.isInjective()); @@ -61,10 +61,8 @@ template void qr() MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); - VERIFY(qr.solve(m3, &m2)); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); - m3 = MatrixType::Random(rows,cols2); - VERIFY(!qr.solve(m3, &m2)); } template void qr_invertible() @@ -84,13 +82,13 @@ template void qr_invertible() m1 += a * a.adjoint(); } - FullPivotingHouseholderQR qr(m1); + FullPivHouseholderQR qr(m1); VERIFY(qr.isInjective()); VERIFY(qr.isInvertible()); VERIFY(qr.isSurjective()); m3 = MatrixType::Random(size,size); - VERIFY(qr.solve(m3, &m2)); + m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); // now construct a matrix with prescribed determinant @@ -108,15 +106,14 @@ template void qr_verify_assert() { MatrixType tmp; - FullPivotingHouseholderQR qr; + FullPivHouseholderQR qr; VERIFY_RAISES_ASSERT(qr.matrixQR()) - VERIFY_RAISES_ASSERT(qr.solve(tmp,&tmp)) + VERIFY_RAISES_ASSERT(qr.solve(tmp)) VERIFY_RAISES_ASSERT(qr.matrixQ()) VERIFY_RAISES_ASSERT(qr.dimensionOfKernel()) VERIFY_RAISES_ASSERT(qr.isInjective()) VERIFY_RAISES_ASSERT(qr.isSurjective()) VERIFY_RAISES_ASSERT(qr.isInvertible()) - VERIFY_RAISES_ASSERT(qr.computeInverse(&tmp)) VERIFY_RAISES_ASSERT(qr.inverse()) VERIFY_RAISES_ASSERT(qr.absDeterminant()) VERIFY_RAISES_ASSERT(qr.logAbsDeterminant()) @@ -126,23 +123,23 @@ void test_qr_fullpivoting() { for(int i = 0; i < 1; i++) { // FIXME : very weird bug here -// CALL_SUBTEST( qr(Matrix2f()) ); - CALL_SUBTEST( qr() ); - CALL_SUBTEST( qr() ); - CALL_SUBTEST( qr() ); +// CALL_SUBTEST(qr(Matrix2f()) ); + CALL_SUBTEST_1( qr() ); + CALL_SUBTEST_2( qr() ); + CALL_SUBTEST_3( qr() ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); - CALL_SUBTEST( qr_invertible() ); + CALL_SUBTEST_1( qr_invertible() ); + CALL_SUBTEST_2( qr_invertible() ); + CALL_SUBTEST_4( qr_invertible() ); + CALL_SUBTEST_3( qr_invertible() ); } - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); - CALL_SUBTEST(qr_verify_assert()); + CALL_SUBTEST_5(qr_verify_assert()); + CALL_SUBTEST_6(qr_verify_assert()); + CALL_SUBTEST_1(qr_verify_assert()); + CALL_SUBTEST_2(qr_verify_assert()); + CALL_SUBTEST_4(qr_verify_assert()); + CALL_SUBTEST_3(qr_verify_assert()); } diff --git a/test/redux.cpp b/test/redux.cpp index 951b34bca..c075c1393 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -112,16 +112,16 @@ template void vectorRedux(const VectorType& w) void test_redux() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( matrixRedux(Matrix()) ); - CALL_SUBTEST( matrixRedux(Matrix2f()) ); - CALL_SUBTEST( matrixRedux(Matrix4d()) ); - CALL_SUBTEST( matrixRedux(MatrixXcf(3, 3)) ); - CALL_SUBTEST( matrixRedux(MatrixXd(8, 12)) ); - CALL_SUBTEST( matrixRedux(MatrixXi(8, 12)) ); + CALL_SUBTEST_1( matrixRedux(Matrix()) ); + CALL_SUBTEST_2( matrixRedux(Matrix2f()) ); + CALL_SUBTEST_3( matrixRedux(Matrix4d()) ); + CALL_SUBTEST_4( matrixRedux(MatrixXcf(3, 3)) ); + CALL_SUBTEST_5( matrixRedux(MatrixXd(8, 12)) ); + CALL_SUBTEST_6( matrixRedux(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( vectorRedux(Vector4f()) ); - CALL_SUBTEST( vectorRedux(VectorXd(10)) ); - CALL_SUBTEST( vectorRedux(VectorXf(33)) ); + CALL_SUBTEST_7( vectorRedux(Vector4f()) ); + CALL_SUBTEST_5( vectorRedux(VectorXd(10)) ); + CALL_SUBTEST_8( vectorRedux(VectorXf(33)) ); } } diff --git a/test/regression.cpp b/test/regression.cpp index 28b6356b3..0e2323bf6 100644 --- a/test/regression.cpp +++ b/test/regression.cpp @@ -95,6 +95,7 @@ void test_regression() { for(int i = 0; i < g_repeat; i++) { +#ifdef EIGEN_TEST_PART_1 { Vector2f points2f [1000]; Vector2f *points2f_ptrs [1000]; @@ -108,7 +109,9 @@ void test_regression() CALL_SUBTEST(check_linearRegression(100, points2f_ptrs, coeffs2f, 0.01f)); CALL_SUBTEST(check_linearRegression(1000, points2f_ptrs, coeffs2f, 0.002f)); } +#endif +#ifdef EIGEN_TEST_PART_2 { Vector2f points2f [1000]; Vector2f *points2f_ptrs [1000]; @@ -119,7 +122,9 @@ void test_regression() CALL_SUBTEST(check_fitHyperplane(100, points2f_ptrs, coeffs3f, 0.01f)); CALL_SUBTEST(check_fitHyperplane(1000, points2f_ptrs, coeffs3f, 0.002f)); } +#endif +#ifdef EIGEN_TEST_PART_3 { Vector4d points4d [1000]; Vector4d *points4d_ptrs [1000]; @@ -130,7 +135,9 @@ void test_regression() CALL_SUBTEST(check_fitHyperplane(100, points4d_ptrs, coeffs5d, 0.01)); CALL_SUBTEST(check_fitHyperplane(1000, points4d_ptrs, coeffs5d, 0.002)); } +#endif +#ifdef EIGEN_TEST_PART_4 { VectorXcd *points11cd_ptrs[1000]; for(int i = 0; i < 1000; i++) points11cd_ptrs[i] = new VectorXcd(11); @@ -141,5 +148,6 @@ void test_regression() delete coeffs12cd; for(int i = 0; i < 1000; i++) delete points11cd_ptrs[i]; } +#endif } } diff --git a/test/resize.cpp b/test/resize.cpp index 3c8f21ee1..dfe3bda17 100644 --- a/test/resize.cpp +++ b/test/resize.cpp @@ -50,7 +50,7 @@ void resizeLikeTest31() { resizeLikeTest<3,1>(); } void test_resize() { - CALL_SUBTEST( resizeLikeTest12() ); - CALL_SUBTEST( resizeLikeTest1020() ); - CALL_SUBTEST( resizeLikeTest31() ); + CALL_SUBTEST(resizeLikeTest12() ); + CALL_SUBTEST(resizeLikeTest1020() ); + CALL_SUBTEST(resizeLikeTest31() ); } diff --git a/test/sizeof.cpp b/test/sizeof.cpp index 8dc9ca7ef..a7243591a 100644 --- a/test/sizeof.cpp +++ b/test/sizeof.cpp @@ -35,14 +35,14 @@ template void verifySizeOf(const MatrixType&) void test_sizeof() { - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(Matrix4d()) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(MatrixXcf(3, 3)) ); - CALL_SUBTEST( verifySizeOf(MatrixXi(8, 12)) ); - CALL_SUBTEST( verifySizeOf(MatrixXcd(20, 20)) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); + CALL_SUBTEST(verifySizeOf(Matrix()) ); + CALL_SUBTEST(verifySizeOf(Matrix4d()) ); + CALL_SUBTEST(verifySizeOf(Matrix()) ); + CALL_SUBTEST(verifySizeOf(Matrix()) ); + CALL_SUBTEST(verifySizeOf(MatrixXcf(3, 3)) ); + CALL_SUBTEST(verifySizeOf(MatrixXi(8, 12)) ); + CALL_SUBTEST(verifySizeOf(MatrixXcd(20, 20)) ); + CALL_SUBTEST(verifySizeOf(Matrix()) ); VERIFY(sizeof(std::complex) == 2*sizeof(float)); VERIFY(sizeof(std::complex) == 2*sizeof(double)); diff --git a/test/smallvectors.cpp b/test/smallvectors.cpp index f0807c796..d6dc8e97c 100644 --- a/test/smallvectors.cpp +++ b/test/smallvectors.cpp @@ -50,8 +50,8 @@ template void smallVectors() void test_smallvectors() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( smallVectors() ); - CALL_SUBTEST( smallVectors() ); - CALL_SUBTEST( smallVectors() ); + CALL_SUBTEST(smallVectors() ); + CALL_SUBTEST(smallVectors() ); + CALL_SUBTEST(smallVectors() ); } } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 666eea872..050b14995 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -344,10 +344,10 @@ template void sparse_basic(const SparseMatrixType& re void test_sparse_basic() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( sparse_basic(SparseMatrix(8, 8)) ); - CALL_SUBTEST( sparse_basic(SparseMatrix >(16, 16)) ); - CALL_SUBTEST( sparse_basic(SparseMatrix(33, 33)) ); + CALL_SUBTEST_1( sparse_basic(SparseMatrix(8, 8)) ); + CALL_SUBTEST_2( sparse_basic(SparseMatrix >(16, 16)) ); + CALL_SUBTEST_1( sparse_basic(SparseMatrix(33, 33)) ); - CALL_SUBTEST( sparse_basic(DynamicSparseMatrix(8, 8)) ); + CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix(8, 8)) ); } } diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index 743273f65..f2a4e8bb9 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -123,10 +123,10 @@ template void sparse_product(const SparseMatrixType& void test_sparse_product() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( sparse_product(SparseMatrix(8, 8)) ); - CALL_SUBTEST( sparse_product(SparseMatrix >(16, 16)) ); - CALL_SUBTEST( sparse_product(SparseMatrix(33, 33)) ); + CALL_SUBTEST_1( sparse_product(SparseMatrix(8, 8)) ); + CALL_SUBTEST_2( sparse_product(SparseMatrix >(16, 16)) ); + CALL_SUBTEST_1( sparse_product(SparseMatrix(33, 33)) ); - CALL_SUBTEST( sparse_product(DynamicSparseMatrix(8, 8)) ); + CALL_SUBTEST_3( sparse_product(DynamicSparseMatrix(8, 8)) ); } } diff --git a/test/sparse_solvers.cpp b/test/sparse_solvers.cpp index 09ae1ad60..a530a9515 100644 --- a/test/sparse_solvers.cpp +++ b/test/sparse_solvers.cpp @@ -109,7 +109,7 @@ template void sparse_solvers(int rows, int cols) initSPD(density, refMat2, m2); - refMat2.llt().solve(b, &refX); + refX = refMat2.llt().solve(b); typedef SparseMatrix SparseSelfAdjointMatrix; if (!NumTraits::IsComplex) { @@ -152,7 +152,7 @@ template void sparse_solvers(int rows, int cols) refMat2 += refMat2.adjoint(); refMat2.diagonal() *= 0.5; - refMat2.llt().solve(b, &refX); // FIXME use LLT to compute the reference because LDLT seems to fail with large matrices + refX = refMat2.llt().solve(b); // FIXME use LLT to compute the reference because LDLT seems to fail with large matrices typedef SparseMatrix SparseSelfAdjointMatrix; x = b; SparseLDLT ldlt(m2); @@ -172,8 +172,8 @@ template void sparse_solvers(int rows, int cols) initSparse(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords); - LU refLu(refMat2); - refLu.solve(b, &refX); + FullPivLU refLu(refMat2); + refX = refLu.solve(b); #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT) Scalar refDet = refLu.determinant(); #endif @@ -229,8 +229,8 @@ template void sparse_solvers(int rows, int cols) void test_sparse_solvers() { for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST( sparse_solvers(8, 8) ); - CALL_SUBTEST( sparse_solvers >(16, 16) ); -// CALL_SUBTEST( sparse_solvers(100, 100) ); +// CALL_SUBTEST(sparse_solvers(8, 8) ); + CALL_SUBTEST(sparse_solvers >(16, 16) ); +// CALL_SUBTEST(sparse_solvers(100, 100) ); } } diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 236e14f1b..5c6dadc00 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -91,9 +91,9 @@ template void sparse_vector(int rows, int cols) void test_sparse_vector() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( sparse_vector(8, 8) ); - CALL_SUBTEST( sparse_vector >(16, 16) ); - CALL_SUBTEST( sparse_vector(299, 535) ); + CALL_SUBTEST_1( sparse_vector(8, 8) ); + CALL_SUBTEST_2( sparse_vector >(16, 16) ); + CALL_SUBTEST_1( sparse_vector(299, 535) ); } } diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index ed72bb7a7..7661fc893 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -84,10 +84,10 @@ template void stable_norm(const MatrixType& m) 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))) ); + CALL_SUBTEST_1( stable_norm(Matrix()) ); + CALL_SUBTEST_2( stable_norm(Vector4d()) ); + CALL_SUBTEST_3( stable_norm(VectorXd(ei_random(10,2000))) ); + CALL_SUBTEST_4( stable_norm(VectorXf(ei_random(10,2000))) ); + CALL_SUBTEST_5( stable_norm(VectorXcd(ei_random(10,2000))) ); } } diff --git a/test/stdvector.cpp b/test/stdvector.cpp index a976f0cf1..bdca826f4 100644 --- a/test/stdvector.cpp +++ b/test/stdvector.cpp @@ -135,29 +135,29 @@ void check_stdvector_quaternion(const QuaternionType&) void test_stdvector() { // some non vectorizable fixed sizes - CALL_SUBTEST(check_stdvector_matrix(Vector2f())); - CALL_SUBTEST(check_stdvector_matrix(Matrix3f())); - CALL_SUBTEST(check_stdvector_matrix(Matrix3d())); + CALL_SUBTEST_1(check_stdvector_matrix(Vector2f())); + CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f())); + CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d())); // some vectorizable fixed sizes - CALL_SUBTEST(check_stdvector_matrix(Matrix2f())); - CALL_SUBTEST(check_stdvector_matrix(Vector4f())); - CALL_SUBTEST(check_stdvector_matrix(Matrix4f())); - CALL_SUBTEST(check_stdvector_matrix(Matrix4d())); + CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f())); + CALL_SUBTEST_1(check_stdvector_matrix(Vector4f())); + CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f())); + CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d())); // some dynamic sizes - CALL_SUBTEST(check_stdvector_matrix(MatrixXd(1,1))); - CALL_SUBTEST(check_stdvector_matrix(VectorXd(20))); - CALL_SUBTEST(check_stdvector_matrix(RowVectorXf(20))); - CALL_SUBTEST(check_stdvector_matrix(MatrixXcf(10,10))); + CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1))); + CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20))); + CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20))); + CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10))); // some Transform - CALL_SUBTEST(check_stdvector_transform(Transform2f())); - CALL_SUBTEST(check_stdvector_transform(Transform3f())); - CALL_SUBTEST(check_stdvector_transform(Transform3d())); - //CALL_SUBTEST(check_stdvector_transform(Transform4d())); + CALL_SUBTEST_4(check_stdvector_transform(Transform2f())); + CALL_SUBTEST_4(check_stdvector_transform(Transform3f())); + CALL_SUBTEST_4(check_stdvector_transform(Transform3d())); + //CALL_SUBTEST(heck_stdvector_transform(Transform4d())); // some Quaternion - CALL_SUBTEST(check_stdvector_quaternion(Quaternionf())); - CALL_SUBTEST(check_stdvector_quaternion(Quaterniond())); + CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf())); + CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond())); } diff --git a/test/submatrices.cpp b/test/submatrices.cpp index 6fe86c281..75b0fde4b 100644 --- a/test/submatrices.cpp +++ b/test/submatrices.cpp @@ -215,14 +215,14 @@ void data_and_stride(const MatrixType& m) void test_submatrices() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( submatrices(Matrix()) ); - CALL_SUBTEST( submatrices(Matrix4d()) ); - CALL_SUBTEST( submatrices(MatrixXcf(3, 3)) ); - CALL_SUBTEST( submatrices(MatrixXi(8, 12)) ); - CALL_SUBTEST( submatrices(MatrixXcd(20, 20)) ); - CALL_SUBTEST( submatrices(MatrixXf(20, 20)) ); + CALL_SUBTEST_1( submatrices(Matrix()) ); + CALL_SUBTEST_2( submatrices(Matrix4d()) ); + CALL_SUBTEST_3( submatrices(MatrixXcf(3, 3)) ); + CALL_SUBTEST_4( submatrices(MatrixXi(8, 12)) ); + CALL_SUBTEST_5( submatrices(MatrixXcd(20, 20)) ); + CALL_SUBTEST_6( 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))) ); + CALL_SUBTEST_6( data_and_stride(MatrixXf(ei_random(5,50), ei_random(5,50))) ); + CALL_SUBTEST_7( data_and_stride(Matrix(ei_random(5,50), ei_random(5,50))) ); } } diff --git a/test/svd.cpp b/test/svd.cpp index e6a32bd3f..1b41d7032 100644 --- a/test/svd.cpp +++ b/test/svd.cpp @@ -59,7 +59,7 @@ template void svd(const MatrixType& m) a += a * a.adjoint() + a1 * a1.adjoint(); } SVD svd(a); - svd.solve(b, &x); + x = svd.solve(b); VERIFY_IS_APPROX(a * x,b); } @@ -87,7 +87,7 @@ template void svd_verify_assert() MatrixType tmp; SVD svd; - VERIFY_RAISES_ASSERT(svd.solve(tmp, &tmp)) + VERIFY_RAISES_ASSERT(svd.solve(tmp)) VERIFY_RAISES_ASSERT(svd.matrixU()) VERIFY_RAISES_ASSERT(svd.singularValues()) VERIFY_RAISES_ASSERT(svd.matrixV()) @@ -100,17 +100,17 @@ template void svd_verify_assert() void test_svd() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( svd(Matrix3f()) ); - CALL_SUBTEST( svd(Matrix4d()) ); - CALL_SUBTEST( svd(MatrixXf(7,7)) ); - CALL_SUBTEST( svd(MatrixXd(14,7)) ); + CALL_SUBTEST_1( svd(Matrix3f()) ); + CALL_SUBTEST_2( svd(Matrix4d()) ); + CALL_SUBTEST_3( svd(MatrixXf(7,7)) ); + CALL_SUBTEST_4( svd(MatrixXd(14,7)) ); // complex are not implemented yet -// CALL_SUBTEST( svd(MatrixXcd(6,6)) ); -// CALL_SUBTEST( svd(MatrixXcf(3,3)) ); +// CALL_SUBTEST(svd(MatrixXcd(6,6)) ); +// CALL_SUBTEST(svd(MatrixXcf(3,3)) ); } - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); - CALL_SUBTEST( svd_verify_assert() ); + CALL_SUBTEST_1( svd_verify_assert() ); + CALL_SUBTEST_2( svd_verify_assert() ); + CALL_SUBTEST_3( svd_verify_assert() ); + CALL_SUBTEST_4( svd_verify_assert() ); } diff --git a/test/swap.cpp b/test/swap.cpp index 8b325992c..c11f0fec0 100644 --- a/test/swap.cpp +++ b/test/swap.cpp @@ -91,8 +91,8 @@ template void swap(const MatrixType& m) 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 + CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization + CALL_SUBTEST_2( swap(Matrix4d()) ); // fixed size, possible vectorization + CALL_SUBTEST_3( swap(MatrixXd(3,3)) ); // dyn size, no vectorization + CALL_SUBTEST_4( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization } diff --git a/test/triangular.cpp b/test/triangular.cpp index 1e0782523..ee02c0022 100644 --- a/test/triangular.cpp +++ b/test/triangular.cpp @@ -137,12 +137,12 @@ template void triangular(const MatrixType& m) void test_triangular() { for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST( triangular(Matrix()) ); - CALL_SUBTEST( triangular(Matrix()) ); - CALL_SUBTEST( triangular(Matrix3d()) ); - CALL_SUBTEST( triangular(MatrixXcf(4, 4)) ); - CALL_SUBTEST( triangular(Matrix,8, 8>()) ); - CALL_SUBTEST( triangular(MatrixXcd(17,17)) ); - CALL_SUBTEST( triangular(Matrix(5, 5)) ); + CALL_SUBTEST_1( triangular(Matrix()) ); + CALL_SUBTEST_2( triangular(Matrix()) ); + CALL_SUBTEST_3( triangular(Matrix3d()) ); + CALL_SUBTEST_4( triangular(MatrixXcf(4, 4)) ); + CALL_SUBTEST_5( triangular(Matrix,8, 8>()) ); + CALL_SUBTEST_6( triangular(MatrixXcd(17,17)) ); + CALL_SUBTEST_7( triangular(Matrix(5, 5)) ); } } diff --git a/test/umeyama.cpp b/test/umeyama.cpp index 0999c59c9..09db27c1b 100644 --- a/test/umeyama.cpp +++ b/test/umeyama.cpp @@ -181,17 +181,17 @@ void test_umeyama() // works also for dimensions bigger than 3... for (int dim=2; dim<8; ++dim) { - CALL_SUBTEST(run_test(dim, num_elements)); - CALL_SUBTEST(run_test(dim, num_elements)); + CALL_SUBTEST_1(run_test(dim, num_elements)); + CALL_SUBTEST_2(run_test(dim, num_elements)); } - CALL_SUBTEST((run_fixed_size_test(num_elements))); - CALL_SUBTEST((run_fixed_size_test(num_elements))); - CALL_SUBTEST((run_fixed_size_test(num_elements))); + CALL_SUBTEST_3((run_fixed_size_test(num_elements))); + CALL_SUBTEST_4((run_fixed_size_test(num_elements))); + CALL_SUBTEST_5((run_fixed_size_test(num_elements))); - CALL_SUBTEST((run_fixed_size_test(num_elements))); - CALL_SUBTEST((run_fixed_size_test(num_elements))); - CALL_SUBTEST((run_fixed_size_test(num_elements))); + CALL_SUBTEST_6((run_fixed_size_test(num_elements))); + CALL_SUBTEST_7((run_fixed_size_test(num_elements))); + CALL_SUBTEST_8((run_fixed_size_test(num_elements))); } // Those two calls don't compile and result in meaningful error messages! diff --git a/test/visitor.cpp b/test/visitor.cpp index 6ec442bc8..65ee60ba4 100644 --- a/test/visitor.cpp +++ b/test/visitor.cpp @@ -115,17 +115,17 @@ template void vectorVisitor(const VectorType& w) void test_visitor() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( matrixVisitor(Matrix()) ); - CALL_SUBTEST( matrixVisitor(Matrix2f()) ); - CALL_SUBTEST( matrixVisitor(Matrix4d()) ); - CALL_SUBTEST( matrixVisitor(MatrixXd(8, 12)) ); - CALL_SUBTEST( matrixVisitor(Matrix(20, 20)) ); - CALL_SUBTEST( matrixVisitor(MatrixXi(8, 12)) ); + CALL_SUBTEST_1( matrixVisitor(Matrix()) ); + CALL_SUBTEST_2( matrixVisitor(Matrix2f()) ); + CALL_SUBTEST_3( matrixVisitor(Matrix4d()) ); + CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) ); + CALL_SUBTEST_5( matrixVisitor(Matrix(20, 20)) ); + CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( vectorVisitor(Vector4f()) ); - CALL_SUBTEST( vectorVisitor(VectorXd(10)) ); - CALL_SUBTEST( vectorVisitor(RowVectorXd(10)) ); - CALL_SUBTEST( vectorVisitor(VectorXf(33)) ); + CALL_SUBTEST_7( vectorVisitor(Vector4f()) ); + CALL_SUBTEST_8( vectorVisitor(VectorXd(10)) ); + CALL_SUBTEST_9( vectorVisitor(RowVectorXd(10)) ); + CALL_SUBTEST_10( vectorVisitor(VectorXf(33)) ); } } diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h index 2fb733a99..c4607c2b8 100644 --- a/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h +++ b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h @@ -29,7 +29,7 @@ namespace Eigen { template struct ei_make_coherent_impl { - static void run(A& a, B& b) {} + static void run(A&, B&) {} }; // resize a to match b is a.size()==0, and conversely. diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 36d13b7eb..636f37655 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -192,7 +192,7 @@ MatrixExponential::MatrixExponential(const MatrixType &M, MatrixType 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); + *result = m_tmp2.partialPivLu().solve(m_tmp1); for (int i=0; i test2; CALL_SUBTEST(test2.testIntersect1()); CALL_SUBTEST(test2.testMinimize1()); CALL_SUBTEST(test2.testIntersect2()); CALL_SUBTEST(test2.testMinimize2()); +#endif +#ifdef EIGEN_TEST_PART_2 TreeTest<3> test3; CALL_SUBTEST(test3.testIntersect1()); CALL_SUBTEST(test3.testMinimize1()); CALL_SUBTEST(test3.testIntersect2()); CALL_SUBTEST(test3.testMinimize2()); +#endif +#ifdef EIGEN_TEST_PART_3 TreeTest<4> test4; CALL_SUBTEST(test4.testIntersect1()); CALL_SUBTEST(test4.testMinimize1()); CALL_SUBTEST(test4.testIntersect2()); CALL_SUBTEST(test4.testMinimize2()); +#endif } } diff --git a/unsupported/test/alignedvector3.cpp b/unsupported/test/alignedvector3.cpp index 52d39ce50..f4b6dd4d9 100644 --- a/unsupported/test/alignedvector3.cpp +++ b/unsupported/test/alignedvector3.cpp @@ -69,6 +69,6 @@ void alignedvector3() void test_alignedvector3() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST(( alignedvector3() )); + CALL_SUBTEST( alignedvector3() ); } } diff --git a/unsupported/test/matrixExponential.cpp b/unsupported/test/matrixExponential.cpp index 7d65a701a..f7ee71768 100644 --- a/unsupported/test/matrixExponential.cpp +++ b/unsupported/test/matrixExponential.cpp @@ -110,18 +110,18 @@ void randomTest(const MatrixType& m, double tol) void test_matrixExponential() { - CALL_SUBTEST(test2dRotation(1e-14)); - CALL_SUBTEST(test2dRotation(1e-5)); - CALL_SUBTEST(test2dHyperbolicRotation(1e-14)); - CALL_SUBTEST(test2dHyperbolicRotation(1e-5)); - CALL_SUBTEST(testPascal(1e-5)); - CALL_SUBTEST(testPascal(1e-14)); - CALL_SUBTEST(randomTest(Matrix2d(), 1e-13)); - CALL_SUBTEST(randomTest(Matrix(), 1e-13)); - CALL_SUBTEST(randomTest(Matrix4cd(), 1e-13)); - CALL_SUBTEST(randomTest(MatrixXd(8,8), 1e-13)); - CALL_SUBTEST(randomTest(Matrix2f(), 1e-4)); - CALL_SUBTEST(randomTest(Matrix3cf(), 1e-4)); - CALL_SUBTEST(randomTest(Matrix4f(), 1e-4)); - CALL_SUBTEST(randomTest(MatrixXf(8,8), 1e-4)); + CALL_SUBTEST_2(test2dRotation(1e-14)); + CALL_SUBTEST_1(test2dRotation(1e-5)); + CALL_SUBTEST_2(test2dHyperbolicRotation(1e-14)); + CALL_SUBTEST_1(test2dHyperbolicRotation(1e-5)); + CALL_SUBTEST_1(testPascal(1e-5)); + CALL_SUBTEST_2(testPascal(1e-14)); + CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13)); + CALL_SUBTEST_2(randomTest(Matrix(), 1e-13)); + CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13)); + CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13)); + CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4)); + CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4)); + CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4)); + CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4)); }