merge with the main dev branch

This commit is contained in:
Thomas Capricelli 2009-08-19 19:46:37 +02:00
commit 47ac354190
79 changed files with 1668 additions and 710 deletions

View File

@ -1,5 +1,7 @@
project(Eigen) project(Eigen)
cmake_minimum_required(VERSION 2.6.2)
# automatically parse the version number # automatically parse the version number
file(READ "${CMAKE_SOURCE_DIR}/Eigen/src/Core/util/Macros.h" _eigen2_version_header LIMIT 5000 OFFSET 1000) 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}") string(REGEX MATCH "define *EIGEN_WORLD_VERSION ([0-9]*)" _eigen2_world_version_match "${_eigen2_version_header}")
@ -10,21 +12,22 @@ string(REGEX MATCH "define *EIGEN_MINOR_VERSION ([0-9]*)" _eigen2_minor_version_
set(EIGEN2_MINOR_VERSION "${CMAKE_MATCH_1}") set(EIGEN2_MINOR_VERSION "${CMAKE_MATCH_1}")
set(EIGEN_VERSION_NUMBER ${EIGEN2_WORLD_VERSION}.${EIGEN2_MAJOR_VERSION}.${EIGEN2_MINOR_VERSION}) set(EIGEN_VERSION_NUMBER ${EIGEN2_WORLD_VERSION}.${EIGEN2_MAJOR_VERSION}.${EIGEN2_MINOR_VERSION})
# if the mercurial program is absent, this will leave the EIGEN_HG_REVISION string empty, # if the mercurial program is absent, this will leave the EIGEN_HG_CHANGESET string empty,
# but won't stop CMake. # but won't stop CMake.
execute_process(COMMAND hg tip -R ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE EIGEN_HGTIP_OUTPUT) execute_process(COMMAND hg tip -R ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE EIGEN_HGTIP_OUTPUT)
execute_process(COMMAND hg branch -R ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE EIGEN_BRANCH_OUTPUT)
# extract the mercurial revision number from the hg tip output # if this is the default (aka development) branch, extract the mercurial changeset number from the hg tip output...
string(REGEX MATCH "^changeset: *[0-9]*:([0-9;a-f]+).*" EIGEN_HG_REVISION_MATCH "${EIGEN_HGTIP_OUTPUT}") if(EIGEN_BRANCH_OUTPUT MATCHES "default")
set(EIGEN_HG_REVISION "${CMAKE_MATCH_1}") string(REGEX MATCH "^changeset: *[0-9]*:([0-9;a-f]+).*" EIGEN_HG_CHANGESET_MATCH "${EIGEN_HGTIP_OUTPUT}")
set(EIGEN_HG_CHANGESET "${CMAKE_MATCH_1}")
if(EIGEN_HG_REVISION) endif(EIGEN_BRANCH_OUTPUT MATCHES "default")
set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER} (mercurial revision ${EIGEN_HG_REVISION})") #...and show it next to the version number
else(EIGEN_HG_REVISION) if(EIGEN_HG_CHANGESET)
set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER} (mercurial changeset ${EIGEN_HG_CHANGESET})")
else(EIGEN_HG_CHANGESET)
set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER}") set(EIGEN_VERSION "${EIGEN_VERSION_NUMBER}")
endif(EIGEN_HG_REVISION) endif(EIGEN_HG_CHANGESET)
cmake_minimum_required(VERSION 2.6.2)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)

View File

@ -150,10 +150,12 @@ namespace Eigen {
#include "src/Core/Assign.h" #include "src/Core/Assign.h"
#endif #endif
#include "src/Core/util/BlasUtil.h"
#include "src/Core/MatrixStorage.h" #include "src/Core/MatrixStorage.h"
#include "src/Core/NestByValue.h" #include "src/Core/NestByValue.h"
#include "src/Core/ReturnByValue.h" #include "src/Core/ReturnByValue.h"
#include "src/Core/Flagged.h" #include "src/Core/Flagged.h"
#include "src/Core/NoAlias.h"
#include "src/Core/Matrix.h" #include "src/Core/Matrix.h"
#include "src/Core/Cwise.h" #include "src/Core/Cwise.h"
#include "src/Core/CwiseBinaryOp.h" #include "src/Core/CwiseBinaryOp.h"
@ -177,7 +179,6 @@ namespace Eigen {
#include "src/Core/IO.h" #include "src/Core/IO.h"
#include "src/Core/Swap.h" #include "src/Core/Swap.h"
#include "src/Core/CommaInitializer.h" #include "src/Core/CommaInitializer.h"
#include "src/Core/util/BlasUtil.h"
#include "src/Core/ProductBase.h" #include "src/Core/ProductBase.h"
#include "src/Core/Product.h" #include "src/Core/Product.h"
#include "src/Core/TriangularMatrix.h" #include "src/Core/TriangularMatrix.h"

View File

@ -7,6 +7,7 @@
#include "Array" #include "Array"
#include "SVD" #include "SVD"
#include "LU"
#include <limits> #include <limits>
#ifndef M_PI #ifndef M_PI

24
Eigen/Jacobi Normal file
View File

@ -0,0 +1,24 @@
#ifndef EIGEN_JACOBI_MODULE_H
#define EIGEN_JACOBI_MODULE_H
#include "Core"
#include "src/Core/util/DisableMSVCWarnings.h"
namespace Eigen {
/** \defgroup Jacobi_Module Jacobi module
* This module provides Jacobi rotations.
*
* \code
* #include <Eigen/Jacobi>
* \endcode
*/
#include "src/Jacobi/Jacobi.h"
} // namespace Eigen
#include "src/Core/util/EnableMSVCWarnings.h"
#endif // EIGEN_JACOBI_MODULE_H

View File

@ -6,6 +6,8 @@
#include "src/Core/util/DisableMSVCWarnings.h" #include "src/Core/util/DisableMSVCWarnings.h"
#include "Cholesky" #include "Cholesky"
#include "Jacobi"
#include "Householder"
// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module // Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module
#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) #if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2)

View File

@ -2,6 +2,8 @@
#define EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H
#include "Core" #include "Core"
#include "Householder"
#include "Jacobi"
#include "src/Core/util/DisableMSVCWarnings.h" #include "src/Core/util/DisableMSVCWarnings.h"
@ -21,6 +23,7 @@ namespace Eigen {
*/ */
#include "src/SVD/SVD.h" #include "src/SVD/SVD.h"
#include "src/SVD/JacobiSquareSVD.h"
} // namespace Eigen } // namespace Eigen

View File

@ -35,13 +35,13 @@ struct ei_functor_traits<ei_scalar_random_op<Scalar> >
/** \array_module /** \array_module
* *
* \returns a random matrix (not an expression, the matrix is immediately evaluated). * \returns a random matrix expression
* *
* The parameters \a rows and \a cols are the number of rows and of columns of * The parameters \a rows and \a cols are the number of rows and of columns of
* the returned matrix. Must be compatible with this MatrixBase type. * the returned matrix. Must be compatible with this MatrixBase type.
* *
* This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * This variant is meant to be used for dynamic-size matrix types. For fixed-size types,
* it is redundant to pass \a rows and \a cols as arguments, so ei_random() should be used * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used
* instead. * instead.
* *
* \addexample RandomExample \label How to create a matrix with random coefficients * \addexample RandomExample \label How to create a matrix with random coefficients
@ -49,6 +49,10 @@ struct ei_functor_traits<ei_scalar_random_op<Scalar> >
* Example: \include MatrixBase_random_int_int.cpp * Example: \include MatrixBase_random_int_int.cpp
* Output: \verbinclude MatrixBase_random_int_int.out * Output: \verbinclude MatrixBase_random_int_int.out
* *
* This expression has the "evaluate before nesting" flag so that it will be evaluated into
* a temporary matrix whenever it is nested in a larger expression. This prevents unexpected
* behavior with expressions involving random matrices.
*
* \sa MatrixBase::setRandom(), MatrixBase::Random(int), MatrixBase::Random() * \sa MatrixBase::setRandom(), MatrixBase::Random(int), MatrixBase::Random()
*/ */
template<typename Derived> template<typename Derived>
@ -60,7 +64,7 @@ MatrixBase<Derived>::Random(int rows, int cols)
/** \array_module /** \array_module
* *
* \returns a random vector (not an expression, the vector is immediately evaluated). * \returns a random vector expression
* *
* The parameter \a size is the size of the returned vector. * The parameter \a size is the size of the returned vector.
* Must be compatible with this MatrixBase type. * Must be compatible with this MatrixBase type.
@ -68,12 +72,16 @@ MatrixBase<Derived>::Random(int rows, int cols)
* \only_for_vectors * \only_for_vectors
* *
* This variant is meant to be used for dynamic-size vector types. For fixed-size types, * This variant is meant to be used for dynamic-size vector types. For fixed-size types,
* it is redundant to pass \a size as argument, so ei_random() should be used * it is redundant to pass \a size as argument, so Random() should be used
* instead. * instead.
* *
* Example: \include MatrixBase_random_int.cpp * Example: \include MatrixBase_random_int.cpp
* Output: \verbinclude MatrixBase_random_int.out * Output: \verbinclude MatrixBase_random_int.out
* *
* This expression has the "evaluate before nesting" flag so that it will be evaluated into
* a temporary vector whenever it is nested in a larger expression. This prevents unexpected
* behavior with expressions involving random matrices.
*
* \sa MatrixBase::setRandom(), MatrixBase::Random(int,int), MatrixBase::Random() * \sa MatrixBase::setRandom(), MatrixBase::Random(int,int), MatrixBase::Random()
*/ */
template<typename Derived> template<typename Derived>
@ -85,8 +93,7 @@ MatrixBase<Derived>::Random(int size)
/** \array_module /** \array_module
* *
* \returns a fixed-size random matrix or vector * \returns a fixed-size random matrix or vector expression
* (not an expression, the matrix is immediately evaluated).
* *
* This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you
* need to use the variants taking size arguments. * need to use the variants taking size arguments.
@ -94,6 +101,10 @@ MatrixBase<Derived>::Random(int size)
* Example: \include MatrixBase_random.cpp * Example: \include MatrixBase_random.cpp
* Output: \verbinclude MatrixBase_random.out * Output: \verbinclude MatrixBase_random.out
* *
* This expression has the "evaluate before nesting" flag so that it will be evaluated into
* a temporary matrix whenever it is nested in a larger expression. This prevents unexpected
* behavior with expressions involving random matrices.
*
* \sa MatrixBase::setRandom(), MatrixBase::Random(int,int), MatrixBase::Random(int) * \sa MatrixBase::setRandom(), MatrixBase::Random(int,int), MatrixBase::Random(int)
*/ */
template<typename Derived> template<typename Derived>

View File

@ -123,7 +123,7 @@ template<typename MatrixType> class LDLT
template<typename Derived> template<typename Derived>
bool solveInPlace(MatrixBase<Derived> &bAndX) const; bool solveInPlace(MatrixBase<Derived> &bAndX) const;
void compute(const MatrixType& matrix); LDLT& compute(const MatrixType& matrix);
protected: protected:
/** \internal /** \internal
@ -142,7 +142,7 @@ template<typename MatrixType> class LDLT
/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix
*/ */
template<typename MatrixType> template<typename MatrixType>
void LDLT<MatrixType>::compute(const MatrixType& a) LDLT<MatrixType>& LDLT<MatrixType>::compute(const MatrixType& a)
{ {
ei_assert(a.rows()==a.cols()); ei_assert(a.rows()==a.cols());
const int size = a.rows(); const int size = a.rows();
@ -154,7 +154,7 @@ void LDLT<MatrixType>::compute(const MatrixType& a)
m_transpositions.setZero(); m_transpositions.setZero();
m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1; m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1;
m_isInitialized = true; m_isInitialized = true;
return; return *this;
} }
RealScalar cutoff = 0, biggest_in_corner; RealScalar cutoff = 0, biggest_in_corner;
@ -180,7 +180,7 @@ void LDLT<MatrixType>::compute(const MatrixType& a)
// in "Analysis of the Cholesky Decomposition of a Semi-definite Matrix" by // in "Analysis of the Cholesky Decomposition of a Semi-definite Matrix" by
// Nicholas J. Higham. Also see "Accuracy and Stability of Numerical // Nicholas J. Higham. Also see "Accuracy and Stability of Numerical
// Algorithms" page 217, also by Higham. // Algorithms" page 217, also by Higham.
cutoff = ei_abs(machine_epsilon<Scalar>() * size * biggest_in_corner); cutoff = ei_abs(epsilon<Scalar>() * size * biggest_in_corner);
m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1;
} }
@ -235,6 +235,7 @@ void LDLT<MatrixType>::compute(const MatrixType& a)
} }
m_isInitialized = true; m_isInitialized = true;
return *this;
} }
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. /** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.

View File

@ -105,7 +105,7 @@ template<typename MatrixType, int _UpLo> class LLT
template<typename Derived> template<typename Derived>
bool solveInPlace(MatrixBase<Derived> &bAndX) const; bool solveInPlace(MatrixBase<Derived> &bAndX) const;
void compute(const MatrixType& matrix); LLT& compute(const MatrixType& matrix);
protected: protected:
/** \internal /** \internal
@ -213,9 +213,12 @@ template<typename MatrixType> struct LLT_Traits<MatrixType,UpperTriangular>
}; };
/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix /** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
*
*
* \returns a reference to *this
*/ */
template<typename MatrixType, int _UpLo> template<typename MatrixType, int _UpLo>
void LLT<MatrixType,_UpLo>::compute(const MatrixType& a) LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const MatrixType& a)
{ {
assert(a.rows()==a.cols()); assert(a.rows()==a.cols());
const int size = a.rows(); const int size = a.rows();
@ -223,6 +226,7 @@ void LLT<MatrixType,_UpLo>::compute(const MatrixType& a)
m_matrix = a; m_matrix = a;
m_isInitialized = Traits::inplace_decomposition(m_matrix); m_isInitialized = Traits::inplace_decomposition(m_matrix);
return *this;
} }
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. /** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.

View File

@ -57,7 +57,10 @@ private:
&& ((int(Derived::Flags)&RowMajorBit)==(int(OtherDerived::Flags)&RowMajorBit)), && ((int(Derived::Flags)&RowMajorBit)==(int(OtherDerived::Flags)&RowMajorBit)),
MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0
&& int(DstIsAligned) && int(SrcIsAligned), && int(DstIsAligned) && int(SrcIsAligned),
MayLinearVectorize = MightVectorize && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), MayLinearVectorize = MightVectorize && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit)
&& (DstIsAligned || InnerMaxSize == Dynamic),/* If the destination isn't aligned,
we have to do runtime checks and we don't unroll, so it's only good for large enough sizes. See remark below
about InnerMaxSize. */
MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize /* slice vectorization can be slow, so we only MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize /* slice vectorization can be slow, so we only
want it if the slices are big, which is indicated by InnerMaxSize rather than InnerSize, think of the case want it if the slices are big, which is indicated by InnerMaxSize rather than InnerSize, think of the case
of a dynamic block in a fixed-size matrix */ of a dynamic block in a fixed-size matrix */
@ -90,6 +93,25 @@ public:
? ( int(MayUnrollCompletely) && int(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) ? ( int(MayUnrollCompletely) && int(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) )
: int(NoUnrolling) : int(NoUnrolling)
}; };
static void debug()
{
EIGEN_DEBUG_VAR(DstIsAligned)
EIGEN_DEBUG_VAR(SrcIsAligned)
EIGEN_DEBUG_VAR(SrcAlignment)
EIGEN_DEBUG_VAR(InnerSize)
EIGEN_DEBUG_VAR(InnerMaxSize)
EIGEN_DEBUG_VAR(PacketSize)
EIGEN_DEBUG_VAR(MightVectorize)
EIGEN_DEBUG_VAR(MayInnerVectorize)
EIGEN_DEBUG_VAR(MayLinearVectorize)
EIGEN_DEBUG_VAR(MaySliceVectorize)
EIGEN_DEBUG_VAR(Vectorization)
EIGEN_DEBUG_VAR(UnrollingLimit)
EIGEN_DEBUG_VAR(MayUnrollCompletely)
EIGEN_DEBUG_VAR(MayUnrollInner)
EIGEN_DEBUG_VAR(Unrolling)
}
}; };
/*************************************************************************** /***************************************************************************
@ -405,6 +427,9 @@ EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
ei_assert(rows() == other.rows() && cols() == other.cols()); ei_assert(rows() == other.rows() && cols() == other.cols());
ei_assign_impl<Derived, OtherDerived>::run(derived(),other.derived()); ei_assign_impl<Derived, OtherDerived>::run(derived(),other.derived());
#ifdef EIGEN_DEBUG_ASSIGN
ei_assign_traits<Derived, OtherDerived>::debug();
#endif
return derived(); return derived();
} }

View File

@ -130,14 +130,14 @@ class BandMatrix : public AnyMatrixBase<BandMatrix<_Scalar,Rows,Cols,Supers,Subs
template<int Index> struct DiagonalIntReturnType { template<int Index> struct DiagonalIntReturnType {
enum { enum {
ReturnOpposite = (Options&SelfAdjoint) && (Index>0 && Supers==0 || Index<0 && Subs==0), ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)),
Conjugate = ReturnOpposite && NumTraits<Scalar>::IsComplex, Conjugate = ReturnOpposite && NumTraits<Scalar>::IsComplex,
ActualIndex = ReturnOpposite ? -Index : Index, ActualIndex = ReturnOpposite ? -Index : Index,
DiagonalSize = RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic)
? Dynamic ? Dynamic
: ActualIndex<0 : (ActualIndex<0
? EIGEN_ENUM_MIN(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) ? EIGEN_ENUM_MIN(ColsAtCompileTime, RowsAtCompileTime + ActualIndex)
: EIGEN_ENUM_MIN(RowsAtCompileTime, ColsAtCompileTime - ActualIndex) : EIGEN_ENUM_MIN(RowsAtCompileTime, ColsAtCompileTime - ActualIndex))
}; };
typedef Block<DataType,1, DiagonalSize> BuildType; typedef Block<DataType,1, DiagonalSize> BuildType;
typedef typename ei_meta_if<Conjugate, typedef typename ei_meta_if<Conjugate,

View File

@ -85,6 +85,8 @@ class CwiseBinaryOp : ei_no_assignment_operator,
EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp)
typedef typename ei_traits<CwiseBinaryOp>::LhsNested LhsNested; typedef typename ei_traits<CwiseBinaryOp>::LhsNested LhsNested;
typedef typename ei_traits<CwiseBinaryOp>::RhsNested RhsNested; typedef typename ei_traits<CwiseBinaryOp>::RhsNested RhsNested;
typedef typename ei_traits<CwiseBinaryOp>::_LhsNested _LhsNested;
typedef typename ei_traits<CwiseBinaryOp>::_RhsNested _RhsNested;
EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp()) EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
: m_lhs(lhs), m_rhs(rhs), m_functor(func) : m_lhs(lhs), m_rhs(rhs), m_functor(func)
@ -130,6 +132,10 @@ class CwiseBinaryOp : ei_no_assignment_operator,
return m_functor.packetOp(m_lhs.template packet<LoadMode>(index), m_rhs.template packet<LoadMode>(index)); return m_functor.packetOp(m_lhs.template packet<LoadMode>(index), m_rhs.template packet<LoadMode>(index));
} }
const _LhsNested& lhs() const { return m_lhs; }
const _RhsNested& rhs() const { return m_rhs; }
const BinaryOp& functor() const { return m_functor; }
protected: protected:
const LhsNested m_lhs; const LhsNested m_lhs;
const RhsNested m_rhs; const RhsNested m_rhs;

View File

@ -25,7 +25,9 @@
#ifndef EIGEN_FLAGGED_H #ifndef EIGEN_FLAGGED_H
#define EIGEN_FLAGGED_H #define EIGEN_FLAGGED_H
/** \class Flagged /** \deprecated it is only used by lazy() which is deprecated
*
* \class Flagged
* *
* \brief Expression with modified flags * \brief Expression with modified flags
* *
@ -111,9 +113,9 @@ template<typename ExpressionType, unsigned int Added, unsigned int Removed> clas
ExpressionTypeNested m_matrix; ExpressionTypeNested m_matrix;
}; };
/** \returns an expression of *this with added flags /** \deprecated it is only used by lazy() which is deprecated
* *
* \addexample MarkExample \label How to mark a triangular matrix as triangular * \returns an expression of *this with added flags
* *
* Example: \include MatrixBase_marked.cpp * Example: \include MatrixBase_marked.cpp
* Output: \verbinclude MatrixBase_marked.out * Output: \verbinclude MatrixBase_marked.out
@ -128,8 +130,9 @@ MatrixBase<Derived>::marked() const
return derived(); return derived();
} }
/** \returns an expression of *this with the following flags removed: /** \deprecated use MatrixBase::noalias()
* EvalBeforeNestingBit and EvalBeforeAssigningBit. *
* \returns an expression of *this with the EvalBeforeAssigningBit flag removed.
* *
* Example: \include MatrixBase_lazy.cpp * Example: \include MatrixBase_lazy.cpp
* Output: \verbinclude MatrixBase_lazy.out * Output: \verbinclude MatrixBase_lazy.out
@ -137,7 +140,7 @@ MatrixBase<Derived>::marked() const
* \sa class Flagged, marked() * \sa class Flagged, marked()
*/ */
template<typename Derived> template<typename Derived>
inline const Flagged<Derived, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit> inline const Flagged<Derived, 0, EvalBeforeAssigningBit>
MatrixBase<Derived>::lazy() const MatrixBase<Derived>::lazy() const
{ {
return derived(); return derived();

View File

@ -26,15 +26,22 @@
#ifndef EIGEN_IO_H #ifndef EIGEN_IO_H
#define EIGEN_IO_H #define EIGEN_IO_H
enum { Raw, AlignCols }; enum { DontAlignCols = 1 };
enum { StreamPrecision = -1,
FullPrecision = -2 };
/** \class IOFormat /** \class IOFormat
* *
* \brief Stores a set of parameters controlling the way matrices are printed * \brief Stores a set of parameters controlling the way matrices are printed
* *
* List of available parameters: * List of available parameters:
* - \b precision number of digits for floating point values * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision.
* - \b flags can be either Raw (default) or AlignCols which aligns all the columns * The default is the special value \c StreamPrecision which means to use the
* stream's own precision setting, as set for instance using \c cout.precision(3). The other special value
* \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point
* type.
* - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which
* allows to disable the alignment of columns, resulting in faster code.
* - \b coeffSeparator string printed between two coefficients of the same row * - \b coeffSeparator string printed between two coefficients of the same row
* - \b rowSeparator string printed between two rows * - \b rowSeparator string printed between two rows
* - \b rowPrefix string printed at the beginning of each row * - \b rowPrefix string printed at the beginning of each row
@ -50,7 +57,7 @@ enum { Raw, AlignCols };
struct IOFormat struct IOFormat
{ {
/** Default contructor, see class IOFormat for the meaning of the parameters */ /** Default contructor, see class IOFormat for the meaning of the parameters */
IOFormat(int _precision=4, int _flags=Raw, IOFormat(int _precision = StreamPrecision, int _flags = 0,
const std::string& _coeffSeparator = " ", const std::string& _coeffSeparator = " ",
const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="",
const std::string& _matPrefix="", const std::string& _matSuffix="") const std::string& _matPrefix="", const std::string& _matSuffix="")
@ -125,21 +132,41 @@ template<typename Derived>
std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt)
{ {
const typename Derived::Nested m = _m; const typename Derived::Nested m = _m;
typedef typename Derived::Scalar Scalar;
int width = 0; int width = 0;
if (fmt.flags & AlignCols)
std::streamsize explicit_precision;
if(fmt.precision == StreamPrecision)
{
explicit_precision = 0;
}
else if(fmt.precision == FullPrecision)
{
explicit_precision = NumTraits<Scalar>::HasFloatingPoint
? std::ceil(-ei_log(epsilon<Scalar>())/ei_log(10.0))
: 0;
}
else
{
explicit_precision = fmt.precision;
}
bool align_cols = !(fmt.flags & DontAlignCols);
if(align_cols)
{ {
// compute the largest width // compute the largest width
for(int j = 1; j < m.cols(); ++j) for(int j = 1; j < m.cols(); ++j)
for(int i = 0; i < m.rows(); ++i) for(int i = 0; i < m.rows(); ++i)
{ {
std::stringstream sstr; std::stringstream sstr;
sstr.precision(fmt.precision); if(explicit_precision) sstr.precision(explicit_precision);
sstr << m.coeff(i,j); sstr << m.coeff(i,j);
width = std::max<int>(width, int(sstr.str().length())); width = std::max<int>(width, int(sstr.str().length()));
} }
} }
s.precision(fmt.precision); std::streamsize old_precision = 0;
if(explicit_precision) old_precision = s.precision(explicit_precision);
s << fmt.matPrefix; s << fmt.matPrefix;
for(int i = 0; i < m.rows(); ++i) for(int i = 0; i < m.rows(); ++i)
{ {
@ -159,6 +186,7 @@ std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOForm
s << fmt.rowSeparator; s << fmt.rowSeparator;
} }
s << fmt.matSuffix; s << fmt.matSuffix;
if(explicit_precision) s.precision(old_precision);
return s; return s;
} }

View File

@ -66,11 +66,11 @@ template<typename Derived> class MapBase
inline const Scalar* data() const { return m_data; } inline const Scalar* data() const { return m_data; }
template<bool IsForceAligned,typename Dummy> struct force_aligned_impl { template<bool IsForceAligned,typename Dummy> struct force_aligned_impl {
AlignedDerivedType static run(MapBase& a) { return a.derived(); } static AlignedDerivedType run(MapBase& a) { return a.derived(); }
}; };
template<typename Dummy> struct force_aligned_impl<false,Dummy> { template<typename Dummy> struct force_aligned_impl<false,Dummy> {
AlignedDerivedType static run(MapBase& a) { return a.derived()._convertToForceAligned(); } static AlignedDerivedType run(MapBase& a) { return a.derived()._convertToForceAligned(); }
}; };
/** \returns an expression equivalent to \c *this but having the \c PacketAccess constant /** \returns an expression equivalent to \c *this but having the \c PacketAccess constant
@ -179,11 +179,11 @@ template<typename Derived> class MapBase
// explicitly add these two overloads. // explicitly add these two overloads.
// Maybe there exists a better solution though. // Maybe there exists a better solution though.
template<typename ProductDerived, typename Lhs,typename Rhs> template<typename ProductDerived, typename Lhs,typename Rhs>
Derived& operator+=(const Flagged<ProductBase<ProductDerived,Lhs,Rhs>, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) Derived& operator+=(const Flagged<ProductBase<ProductDerived,Lhs,Rhs>, 0, EvalBeforeAssigningBit>& other)
{ return Base::operator+=(other); } { return Base::operator+=(other); }
template<typename ProductDerived, typename Lhs,typename Rhs> template<typename ProductDerived, typename Lhs,typename Rhs>
Derived& operator-=(const Flagged<ProductBase<ProductDerived,Lhs,Rhs>, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) Derived& operator-=(const Flagged<ProductBase<ProductDerived,Lhs,Rhs>, 0, EvalBeforeAssigningBit>& other)
{ return Base::operator-=(other); } { return Base::operator-=(other); }
template<typename OtherDerived> template<typename OtherDerived>

View File

@ -1,7 +1,7 @@
// This file is part of Eigen, a lightweight C++ template library // This file is part of Eigen, a lightweight C++ template library
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> // Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
// //
// Eigen is free software; you can redistribute it and/or // Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
@ -25,8 +25,13 @@
#ifndef EIGEN_MATHFUNCTIONS_H #ifndef EIGEN_MATHFUNCTIONS_H
#define EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H
template<typename T> inline typename NumTraits<T>::Real epsilon()
{
return std::numeric_limits<typename NumTraits<T>::Real>::epsilon();
}
template<typename T> inline typename NumTraits<T>::Real precision(); template<typename T> inline typename NumTraits<T>::Real precision();
template<typename T> inline typename NumTraits<T>::Real machine_epsilon();
template<typename T> inline T ei_random(T a, T b); template<typename T> inline T ei_random(T a, T b);
template<typename T> inline T ei_random(); template<typename T> inline T ei_random();
template<typename T> inline T ei_random_amplitude() template<typename T> inline T ei_random_amplitude()
@ -51,7 +56,6 @@ template<typename T> inline typename NumTraits<T>::Real ei_hypot(T x, T y)
**************/ **************/
template<> inline int precision<int>() { return 0; } template<> inline int precision<int>() { return 0; }
template<> inline int machine_epsilon<int>() { return 0; }
inline int ei_real(int x) { return x; } inline int ei_real(int x) { return x; }
inline int& ei_real_ref(int& x) { return x; } inline int& ei_real_ref(int& x) { return x; }
inline int ei_imag(int) { return 0; } inline int ei_imag(int) { return 0; }
@ -106,7 +110,6 @@ inline bool ei_isApproxOrLessThan(int a, int b, int = precision<int>())
**************/ **************/
template<> inline float precision<float>() { return 1e-5f; } template<> inline float precision<float>() { return 1e-5f; }
template<> inline float machine_epsilon<float>() { return 1.192e-07f; }
inline float ei_real(float x) { return x; } inline float ei_real(float x) { return x; }
inline float& ei_real_ref(float& x) { return x; } inline float& ei_real_ref(float& x) { return x; }
inline float ei_imag(float) { return 0.f; } inline float ei_imag(float) { return 0.f; }
@ -154,7 +157,6 @@ inline bool ei_isApproxOrLessThan(float a, float b, float prec = precision<float
**************/ **************/
template<> inline double precision<double>() { return 1e-12; } template<> inline double precision<double>() { return 1e-12; }
template<> inline double machine_epsilon<double>() { return 2.220e-16; }
inline double ei_real(double x) { return x; } inline double ei_real(double x) { return x; }
inline double& ei_real_ref(double& x) { return x; } inline double& ei_real_ref(double& x) { return x; }
@ -203,7 +205,6 @@ inline bool ei_isApproxOrLessThan(double a, double b, double prec = precision<do
*********************/ *********************/
template<> inline float precision<std::complex<float> >() { return precision<float>(); } template<> inline float precision<std::complex<float> >() { return precision<float>(); }
template<> inline float machine_epsilon<std::complex<float> >() { return machine_epsilon<float>(); }
inline float ei_real(const std::complex<float>& x) { return std::real(x); } inline float ei_real(const std::complex<float>& x) { return std::real(x); }
inline float ei_imag(const std::complex<float>& x) { return std::imag(x); } inline float ei_imag(const std::complex<float>& x) { return std::imag(x); }
inline float& ei_real_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[0]; } inline float& ei_real_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[0]; }
@ -240,7 +241,6 @@ inline bool ei_isApprox(const std::complex<float>& a, const std::complex<float>&
**********************/ **********************/
template<> inline double precision<std::complex<double> >() { return precision<double>(); } template<> inline double precision<std::complex<double> >() { return precision<double>(); }
template<> inline double machine_epsilon<std::complex<double> >() { return machine_epsilon<double>(); }
inline double ei_real(const std::complex<double>& x) { return std::real(x); } inline double ei_real(const std::complex<double>& x) { return std::real(x); }
inline double ei_imag(const std::complex<double>& x) { return std::imag(x); } inline double ei_imag(const std::complex<double>& x) { return std::imag(x); }
inline double& ei_real_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[0]; } inline double& ei_real_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[0]; }
@ -278,7 +278,6 @@ inline bool ei_isApprox(const std::complex<double>& a, const std::complex<double
******************/ ******************/
template<> inline long double precision<long double>() { return precision<double>(); } template<> inline long double precision<long double>() { return precision<double>(); }
template<> inline long double machine_epsilon<long double>() { return 1.084e-19l; }
inline long double ei_real(long double x) { return x; } inline long double ei_real(long double x) { return x; }
inline long double& ei_real_ref(long double& x) { return x; } inline long double& ei_real_ref(long double& x) { return x; }
inline long double ei_imag(long double) { return 0.; } inline long double ei_imag(long double) { return 0.; }

View File

@ -326,9 +326,10 @@ template<typename Derived> class MatrixBase
template<typename OtherDerived> template<typename OtherDerived>
Derived& lazyAssign(const MatrixBase<OtherDerived>& other); Derived& lazyAssign(const MatrixBase<OtherDerived>& other);
/** Overloaded for cache friendly product evaluation */ /** \deprecated because .lazy() is deprecated
* Overloaded for cache friendly product evaluation */
template<typename OtherDerived> template<typename OtherDerived>
Derived& lazyAssign(const Flagged<OtherDerived, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) Derived& lazyAssign(const Flagged<OtherDerived, 0, EvalBeforeAssigningBit>& other)
{ return lazyAssign(other._expression()); } { return lazyAssign(other._expression()); }
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
@ -336,11 +337,11 @@ template<typename Derived> class MatrixBase
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0, Derived& operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
EvalBeforeNestingBit | EvalBeforeAssigningBit>& other); EvalBeforeAssigningBit>& other);
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0, Derived& operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
EvalBeforeNestingBit | EvalBeforeAssigningBit>& other); EvalBeforeAssigningBit>& other);
#endif // not EIGEN_PARSED_BY_DOXYGEN #endif // not EIGEN_PARSED_BY_DOXYGEN
CommaInitializer<Derived> operator<< (const Scalar& s); CommaInitializer<Derived> operator<< (const Scalar& s);
@ -456,6 +457,21 @@ template<typename Derived> class MatrixBase
void transposeInPlace(); void transposeInPlace();
const AdjointReturnType adjoint() const; const AdjointReturnType adjoint() const;
void adjointInPlace(); void adjointInPlace();
#ifndef EIGEN_NO_DEBUG
template<typename OtherDerived>
Derived& lazyAssign(const Transpose<OtherDerived>& other);
template<typename DerivedA, typename DerivedB>
Derived& lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,Transpose<DerivedA>,DerivedB>& other);
template<typename DerivedA, typename DerivedB>
Derived& lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,Transpose<DerivedB> >& other);
template<typename OtherDerived>
Derived& lazyAssign(const CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<OtherDerived> > >& other);
template<typename DerivedA, typename DerivedB>
Derived& lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedA> > >,DerivedB>& other);
template<typename DerivedA, typename DerivedB>
Derived& lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedB> > > >& other);
#endif
RowXpr row(int i); RowXpr row(int i);
const RowXpr row(int i) const; const RowXpr row(int i) const;
@ -614,7 +630,9 @@ template<typename Derived> class MatrixBase
template<unsigned int Added> template<unsigned int Added>
const Flagged<Derived, Added, 0> marked() const; const Flagged<Derived, Added, 0> marked() const;
const Flagged<Derived, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit> lazy() const; const Flagged<Derived, 0, EvalBeforeAssigningBit> lazy() const;
NoAlias<Derived> noalias();
/** \returns number of elements to skip to pass from one row (resp. column) to another /** \returns number of elements to skip to pass from one row (resp. column) to another
* for a row-major (resp. column-major) matrix. * for a row-major (resp. column-major) matrix.
@ -768,16 +786,26 @@ template<typename Derived> class MatrixBase
////////// Householder module /////////// ////////// Householder module ///////////
void makeHouseholderInPlace(Scalar *tau, RealScalar *beta);
template<typename EssentialPart> template<typename EssentialPart>
void makeHouseholder(EssentialPart *essential, void makeHouseholder(EssentialPart *essential,
RealScalar *beta) const; Scalar *tau, RealScalar *beta) const;
template<typename EssentialPart> template<typename EssentialPart>
void applyHouseholderOnTheLeft(const EssentialPart& essential, void applyHouseholderOnTheLeft(const EssentialPart& essential,
const RealScalar& beta); const Scalar& tau,
Scalar* workspace);
template<typename EssentialPart> template<typename EssentialPart>
void applyHouseholderOnTheRight(const EssentialPart& essential, void applyHouseholderOnTheRight(const EssentialPart& essential,
const RealScalar& beta); const Scalar& tau,
Scalar* workspace);
///////// Jacobi module /////////
void applyJacobiOnTheLeft(int p, int q, Scalar c, Scalar s);
void applyJacobiOnTheRight(int p, int q, Scalar c, Scalar s);
bool makeJacobi(int p, int q, Scalar *c, Scalar *s) const;
bool makeJacobiForAtA(int p, int q, Scalar *c, Scalar *s) const;
bool makeJacobiForAAt(int p, int q, Scalar *c, Scalar *s) const;
#ifdef EIGEN_MATRIXBASE_PLUGIN #ifdef EIGEN_MATRIXBASE_PLUGIN
#include EIGEN_MATRIXBASE_PLUGIN #include EIGEN_MATRIXBASE_PLUGIN

112
Eigen/src/Core/NoAlias.h Normal file
View File

@ -0,0 +1,112 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef EIGEN_NOALIAS_H
#define EIGEN_NOALIAS_H
/** \class NoAlias
*
* \brief Pseudo expression providing an operator = assuming no aliasing
*
* \param ExpressionType the type of the object on which to do the lazy assignment
*
* This class represents an expression with special assignment operators
* assuming no aliasing between the target expression and the source expression.
* More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression.
* It is the return type of MatrixBase::noalias()
* and most of the time this is the only way it is used.
*
* \sa MatrixBase::noalias()
*/
template<typename ExpressionType>
class NoAlias
{
public:
NoAlias(ExpressionType& expression) : m_expression(expression) {}
/** Behaves like MatrixBase::lazyAssign(other)
* \sa MatrixBase::lazyAssign() */
template<typename OtherDerived>
EIGEN_STRONG_INLINE ExpressionType& operator=(const MatrixBase<OtherDerived>& other)
{ return m_expression.lazyAssign(other.derived()); }
/** \sa MatrixBase::operator+= */
template<typename OtherDerived>
EIGEN_STRONG_INLINE ExpressionType& operator+=(const MatrixBase<OtherDerived>& other)
{ return m_expression.lazyAssign(m_expression + other.derived()); }
/** \sa MatrixBase::operator-= */
template<typename OtherDerived>
EIGEN_STRONG_INLINE ExpressionType& operator-=(const MatrixBase<OtherDerived>& other)
{ return m_expression.lazyAssign(m_expression - other.derived()); }
#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename ProductDerived, typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{ other.derived().addTo(m_expression); return m_expression; }
template<typename ProductDerived, typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{ other.derived().subTo(m_expression); return m_expression; }
#endif
protected:
ExpressionType& m_expression;
};
/** \returns a pseudo expression of \c *this with an operator= assuming
* no aliasing between \c *this and the source expression.
*
* More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag.
* Currently, even though several expressions may alias, only product
* expressions have this flag. Therefore, noalias() is only usefull when
* the source expression contains a matrix product.
*
* Here are some examples where noalias is usefull:
* \code
* D.noalias() = A * B;
* D.noalias() += A.transpose() * B;
* D.noalias() -= 2 * A * B.adjoint();
* \endcode
*
* On the other hand the following example will lead to a \b wrong result:
* \code
* A.noalias() = A * B;
* \endcode
* because the result matrix A is also an operand of the matrix product. Therefore,
* there is no alternative than evaluating A * B in a temporary, that is the default
* behavior when you write:
* \code
* A = A * B;
* \endcode
*
* \sa class NoAlias
*/
template<typename Derived>
NoAlias<Derived> MatrixBase<Derived>::noalias()
{
return derived();
}
#endif // EIGEN_NOALIAS_H

View File

@ -153,10 +153,10 @@ class GeneralProduct<Lhs, Rhs, InnerProduct>
GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(dst.rows()==1 && dst.cols()==1); ei_assert(dst.rows()==1 && dst.cols()==1);
dst.coeffRef(0,0) += alpha * (m_lhs.cwise()*m_rhs).sum(); dst.coeffRef(0,0) += alpha * (m_lhs.transpose().cwise()*m_rhs).sum();
} }
}; };
@ -179,7 +179,7 @@ class GeneralProduct<Lhs, Rhs, OuterProduct>
GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dest, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
{ {
ei_outer_product_selector<Dest::Flags&RowMajorBit>::run(*this, dest, alpha); ei_outer_product_selector<Dest::Flags&RowMajorBit>::run(*this, dest, alpha);
} }
@ -187,7 +187,7 @@ class GeneralProduct<Lhs, Rhs, OuterProduct>
template<> struct ei_outer_product_selector<ColMajor> { template<> struct ei_outer_product_selector<ColMajor> {
template<typename ProductType, typename Dest> template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { EIGEN_DONT_INLINE static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
// FIXME make sure lhs is sequentially stored // FIXME make sure lhs is sequentially stored
const int cols = dest.cols(); const int cols = dest.cols();
for (int j=0; j<cols; ++j) for (int j=0; j<cols; ++j)
@ -197,7 +197,7 @@ template<> struct ei_outer_product_selector<ColMajor> {
template<> struct ei_outer_product_selector<RowMajor> { template<> struct ei_outer_product_selector<RowMajor> {
template<typename ProductType, typename Dest> template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) { EIGEN_DONT_INLINE static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
// FIXME make sure rhs is sequentially stored // FIXME make sure rhs is sequentially stored
const int rows = dest.rows(); const int rows = dest.rows();
for (int i=0; i<rows; ++i) for (int i=0; i<rows; ++i)
@ -236,7 +236,7 @@ class GeneralProduct<Lhs, Rhs, GemvProduct>
enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight };
typedef typename ei_meta_if<int(Side)==OnTheRight,_LhsNested,_RhsNested>::ret MatrixType; typedef typename ei_meta_if<int(Side)==OnTheRight,_LhsNested,_RhsNested>::ret MatrixType;
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); ei_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
ei_gemv_selector<Side,int(MatrixType::Flags)&RowMajorBit, ei_gemv_selector<Side,int(MatrixType::Flags)&RowMajorBit,

View File

@ -100,29 +100,27 @@ class ProductBase : public MatrixBase<Derived>
inline int cols() const { return m_rhs.cols(); } inline int cols() const { return m_rhs.cols(); }
template<typename Dest> template<typename Dest>
inline void evalTo(Dest& dst) const { dst.setZero(); addTo(dst,1); } inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,1); }
template<typename Dest> template<typename Dest>
inline void addTo(Dest& dst) const { addTo(dst,1); } inline void addTo(Dest& dst) const { scaleAndAddTo(dst,1); }
template<typename Dest> template<typename Dest>
inline void subTo(Dest& dst) const { addTo(dst,-1); } inline void subTo(Dest& dst) const { scaleAndAddTo(dst,-1); }
template<typename Dest> template<typename Dest>
inline void addTo(Dest& dst,Scalar alpha) const { derived().addTo(dst,alpha); } inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { derived().scaleAndAddTo(dst,alpha); }
PlainMatrixType eval() const PlainMatrixType eval() const
{ {
PlainMatrixType res(rows(), cols()); PlainMatrixType res(rows(), cols());
res.setZero(); res.setZero();
evalTo(res); derived().evalTo(res);
return res; return res;
} }
const Flagged<ProductBase, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit> lazy() const EIGEN_DEPRECATED const Flagged<ProductBase, 0, EvalBeforeAssigningBit> lazy() const
{ { return *this; }
return *this;
}
const _LhsNested& lhs() const { return m_lhs; } const _LhsNested& lhs() const { return m_lhs; }
const _RhsNested& rhs() const { return m_rhs; } const _RhsNested& rhs() const { return m_rhs; }
@ -141,13 +139,86 @@ class ProductBase : public MatrixBase<Derived>
void coeffRef(int); void coeffRef(int);
}; };
template<typename NestedProduct>
class ScaledProduct;
// Note that these two operator* functions are not defined as member
// functions of ProductBase, because, otherwise we would have to
// define all overloads defined in MatrixBase. Furthermore, Using
// "using Base::operator*" would not work with MSVC.
//
// Also note that here we accept any compatible scalar types
template<typename Derived,typename Lhs,typename Rhs>
const ScaledProduct<Derived>
operator*(const ProductBase<Derived,Lhs,Rhs>& prod, typename Derived::Scalar x)
{ return ScaledProduct<Derived>(prod.derived(), x); }
template<typename Derived,typename Lhs,typename Rhs>
typename ei_enable_if<!ei_is_same_type<typename Derived::Scalar,typename Derived::RealScalar>::ret,
const ScaledProduct<Derived> >::type
operator*(const ProductBase<Derived,Lhs,Rhs>& prod, typename Derived::RealScalar x)
{ return ScaledProduct<Derived>(prod.derived(), x); }
template<typename Derived,typename Lhs,typename Rhs>
const ScaledProduct<Derived>
operator*(typename Derived::Scalar x,const ProductBase<Derived,Lhs,Rhs>& prod)
{ return ScaledProduct<Derived>(prod.derived(), x); }
template<typename Derived,typename Lhs,typename Rhs>
typename ei_enable_if<!ei_is_same_type<typename Derived::Scalar,typename Derived::RealScalar>::ret,
const ScaledProduct<Derived> >::type
operator*(typename Derived::RealScalar x,const ProductBase<Derived,Lhs,Rhs>& prod)
{ return ScaledProduct<Derived>(prod.derived(), x); }
template<typename NestedProduct>
struct ei_traits<ScaledProduct<NestedProduct> >
: ei_traits<ProductBase<ScaledProduct<NestedProduct>,
typename NestedProduct::_LhsNested,
typename NestedProduct::_RhsNested> >
{};
template<typename NestedProduct>
class ScaledProduct
: public ProductBase<ScaledProduct<NestedProduct>,
typename NestedProduct::_LhsNested,
typename NestedProduct::_RhsNested>
{
public:
typedef ProductBase<ScaledProduct<NestedProduct>,
typename NestedProduct::_LhsNested,
typename NestedProduct::_RhsNested> Base;
typedef typename Base::Scalar Scalar;
// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct)
ScaledProduct(const NestedProduct& prod, Scalar x)
: Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {}
template<typename Dest>
inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,m_alpha); }
template<typename Dest>
inline void addTo(Dest& dst) const { scaleAndAddTo(dst,m_alpha); }
template<typename Dest>
inline void subTo(Dest& dst) const { scaleAndAddTo(dst,-m_alpha); }
template<typename Dest>
inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { m_prod.derived().scaleAndAddTo(dst,alpha); }
protected:
const NestedProduct& m_prod;
Scalar m_alpha;
};
/** \internal /** \internal
* Overloaded to perform an efficient C = (A*B).lazy() */ * Overloaded to perform an efficient C = (A*B).lazy() */
template<typename Derived> template<typename Derived>
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other) Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{ {
other.evalTo(derived()); return derived(); other.derived().evalTo(derived()); return derived();
} }
/** \internal /** \internal
@ -155,9 +226,9 @@ Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,R
template<typename Derived> template<typename Derived>
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0, Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) EvalBeforeAssigningBit>& other)
{ {
other._expression().addTo(derived()); return derived(); other._expression().derived().addTo(derived()); return derived();
} }
/** \internal /** \internal
@ -165,9 +236,9 @@ Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerive
template<typename Derived> template<typename Derived>
template<typename ProductDerived, typename Lhs, typename Rhs> template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& MatrixBase<Derived>::operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0, Derived& MatrixBase<Derived>::operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) EvalBeforeAssigningBit>& other)
{ {
other._expression().subTo(derived()); return derived(); other._expression().derived().subTo(derived()); return derived();
} }
#endif // EIGEN_PRODUCTBASE_H #endif // EIGEN_PRODUCTBASE_H

View File

@ -115,20 +115,20 @@ MatrixBase<Derived>::blueNorm() const
ei_assert(false && "the algorithm cannot be guaranteed on this computer"); ei_assert(false && "the algorithm cannot be guaranteed on this computer");
} }
iexp = -((1-iemin)/2); iexp = -((1-iemin)/2);
b1 = std::pow(double(ibeta),iexp); // lower boundary of midrange b1 = RealScalar(std::pow(double(ibeta),iexp)); // lower boundary of midrange
iexp = (iemax + 1 - it)/2; iexp = (iemax + 1 - it)/2;
b2 = std::pow(double(ibeta),iexp); // upper boundary of midrange b2 = RealScalar(std::pow(double(ibeta),iexp)); // upper boundary of midrange
iexp = (2-iemin)/2; iexp = (2-iemin)/2;
s1m = std::pow(double(ibeta),iexp); // scaling factor for lower range s1m = RealScalar(std::pow(double(ibeta),iexp)); // scaling factor for lower range
iexp = - ((iemax+it)/2); iexp = - ((iemax+it)/2);
s2m = std::pow(double(ibeta),iexp); // scaling factor for upper range s2m = RealScalar(std::pow(double(ibeta),iexp)); // scaling factor for upper range
overfl = rbig*s2m; // overfow boundary for abig overfl = rbig*s2m; // overfow boundary for abig
eps = std::pow(double(ibeta), 1-it); eps = RealScalar(std::pow(double(ibeta), 1-it));
relerr = ei_sqrt(eps); // tolerance for neglecting asml relerr = ei_sqrt(eps); // tolerance for neglecting asml
abig = 1.0/eps - 1.0; abig = 1.0/eps - 1.0;
if (RealScalar(nbig)>abig) nmax = abig; // largest safe n if (RealScalar(nbig)>abig) nmax = int(abig); // largest safe n
else nmax = nbig; else nmax = nbig;
} }
int n = size(); int n = size();

View File

@ -267,4 +267,92 @@ inline void MatrixBase<Derived>::adjointInPlace()
derived() = adjoint().eval(); derived() = adjoint().eval();
} }
#ifndef EIGEN_NO_DEBUG
// The following is to detect aliasing problems in the following common cases:
// a = a.transpose()
// a = a.transpose() + X
// a = X + a.transpose()
// a = a.adjoint()
// a = a.adjoint() + X
// a = X + a.adjoint()
template<typename T, int Access=ei_blas_traits<T>::ActualAccess>
struct ei_extract_data_selector {
static typename T::Scalar* run(const T& m)
{
return &ei_blas_traits<T>::extract(m).const_cast_derived().coeffRef(0,0);
}
};
template<typename T>
struct ei_extract_data_selector<T,NoDirectAccess> {
static typename T::Scalar* run(const T&) { return 0; }
};
template<typename T> typename T::Scalar* ei_extract_data(const T& m)
{
return ei_extract_data_selector<T>::run(m);
}
template<typename Derived>
template<typename OtherDerived>
Derived& MatrixBase<Derived>::lazyAssign(const Transpose<OtherDerived>& other)
{
ei_assert(ei_extract_data(other) != ei_extract_data(derived())
&& "aliasing detected during tranposition, please use transposeInPlace()");
return lazyAssign(static_cast<const MatrixBase<Transpose<OtherDerived> >& >(other));
}
template<typename Derived>
template<typename DerivedA, typename DerivedB>
Derived& MatrixBase<Derived>::
lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,Transpose<DerivedA>,DerivedB>& other)
{
ei_assert(ei_extract_data(derived()) != ei_extract_data(other.lhs())
&& "aliasing detected during tranposition, please evaluate your expression");
return lazyAssign(static_cast<const MatrixBase<CwiseBinaryOp<ei_scalar_sum_op<Scalar>,Transpose<DerivedA>,DerivedB> >& >(other));
}
template<typename Derived>
template<typename DerivedA, typename DerivedB>
Derived& MatrixBase<Derived>::
lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,Transpose<DerivedB> >& other)
{
ei_assert(ei_extract_data(derived()) != ei_extract_data(other.rhs())
&& "aliasing detected during tranposition, please evaluate your expression");
return lazyAssign(static_cast<const MatrixBase<CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,Transpose<DerivedB> > >& >(other));
}
template<typename Derived>
template<typename OtherDerived> Derived&
MatrixBase<Derived>::
lazyAssign(const CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<OtherDerived> > >& other)
{
ei_assert(ei_extract_data(other) != ei_extract_data(derived())
&& "aliasing detected during tranposition, please use adjointInPlace()");
return lazyAssign(static_cast<const MatrixBase<CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<OtherDerived> > > >& >(other));
}
template<typename Derived>
template<typename DerivedA, typename DerivedB>
Derived& MatrixBase<Derived>::
lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedA> > >,DerivedB>& other)
{
ei_assert(ei_extract_data(derived()) != ei_extract_data(other.lhs())
&& "aliasing detected during tranposition, please evaluate your expression");
return lazyAssign(static_cast<const MatrixBase<CwiseBinaryOp<ei_scalar_sum_op<Scalar>,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedA> > >,DerivedB> >& >(other));
}
template<typename Derived>
template<typename DerivedA, typename DerivedB>
Derived& MatrixBase<Derived>::
lazyAssign(const CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedB> > > >& other)
{
ei_assert(ei_extract_data(derived()) != ei_extract_data(other.rhs())
&& "aliasing detected during tranposition, please evaluate your expression");
return lazyAssign(static_cast<const MatrixBase<CwiseBinaryOp<ei_scalar_sum_op<Scalar>,DerivedA,CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestByValue<Eigen::Transpose<DerivedB> > > > >& >(other));
}
#endif
#endif // EIGEN_TRANSPOSE_H #endif // EIGEN_TRANSPOSE_H

View File

@ -234,14 +234,14 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView
inline TriangularView<NestByValue<typename MatrixType::AdjointReturnType>,TransposeMode> adjoint() inline TriangularView<NestByValue<typename MatrixType::AdjointReturnType>,TransposeMode> adjoint()
{ return m_matrix.adjoint().nestByValue(); } { return m_matrix.adjoint().nestByValue(); }
/** \sa MatrixBase::adjoint() const */ /** \sa MatrixBase::adjoint() const */
const inline TriangularView<NestByValue<typename MatrixType::AdjointReturnType>,TransposeMode> adjoint() const inline const TriangularView<NestByValue<typename MatrixType::AdjointReturnType>,TransposeMode> adjoint() const
{ return m_matrix.adjoint().nestByValue(); } { return m_matrix.adjoint().nestByValue(); }
/** \sa MatrixBase::transpose() */ /** \sa MatrixBase::transpose() */
inline TriangularView<NestByValue<Transpose<MatrixType> >,TransposeMode> transpose() inline TriangularView<NestByValue<Transpose<MatrixType> >,TransposeMode> transpose()
{ return m_matrix.transpose().nestByValue(); } { return m_matrix.transpose().nestByValue(); }
/** \sa MatrixBase::transpose() const */ /** \sa MatrixBase::transpose() const */
const inline TriangularView<NestByValue<Transpose<MatrixType> >,TransposeMode> transpose() const inline const TriangularView<NestByValue<Transpose<MatrixType> >,TransposeMode> transpose() const
{ return m_matrix.transpose().nestByValue(); } { return m_matrix.transpose().nestByValue(); }
PlainMatrixType toDense() const PlainMatrixType toDense() const

View File

@ -191,22 +191,22 @@ template<> EIGEN_STRONG_INLINE Packet4i ei_ploadu<int>(const int* from) { return
template<> EIGEN_STRONG_INLINE Packet4f ei_ploadu(const float* from) template<> EIGEN_STRONG_INLINE Packet4f ei_ploadu(const float* from)
{ {
__m128 res; __m128 res;
asm("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from), [dummy] "m" (*(from+1)) ); asm volatile ("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from), [dummy] "m" (*(from+1)) );
asm("movhps %[from2], %[r]" : [r] "+x" (res) : [from2] "m" (*(from+2)), [dummy] "m" (*(from+3)) ); asm volatile ("movhps %[from2], %[r]" : [r] "+x" (res) : [from2] "m" (*(from+2)), [dummy] "m" (*(from+3)) );
return res; return res;
} }
template<> EIGEN_STRONG_INLINE Packet2d ei_ploadu(const double* from) template<> EIGEN_STRONG_INLINE Packet2d ei_ploadu(const double* from)
{ {
__m128d res; __m128d res;
asm("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from) ); asm volatile ("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from) );
asm("movhpd %[from1], %[r]" : [r] "+x" (res) : [from1] "m" (*(from+1)) ); asm volatile ("movhpd %[from1], %[r]" : [r] "+x" (res) : [from1] "m" (*(from+1)) );
return res; return res;
} }
template<> EIGEN_STRONG_INLINE Packet4i ei_ploadu(const int* from) template<> EIGEN_STRONG_INLINE Packet4i ei_ploadu(const int* from)
{ {
__m128i res; __m128i res;
asm("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from), [dummy] "m" (*(from+1)) ); asm volatile ("movsd %[from0], %[r]" : [r] "=x" (res) : [from0] "m" (*from), [dummy] "m" (*(from+1)) );
asm("movhps %[from2], %[r]" : [r] "+x" (res) : [from2] "m" (*(from+2)), [dummy] "m" (*(from+3)) ); asm volatile ("movhps %[from2], %[r]" : [r] "+x" (res) : [from2] "m" (*(from+2)), [dummy] "m" (*(from+3)) );
return res; return res;
} }
#endif #endif

View File

@ -137,7 +137,7 @@ class GeneralProduct<Lhs, Rhs, GemmProduct>
GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());

View File

@ -375,7 +375,7 @@ struct SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,RhsMode,false>
RhsIsSelfAdjoint = (RhsMode&SelfAdjointBit)==SelfAdjointBit RhsIsSelfAdjoint = (RhsMode&SelfAdjointBit)==SelfAdjointBit
}; };
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());

View File

@ -175,7 +175,7 @@ struct SelfadjointProductMatrix<Lhs,LhsMode,false,Rhs,0,true>
SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());

View File

@ -333,7 +333,7 @@ struct TriangularProduct<Mode,LhsIsTriangular,Lhs,false,Rhs,false>
TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs); const ActualLhsType lhs = LhsBlasTraits::extract(m_lhs);
const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs); const ActualRhsType rhs = RhsBlasTraits::extract(m_rhs);

View File

@ -130,7 +130,7 @@ struct TriangularProduct<Mode,true,Lhs,false,Rhs,true>
TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {}
template<typename Dest> void addTo(Dest& dst, Scalar alpha) const template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{ {
ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); ei_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols());

View File

@ -182,7 +182,7 @@ struct ei_blas_traits<CwiseUnaryOp<ei_scalar_conjugate_op<Scalar>, NestedXpr> >
enum { enum {
IsComplex = NumTraits<Scalar>::IsComplex, IsComplex = NumTraits<Scalar>::IsComplex,
NeedToConjugate = IsComplex NeedToConjugate = Base::NeedToConjugate ? 0 : IsComplex
}; };
static inline ExtractType extract(const XprType& x) { return Base::extract(x._expression()); } static inline ExtractType extract(const XprType& x) { return Base::extract(x._expression()); }
static inline Scalar extractScalarFactor(const XprType& x) { return ei_conj(Base::extractScalarFactor(x._expression())); } static inline Scalar extractScalarFactor(const XprType& x) { return ei_conj(Base::extractScalarFactor(x._expression())); }

View File

@ -2,7 +2,7 @@
// for linear algebra. // for linear algebra.
// //
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr> // Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> // Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
// //
// Eigen is free software; you can redistribute it and/or // Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
@ -39,10 +39,9 @@
* Also, disabling compiler warnings for integer overflow, sounds like a bad idea. * Also, disabling compiler warnings for integer overflow, sounds like a bad idea.
* - It should be a prime number, because for example the old value 10000 led to bugs with 100x100 matrices. * - It should be a prime number, because for example the old value 10000 led to bugs with 100x100 matrices.
* *
* If you wish to port Eigen to a platform where sizeof(int)==2, it is perfectly possible to set Dynamic to, say, 97. * Changing the value of Dynamic breaks the ABI, as Dynamic is often used as a template parameter for Matrix.
* However, changing the value of Dynamic breaks the ABI, as Dynamic is often used as a template parameter for Matrix.
*/ */
const int Dynamic = 33331; const int Dynamic = sizeof(int) >= 4 ? 33331 : 101;
/** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>(). /** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
* The value Infinity there means the L-infinity norm. * The value Infinity there means the L-infinity norm.

View File

@ -35,6 +35,7 @@ template<typename _Scalar, int _Rows, int _Cols,
int _MaxRows = _Rows, int _MaxCols = _Cols> class Matrix; int _MaxRows = _Rows, int _MaxCols = _Cols> class Matrix;
template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged; template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged;
template<typename ExpressionType> class NoAlias;
template<typename ExpressionType> class NestByValue; template<typename ExpressionType> class NestByValue;
template<typename ExpressionType> class SwapWrapper; template<typename ExpressionType> class SwapWrapper;
template<typename MatrixType> class Minor; template<typename MatrixType> class Minor;

View File

@ -111,6 +111,8 @@
#define EIGEN_FAST_MATH 1 #define EIGEN_FAST_MATH 1
#endif #endif
#define EIGEN_DEBUG_VAR(x) std::cerr << #x << " = " << x << std::endl;
#define USING_PART_OF_NAMESPACE_EIGEN \ #define USING_PART_OF_NAMESPACE_EIGEN \
EIGEN_USING_MATRIX_TYPEDEFS \ EIGEN_USING_MATRIX_TYPEDEFS \
using Eigen::Matrix; \ using Eigen::Matrix; \
@ -242,7 +244,7 @@ using Eigen::ei_cos;
// format used in Eigen's documentation // format used in Eigen's documentation
// needed to define it here as escaping characters in CMake add_definition's argument seems very problematic. // needed to define it here as escaping characters in CMake add_definition's argument seems very problematic.
#define EIGEN_DOCS_IO_FORMAT IOFormat(3, AlignCols, " ", "\n", "", "") #define EIGEN_DOCS_IO_FORMAT IOFormat(3, 0, " ", "\n", "", "")
#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ #define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \
using Base::operator =; \ using Base::operator =; \

View File

@ -155,12 +155,7 @@ template<int Y, int InfX, int SupX>
class ei_meta_sqrt<Y, InfX, SupX, true> { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; }; class ei_meta_sqrt<Y, InfX, SupX, true> { public: enum { ret = (SupX*SupX <= Y) ? SupX : InfX }; };
/** \internal determines whether the product of two numeric types is allowed and what the return type is */ /** \internal determines whether the product of two numeric types is allowed and what the return type is */
template<typename T, typename U> struct ei_scalar_product_traits template<typename T, typename U> struct ei_scalar_product_traits;
{
// dummy general case where T and U aren't compatible -- not allowed anyway but we catch it elsewhere
//enum { Cost = NumTraits<T>::MulCost };
typedef T ReturnType;
};
template<typename T> struct ei_scalar_product_traits<T,T> template<typename T> struct ei_scalar_product_traits<T,T>
{ {

View File

@ -90,7 +90,7 @@ class ei_compute_matrix_flags
: MaxRows==1 ? MaxCols : MaxRows==1 ? MaxCols
: row_major_bit ? MaxCols : MaxRows, : row_major_bit ? MaxCols : MaxRows,
is_big = inner_max_size == Dynamic, is_big = inner_max_size == Dynamic,
is_packet_size_multiple = Rows==Dynamic || Cols==Dynamic || ((Cols*Rows) % ei_packet_traits<Scalar>::size) == 0, is_packet_size_multiple = MaxRows==Dynamic || MaxCols==Dynamic || ((MaxCols*MaxRows) % ei_packet_traits<Scalar>::size) == 0,
aligned_bit = (((Options&DontAlign)==0) && (is_big || is_packet_size_multiple)) ? AlignedBit : 0, aligned_bit = (((Options&DontAlign)==0) && (is_big || is_packet_size_multiple)) ? AlignedBit : 0,
packet_access_bit = ei_packet_traits<Scalar>::size > 1 && aligned_bit ? PacketAccessBit : 0 packet_access_bit = ei_packet_traits<Scalar>::size > 1 && aligned_bit ? PacketAccessBit : 0
}; };

View File

@ -85,7 +85,7 @@ public:
/** Concatenates two rotations */ /** Concatenates two rotations */
inline Rotation2D& operator*=(const Rotation2D& other) inline Rotation2D& operator*=(const Rotation2D& other)
{ return m_angle += other.m_angle; } { return m_angle += other.m_angle; return *this; }
/** Applies the rotation to a 2D vector */ /** Applies the rotation to a 2D vector */
Vector2 operator* (const Vector2& vec) const Vector2 operator* (const Vector2& vec) const

View File

@ -460,6 +460,11 @@ public:
inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() const inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() const
{ return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); } { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); }
#ifdef EIGEN_TRANSFORM_PLUGIN
#include EIGEN_TRANSFORM_PLUGIN
#endif
}; };
/** \ingroup Geometry_Module */ /** \ingroup Geometry_Module */

View File

@ -32,54 +32,93 @@ template<int n> struct ei_decrement_size
}; };
}; };
template<typename EssentialPart>
void makeTrivialHouseholder(
EssentialPart *essential,
typename EssentialPart::RealScalar *beta)
{
*beta = typename EssentialPart::RealScalar(0);
essential->setZero();
}
template<typename Derived>
void MatrixBase<Derived>::makeHouseholderInPlace(Scalar *tau, RealScalar *beta)
{
VectorBlock<Derived, ei_decrement_size<SizeAtCompileTime>::ret> essentialPart(derived(), 1, size()-1);
makeHouseholder(&essentialPart, tau, beta);
}
/** Computes the elementary reflector H such that:
* \f$ H *this = [ beta 0 ... 0]^T \f$
* where the transformation H is:
* \f$ H = I - tau v v^*\f$
* and the vector v is:
* \f$ v^T = [1 essential^T] \f$
*
* On output:
* \param essential the essential part of the vector \c v
* \param tau the scaling factor of the householder transformation
* \param beta the result of H * \c *this
*
* \sa MatrixBase::makeHouseholderInPlace(), MatrixBase::applyHouseholderOnTheLeft(),
* MatrixBase::applyHouseholderOnTheRight()
*/
template<typename Derived> template<typename Derived>
template<typename EssentialPart> template<typename EssentialPart>
void MatrixBase<Derived>::makeHouseholder( void MatrixBase<Derived>::makeHouseholder(
EssentialPart *essential, EssentialPart *essential,
Scalar *tau,
RealScalar *beta) const RealScalar *beta) const
{ {
EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart) EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart)
RealScalar _squaredNorm = squaredNorm(); VectorBlock<Derived, EssentialPart::SizeAtCompileTime> tail(derived(), 1, size()-1);
Scalar c0;
if(ei_abs2(coeff(0)) <= ei_abs2(precision<Scalar>()) * _squaredNorm) RealScalar tailSqNorm;
Scalar c0 = coeff(0);
if( (size()==1 || (tailSqNorm=tail.squaredNorm()) == RealScalar(0)) && ei_imag(c0)==RealScalar(0))
{ {
c0 = ei_sqrt(_squaredNorm); *tau = 0;
*beta = ei_real(c0);
} }
else else
{ {
Scalar sign = coeff(0) / ei_abs(coeff(0)); *beta = ei_sqrt(ei_abs2(c0) + tailSqNorm);
c0 = coeff(0) + sign * ei_sqrt(_squaredNorm); if (ei_real(c0)>=0.)
*beta = -*beta;
*essential = tail / (c0 - *beta);
*tau = ei_conj((*beta - c0) / *beta);
} }
VectorBlock<Derived, EssentialPart::SizeAtCompileTime> tail(derived(), 1, size()-1);
*essential = tail / c0;
const RealScalar c0abs2 = ei_abs2(c0);
*beta = RealScalar(2) * c0abs2 / (c0abs2 + _squaredNorm - ei_abs2(coeff(0)));
} }
template<typename Derived> template<typename Derived>
template<typename EssentialPart> template<typename EssentialPart>
void MatrixBase<Derived>::applyHouseholderOnTheLeft( void MatrixBase<Derived>::applyHouseholderOnTheLeft(
const EssentialPart& essential, const EssentialPart& essential,
const RealScalar& beta) const Scalar& tau,
Scalar* workspace)
{ {
Matrix<Scalar, 1, ColsAtCompileTime, PlainMatrixType::Options, 1, MaxColsAtCompileTime> tmp(cols()); Map<Matrix<Scalar, 1, ColsAtCompileTime, PlainMatrixType::Options, 1, MaxColsAtCompileTime> > tmp(workspace,cols());
Block<Derived, EssentialPart::SizeAtCompileTime, Derived::ColsAtCompileTime> bottom(derived(), 1, 0, rows()-1, cols()); Block<Derived, EssentialPart::SizeAtCompileTime, Derived::ColsAtCompileTime> bottom(derived(), 1, 0, rows()-1, cols());
tmp = row(0) + essential.adjoint() * bottom; tmp.noalias() = essential.adjoint() * bottom;
row(0) -= beta * tmp; tmp += row(0);
bottom -= beta * essential * tmp; row(0) -= tau * tmp;
bottom.noalias() -= tau * essential * tmp;
} }
template<typename Derived> template<typename Derived>
template<typename EssentialPart> template<typename EssentialPart>
void MatrixBase<Derived>::applyHouseholderOnTheRight( void MatrixBase<Derived>::applyHouseholderOnTheRight(
const EssentialPart& essential, const EssentialPart& essential,
const RealScalar& beta) const Scalar& tau,
Scalar* workspace)
{ {
Matrix<Scalar, RowsAtCompileTime, 1, PlainMatrixType::Options, MaxRowsAtCompileTime, 1> tmp(rows()); Map<Matrix<Scalar, RowsAtCompileTime, 1, PlainMatrixType::Options, MaxRowsAtCompileTime, 1> > tmp(workspace,rows());
Block<Derived, Derived::RowsAtCompileTime, EssentialPart::SizeAtCompileTime> right(derived(), 0, 1, rows(), cols()-1); Block<Derived, Derived::RowsAtCompileTime, EssentialPart::SizeAtCompileTime> right(derived(), 0, 1, rows(), cols()-1);
tmp = col(0) + right * essential.conjugate(); tmp.noalias() = right * essential.conjugate();
col(0) -= beta * tmp; tmp += col(0);
right -= beta * tmp * essential.transpose(); col(0) -= tau * tmp;
right.noalias() -= tau * tmp * essential.transpose();
} }
#endif // EIGEN_HOUSEHOLDER_H #endif // EIGEN_HOUSEHOLDER_H

View File

@ -0,0 +1,6 @@
FILE(GLOB Eigen_Jacobi_SRCS "*.h")
INSTALL(FILES
${Eigen_Jacobi_SRCS}
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Jacobi COMPONENT Devel
)

202
Eigen/src/Jacobi/Jacobi.h Normal file
View File

@ -0,0 +1,202 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef EIGEN_JACOBI_H
#define EIGEN_JACOBI_H
template<typename VectorX, typename VectorY>
void ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, typename VectorX::Scalar c, typename VectorY::Scalar s);
template<typename Derived>
inline void MatrixBase<Derived>::applyJacobiOnTheLeft(int p, int q, Scalar c, Scalar s)
{
RowXpr x(row(p));
RowXpr y(row(q));
ei_apply_rotation_in_the_plane(x, y, c, s);
}
template<typename Derived>
inline void MatrixBase<Derived>::applyJacobiOnTheRight(int p, int q, Scalar c, Scalar s)
{
ColXpr x(col(p));
ColXpr y(col(q));
ei_apply_rotation_in_the_plane(x, y, c, s);
}
template<typename Scalar>
bool ei_makeJacobi(Scalar x, Scalar y, Scalar z, Scalar *c, Scalar *s)
{
if(y == 0)
{
*c = Scalar(1);
*s = Scalar(0);
return false;
}
else
{
Scalar tau = (z - x) / (2 * y);
Scalar w = ei_sqrt(1 + ei_abs2(tau));
Scalar t;
if(tau>0)
t = Scalar(1) / (tau + w);
else
t = Scalar(1) / (tau - w);
*c = Scalar(1) / ei_sqrt(1 + ei_abs2(t));
*s = *c * t;
return true;
}
}
template<typename Derived>
inline bool MatrixBase<Derived>::makeJacobi(int p, int q, Scalar *c, Scalar *s) const
{
return ei_makeJacobi(coeff(p,p), coeff(p,q), coeff(q,q), c, s);
}
template<typename Derived>
inline bool MatrixBase<Derived>::makeJacobiForAtA(int p, int q, Scalar *c, Scalar *s) const
{
return ei_makeJacobi(ei_abs2(coeff(p,p)) + ei_abs2(coeff(q,p)),
ei_conj(coeff(p,p))*coeff(p,q) + ei_conj(coeff(q,p))*coeff(q,q),
ei_abs2(coeff(p,q)) + ei_abs2(coeff(q,q)),
c,s);
}
template<typename Derived>
inline bool MatrixBase<Derived>::makeJacobiForAAt(int p, int q, Scalar *c, Scalar *s) const
{
return ei_makeJacobi(ei_abs2(coeff(p,p)) + ei_abs2(coeff(p,q)),
ei_conj(coeff(q,p))*coeff(p,p) + ei_conj(coeff(q,q))*coeff(p,q),
ei_abs2(coeff(q,p)) + ei_abs2(coeff(q,q)),
c,s);
}
template<typename Scalar>
inline void ei_normalizeJacobi(Scalar *c, Scalar *s, const Scalar& x, const Scalar& y)
{
Scalar a = x * *c - y * *s;
Scalar b = x * *s + y * *c;
if(ei_abs(b)>ei_abs(a)) {
Scalar x = *c;
*c = -*s;
*s = x;
}
}
template<typename VectorX, typename VectorY>
void /*EIGEN_DONT_INLINE*/ ei_apply_rotation_in_the_plane(VectorX& _x, VectorY& _y, typename VectorX::Scalar c, typename VectorY::Scalar s)
{
typedef typename VectorX::Scalar Scalar;
ei_assert(_x.size() == _y.size());
int size = _x.size();
int incrx = size ==1 ? 1 : &_x.coeffRef(1) - &_x.coeffRef(0);
int incry = size ==1 ? 1 : &_y.coeffRef(1) - &_y.coeffRef(0);
Scalar* EIGEN_RESTRICT x = &_x.coeffRef(0);
Scalar* EIGEN_RESTRICT y = &_y.coeffRef(0);
if (incrx==1 && incry==1)
{
// both vectors are sequentially stored in memory => vectorization
typedef typename ei_packet_traits<Scalar>::type Packet;
enum { PacketSize = ei_packet_traits<Scalar>::size, Peeling = 2 };
int alignedStart = ei_alignmentOffset(y, size);
int alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
const Packet pc = ei_pset1(c);
const Packet ps = ei_pset1(s);
for(int i=0; i<alignedStart; ++i)
{
Scalar xi = x[i];
Scalar yi = y[i];
x[i] = c * xi - s * yi;
y[i] = s * xi + c * yi;
}
Scalar* px = x + alignedStart;
Scalar* py = y + alignedStart;
if(ei_alignmentOffset(x, size)==alignedStart)
{
for(int i=alignedStart; i<alignedEnd; i+=PacketSize)
{
Packet xi = ei_pload(px);
Packet yi = ei_pload(py);
ei_pstore(px, ei_psub(ei_pmul(pc,xi),ei_pmul(ps,yi)));
ei_pstore(py, ei_padd(ei_pmul(ps,xi),ei_pmul(pc,yi)));
px += PacketSize;
py += PacketSize;
}
}
else
{
int peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
for(int i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
{
Packet xi = ei_ploadu(px);
Packet xi1 = ei_ploadu(px+PacketSize);
Packet yi = ei_pload (py);
Packet yi1 = ei_pload (py+PacketSize);
ei_pstoreu(px, ei_psub(ei_pmul(pc,xi),ei_pmul(ps,yi)));
ei_pstoreu(px+PacketSize, ei_psub(ei_pmul(pc,xi1),ei_pmul(ps,yi1)));
ei_pstore (py, ei_padd(ei_pmul(ps,xi),ei_pmul(pc,yi)));
ei_pstore (py+PacketSize, ei_padd(ei_pmul(ps,xi1),ei_pmul(pc,yi1)));
px += Peeling*PacketSize;
py += Peeling*PacketSize;
}
if(alignedEnd!=peelingEnd)
{
Packet xi = ei_ploadu(x+peelingEnd);
Packet yi = ei_pload (y+peelingEnd);
ei_pstoreu(x+peelingEnd, ei_psub(ei_pmul(pc,xi),ei_pmul(ps,yi)));
ei_pstore (y+peelingEnd, ei_padd(ei_pmul(ps,xi),ei_pmul(pc,yi)));
}
}
for(int i=alignedEnd; i<size; ++i)
{
Scalar xi = x[i];
Scalar yi = y[i];
x[i] = c * xi - s * yi;
y[i] = s * xi + c * yi;
}
}
else
{
for(int i=0; i<size; ++i)
{
Scalar xi = *x;
Scalar yi = *y;
*x = c * xi - s * yi;
*y = s * xi + c * yi;
x += incrx;
y += incry;
}
}
}
#endif // EIGEN_JACOBI_H

View File

@ -111,8 +111,10 @@ template<typename MatrixType> class LU
* *
* \param matrix the matrix of which to compute the LU decomposition. * \param matrix the matrix of which to compute the LU decomposition.
* It is required to be nonzero. * It is required to be nonzero.
*
* \returns a reference to *this
*/ */
void compute(const MatrixType& matrix); LU& compute(const MatrixType& matrix);
/** \returns the LU decomposition matrix: the upper-triangular part is U, the /** \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 * unit-lower-triangular part is L (at least for square matrices; in the non-square
@ -377,7 +379,7 @@ LU<MatrixType>::LU(const MatrixType& matrix)
} }
template<typename MatrixType> template<typename MatrixType>
void LU<MatrixType>::compute(const MatrixType& matrix) LU<MatrixType>& LU<MatrixType>::compute(const MatrixType& matrix)
{ {
m_originalMatrix = &matrix; m_originalMatrix = &matrix;
m_lu = matrix; m_lu = matrix;
@ -390,7 +392,7 @@ void LU<MatrixType>::compute(const MatrixType& matrix)
// this formula comes from experimenting (see "LU precision tuning" thread on the list) // 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. // and turns out to be identical to Higham's formula used already in LDLt.
m_precision = machine_epsilon<Scalar>() * size; m_precision = epsilon<Scalar>() * size;
IntColVectorType rows_transpositions(matrix.rows()); IntColVectorType rows_transpositions(matrix.rows());
IntRowVectorType cols_transpositions(matrix.cols()); IntRowVectorType cols_transpositions(matrix.cols());
@ -435,7 +437,7 @@ void LU<MatrixType>::compute(const MatrixType& matrix)
if(k<rows-1) if(k<rows-1)
m_lu.col(k).end(rows-k-1) /= m_lu.coeff(k,k); m_lu.col(k).end(rows-k-1) /= m_lu.coeff(k,k);
if(k<size-1) if(k<size-1)
m_lu.block(k+1,k+1,rows-k-1,cols-k-1) -= m_lu.col(k).end(rows-k-1) * m_lu.row(k).end(cols-k-1); m_lu.block(k+1,k+1,rows-k-1,cols-k-1).noalias() -= m_lu.col(k).end(rows-k-1) * m_lu.row(k).end(cols-k-1);
} }
for(int k = 0; k < matrix.rows(); ++k) m_p.coeffRef(k) = k; for(int k = 0; k < matrix.rows(); ++k) m_p.coeffRef(k) = k;
@ -447,6 +449,7 @@ void LU<MatrixType>::compute(const MatrixType& matrix)
std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k))); std::swap(m_q.coeffRef(k), m_q.coeffRef(cols_transpositions.coeff(k)));
m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_det_pq = (number_of_transpositions%2) ? -1 : 1;
return *this;
} }
template<typename MatrixType> template<typename MatrixType>
@ -561,7 +564,7 @@ bool LU<MatrixType>::solve(
if(!isSurjective()) if(!isSurjective())
{ {
// is c is in the image of U ? // is c is in the image of U ?
RealScalar biggest_in_c = c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff(); RealScalar biggest_in_c = m_rank>0 ? c.corner(TopLeft, m_rank, c.cols()).cwise().abs().maxCoeff() : 0;
for(int col = 0; col < c.cols(); ++col) for(int col = 0; col < c.cols(); ++col)
for(int row = m_rank; row < c.rows(); ++row) for(int row = m_rank; row < c.rows(); ++row)
if(!ei_isMuchSmallerThan(c.coeff(row,col), biggest_in_c, m_precision)) if(!ei_isMuchSmallerThan(c.coeff(row,col), biggest_in_c, m_precision))

View File

@ -87,7 +87,7 @@ template<typename MatrixType> class PartialLU
*/ */
PartialLU(const MatrixType& matrix); PartialLU(const MatrixType& matrix);
void compute(const MatrixType& matrix); PartialLU& compute(const MatrixType& matrix);
/** \returns the LU decomposition matrix: the upper-triangular part is U, the /** \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 * unit-lower-triangular part is L (at least for square matrices; in the non-square
@ -248,7 +248,7 @@ struct ei_partial_lu_impl
int rrows = rows-k-1; int rrows = rows-k-1;
int rsize = size-k-1; int rsize = size-k-1;
lu.col(k).end(rrows) /= lu.coeff(k,k); lu.col(k).end(rrows) /= lu.coeff(k,k);
lu.corner(BottomRight,rrows,rsize) -= (lu.col(k).end(rrows) * lu.row(k).end(rsize)).lazy(); lu.corner(BottomRight,rrows,rsize).noalias() -= lu.col(k).end(rrows) * lu.row(k).end(rsize);
} }
} }
} }
@ -350,7 +350,7 @@ void ei_partial_lu_inplace(MatrixType& lu, IntVector& row_transpositions, int& n
} }
template<typename MatrixType> template<typename MatrixType>
void PartialLU<MatrixType>::compute(const MatrixType& matrix) PartialLU<MatrixType>& PartialLU<MatrixType>::compute(const MatrixType& matrix)
{ {
m_lu = matrix; m_lu = matrix;
m_p.resize(matrix.rows()); m_p.resize(matrix.rows());
@ -369,6 +369,7 @@ void PartialLU<MatrixType>::compute(const MatrixType& matrix)
std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k))); std::swap(m_p.coeffRef(k), m_p.coeffRef(rows_transpositions.coeff(k)));
m_isInitialized = true; m_isInitialized = true;
return *this;
} }
template<typename MatrixType> template<typename MatrixType>

View File

@ -118,7 +118,7 @@ template<typename _MatrixType> class EigenSolver
return m_eivalues; return m_eivalues;
} }
void compute(const MatrixType& matrix); EigenSolver& compute(const MatrixType& matrix);
private: private:
@ -189,7 +189,7 @@ typename EigenSolver<MatrixType>::EigenvectorType EigenSolver<MatrixType>::eigen
} }
template<typename MatrixType> template<typename MatrixType>
void EigenSolver<MatrixType>::compute(const MatrixType& matrix) EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const MatrixType& matrix)
{ {
assert(matrix.cols() == matrix.rows()); assert(matrix.cols() == matrix.rows());
int n = matrix.cols(); int n = matrix.cols();
@ -205,6 +205,7 @@ void EigenSolver<MatrixType>::compute(const MatrixType& matrix)
hqr2(matH); hqr2(matH);
m_isInitialized = true; m_isInitialized = true;
return *this;
} }
// Nonsymmetric reduction to Hessenberg form. // Nonsymmetric reduction to Hessenberg form.

View File

@ -93,7 +93,7 @@ template<typename _MatrixType> class HessenbergDecomposition
* *
* \sa packedMatrix() * \sa packedMatrix()
*/ */
CoeffVectorType householderCoefficients(void) const { return m_hCoeffs; } CoeffVectorType householderCoefficients() const { return m_hCoeffs; }
/** \returns the internal result of the decomposition. /** \returns the internal result of the decomposition.
* *
@ -112,8 +112,8 @@ template<typename _MatrixType> class HessenbergDecomposition
*/ */
const MatrixType& packedMatrix(void) const { return m_matrix; } const MatrixType& packedMatrix(void) const { return m_matrix; }
MatrixType matrixQ(void) const; MatrixType matrixQ() const;
MatrixType matrixH(void) const; MatrixType matrixH() const;
private: private:
@ -143,87 +143,42 @@ void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVector
{ {
assert(matA.rows()==matA.cols()); assert(matA.rows()==matA.cols());
int n = matA.rows(); int n = matA.rows();
for (int i = 0; i<n-2; ++i) Matrix<Scalar,1,Dynamic> temp(n);
for (int i = 0; i<n-1; ++i)
{ {
// let's consider the vector v = i-th column starting at position i+1 // let's consider the vector v = i-th column starting at position i+1
int remainingSize = n-i-1;
// start of the householder transformation RealScalar beta;
// squared norm of the vector v skipping the first element Scalar h;
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).squaredNorm(); matA.col(i).end(remainingSize).makeHouseholderInPlace(&h, &beta);
if (ei_isMuchSmallerThan(v1norm2,static_cast<Scalar>(1)))
{
hCoeffs.coeffRef(i) = 0.;
}
else
{
Scalar v0 = matA.col(i).coeff(i+1);
RealScalar beta = ei_sqrt(ei_abs2(v0)+v1norm2);
if (ei_real(v0)>=0.)
beta = -beta;
matA.col(i).end(n-(i+2)) *= (Scalar(1)/(v0-beta));
matA.col(i).coeffRef(i+1) = beta; matA.col(i).coeffRef(i+1) = beta;
Scalar h = (beta - v0) / beta; hCoeffs.coeffRef(i) = h;
// end of the householder transformation
// Apply similarity transformation to remaining columns, // Apply similarity transformation to remaining columns,
// i.e., A = H' A H where H = I - h v v' and v = matA.col(i).end(n-i-1) // i.e., compute A = H A H'
matA.col(i).coeffRef(i+1) = 1;
// first let's do A = H' A // A = H A
matA.corner(BottomRight,n-i-1,n-i-1) -= ((ei_conj(h) * matA.col(i).end(n-i-1)) * matA.corner(BottomRight, remainingSize, remainingSize)
(matA.col(i).end(n-i-1).adjoint() * matA.corner(BottomRight,n-i-1,n-i-1))).lazy(); .applyHouseholderOnTheLeft(matA.col(i).end(remainingSize-1), h, &temp.coeffRef(0));
// now let's do A = A H // A = A H'
matA.corner(BottomRight,n,n-i-1) -= ((matA.corner(BottomRight,n,n-i-1) * matA.col(i).end(n-i-1)) matA.corner(BottomRight, n, remainingSize)
* (h * matA.col(i).end(n-i-1).adjoint())).lazy(); .applyHouseholderOnTheRight(matA.col(i).end(remainingSize-1).conjugate(), ei_conj(h), &temp.coeffRef(0));
matA.col(i).coeffRef(i+1) = beta;
hCoeffs.coeffRef(i) = h;
}
}
if (NumTraits<Scalar>::IsComplex)
{
// Householder transformation on the remaining single scalar
int i = n-2;
Scalar v0 = matA.coeff(i+1,i);
RealScalar beta = ei_sqrt(ei_abs2(v0));
if (ei_real(v0)>=0.)
beta = -beta;
Scalar h = (beta - v0) / beta;
hCoeffs.coeffRef(i) = h;
// A = H* A
matA.corner(BottomRight,n-i-1,n-i) -= ei_conj(h) * matA.corner(BottomRight,n-i-1,n-i);
// A = A H
matA.col(n-1) -= h * matA.col(n-1);
}
else
{
hCoeffs.coeffRef(n-2) = 0;
} }
} }
/** reconstructs and returns the matrix Q */ /** reconstructs and returns the matrix Q */
template<typename MatrixType> template<typename MatrixType>
typename HessenbergDecomposition<MatrixType>::MatrixType typename HessenbergDecomposition<MatrixType>::MatrixType
HessenbergDecomposition<MatrixType>::matrixQ(void) const HessenbergDecomposition<MatrixType>::matrixQ() const
{ {
int n = m_matrix.rows(); int n = m_matrix.rows();
MatrixType matQ = MatrixType::Identity(n,n); MatrixType matQ = MatrixType::Identity(n,n);
Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(n); Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(n);
for (int i = n-2; i>=0; i--) for (int i = n-2; i>=0; i--)
{ {
Scalar tmp = m_matrix.coeff(i+1,i); matQ.corner(BottomRight,n-i-1,n-i-1)
m_matrix.const_cast_derived().coeffRef(i+1,i) = 1; .applyHouseholderOnTheLeft(m_matrix.col(i).end(n-i-2), ei_conj(m_hCoeffs.coeff(i)), &temp.coeffRef(0,0));
int rs = n-i-1;
temp.end(rs) = (m_matrix.col(i).end(rs).adjoint() * matQ.corner(BottomRight,rs,rs)).lazy();
matQ.corner(BottomRight,rs,rs) -= (m_hCoeffs.coeff(i) * m_matrix.col(i).end(rs) * temp.end(rs)).lazy();
m_matrix.const_cast_derived().coeffRef(i+1,i) = tmp;
} }
return matQ; return matQ;
} }
@ -237,7 +192,7 @@ HessenbergDecomposition<MatrixType>::matrixQ(void) const
*/ */
template<typename MatrixType> template<typename MatrixType>
typename HessenbergDecomposition<MatrixType>::MatrixType typename HessenbergDecomposition<MatrixType>::MatrixType
HessenbergDecomposition<MatrixType>::matrixH(void) const HessenbergDecomposition<MatrixType>::matrixH() const
{ {
// FIXME should this function (and other similar) rather take a matrix as argument // FIXME should this function (and other similar) rather take a matrix as argument
// and fill it (to avoid temporaries) // and fill it (to avoid temporaries)

View File

@ -45,11 +45,15 @@ template<typename MatrixType> class HouseholderQR
{ {
public: public:
enum {
MinSizeAtCompileTime = EIGEN_ENUM_MIN(MatrixType::ColsAtCompileTime,MatrixType::RowsAtCompileTime)
};
typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar; typedef typename MatrixType::RealScalar RealScalar;
typedef Block<MatrixType, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixRBlockType; typedef Block<MatrixType, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixRBlockType;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixTypeR; typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> MatrixTypeR;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType; typedef Matrix<Scalar, MinSizeAtCompileTime, 1> HCoeffsType;
/** /**
* \brief Default Constructor. * \brief Default Constructor.
@ -61,7 +65,7 @@ template<typename MatrixType> class HouseholderQR
HouseholderQR(const MatrixType& matrix) HouseholderQR(const MatrixType& matrix)
: m_qr(matrix.rows(), matrix.cols()), : m_qr(matrix.rows(), matrix.cols()),
m_hCoeffs(matrix.cols()), m_hCoeffs(std::min(matrix.rows(),matrix.cols())),
m_isInitialized(false) m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
@ -101,80 +105,43 @@ template<typename MatrixType> class HouseholderQR
*/ */
const MatrixType& matrixQR() const { return m_qr; } const MatrixType& matrixQR() const { return m_qr; }
void compute(const MatrixType& matrix); HouseholderQR& compute(const MatrixType& matrix);
protected: protected:
MatrixType m_qr; MatrixType m_qr;
VectorType m_hCoeffs; HCoeffsType m_hCoeffs;
bool m_isInitialized; bool m_isInitialized;
}; };
#ifndef EIGEN_HIDE_HEAVY_CODE #ifndef EIGEN_HIDE_HEAVY_CODE
template<typename MatrixType> template<typename MatrixType>
void HouseholderQR<MatrixType>::compute(const MatrixType& matrix) HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix)
{ {
m_qr = matrix;
m_hCoeffs.resize(matrix.cols());
int rows = matrix.rows(); int rows = matrix.rows();
int cols = matrix.cols(); int cols = matrix.cols();
RealScalar eps2 = precision<RealScalar>()*precision<RealScalar>(); int size = std::min(rows,cols);
m_qr = matrix;
m_hCoeffs.resize(size);
Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(cols); Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(cols);
for (int k = 0; k < cols; ++k) for (int k = 0; k < size; ++k)
{ {
int remainingSize = rows-k; int remainingRows = rows - k;
int remainingCols = cols - k -1;
RealScalar beta; RealScalar beta;
Scalar v0 = m_qr.col(k).coeff(k); m_qr.col(k).end(remainingRows).makeHouseholderInPlace(&m_hCoeffs.coeffRef(k), &beta);
m_qr.coeffRef(k,k) = beta;
if (remainingSize==1) // apply H to remaining part of m_qr from the left
{ m_qr.corner(BottomRight, remainingRows, remainingCols)
if (NumTraits<Scalar>::IsComplex) .applyHouseholderOnTheLeft(m_qr.col(k).end(remainingRows-1), m_hCoeffs.coeffRef(k), &temp.coeffRef(k+1));
{
// Householder transformation on the remaining single scalar
beta = ei_abs(v0);
if (ei_real(v0)>0)
beta = -beta;
m_qr.coeffRef(k,k) = beta;
m_hCoeffs.coeffRef(k) = (beta - v0) / beta;
}
else
{
m_hCoeffs.coeffRef(k) = 0;
}
}
else if ((beta=m_qr.col(k).end(remainingSize-1).squaredNorm())>eps2)
// FIXME what about ei_imag(v0) ??
{
// form k-th Householder vector
beta = ei_sqrt(ei_abs2(v0)+beta);
if (ei_real(v0)>=0.)
beta = -beta;
m_qr.col(k).end(remainingSize-1) /= v0-beta;
m_qr.coeffRef(k,k) = beta;
Scalar h = m_hCoeffs.coeffRef(k) = (beta - v0) / beta;
// apply the Householder transformation (I - h v v') to remaining columns, i.e.,
// R <- (I - h v v') * R where v = [1,m_qr(k+1,k), m_qr(k+2,k), ...]
int remainingCols = cols - k -1;
if (remainingCols>0)
{
m_qr.coeffRef(k,k) = Scalar(1);
temp.end(remainingCols) = (m_qr.col(k).end(remainingSize).adjoint()
* m_qr.corner(BottomRight, remainingSize, remainingCols)).lazy();
m_qr.corner(BottomRight, remainingSize, remainingCols) -= (ei_conj(h) * m_qr.col(k).end(remainingSize)
* temp.end(remainingCols)).lazy();
m_qr.coeffRef(k,k) = beta;
}
}
else
{
m_hCoeffs.coeffRef(k) = 0;
}
} }
m_isInitialized = true; m_isInitialized = true;
return *this;
} }
template<typename MatrixType> template<typename MatrixType>
@ -186,12 +153,20 @@ void HouseholderQR<MatrixType>::solve(
{ {
ei_assert(m_isInitialized && "HouseholderQR is not initialized."); ei_assert(m_isInitialized && "HouseholderQR is not initialized.");
const int rows = m_qr.rows(); const int rows = m_qr.rows();
const int cols = b.cols();
ei_assert(b.rows() == rows); ei_assert(b.rows() == rows);
result->resize(rows, b.cols()); result->resize(rows, cols);
// TODO(keir): There is almost certainly a faster way to multiply by *result = b;
// Q^T without explicitly forming matrixQ(). Investigate.
*result = matrixQ().transpose()*b; Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(cols);
for (int k = 0; k < cols; ++k)
{
int remainingSize = rows-k;
result->corner(BottomRight, remainingSize, cols)
.applyHouseholderOnTheLeft(m_qr.col(k).end(remainingSize-1), m_hCoeffs.coeff(k), &temp.coeffRef(0));
}
const int rank = std::min(result->rows(), result->cols()); const int rank = std::min(result->rows(), result->cols());
m_qr.corner(TopLeft, rank, rank) m_qr.corner(TopLeft, rank, rank)
@ -204,8 +179,8 @@ template<typename MatrixType>
MatrixType HouseholderQR<MatrixType>::matrixQ() const MatrixType HouseholderQR<MatrixType>::matrixQ() const
{ {
ei_assert(m_isInitialized && "HouseholderQR is not initialized."); ei_assert(m_isInitialized && "HouseholderQR is not initialized.");
// compute the product Q_0 Q_1 ... Q_n-1, // compute the product H'_0 H'_1 ... H'_n-1,
// where Q_k is the k-th Householder transformation I - h_k v_k v_k' // 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), ...] // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
int rows = m_qr.rows(); int rows = m_qr.rows();
int cols = m_qr.cols(); int cols = m_qr.cols();
@ -213,15 +188,9 @@ MatrixType HouseholderQR<MatrixType>::matrixQ() const
Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(cols); Matrix<Scalar,1,MatrixType::ColsAtCompileTime> temp(cols);
for (int k = cols-1; k >= 0; k--) for (int k = cols-1; k >= 0; k--)
{ {
// to make easier the computation of the transformation, let's temporarily int remainingSize = rows-k;
// overwrite m_qr(k,k) such that the end of m_qr.col(k) is exactly our Householder vector. res.corner(BottomRight, remainingSize, cols-k)
Scalar beta = m_qr.coeff(k,k); .applyHouseholderOnTheLeft(m_qr.col(k).end(remainingSize-1), ei_conj(m_hCoeffs.coeff(k)), &temp.coeffRef(k));
m_qr.const_cast_derived().coeffRef(k,k) = 1;
int endLength = rows-k;
temp.end(cols-k) = (m_qr.col(k).end(endLength).adjoint() * res.corner(BottomRight,endLength, cols-k)).lazy();
res.corner(BottomRight,endLength, cols-k) -= ((m_hCoeffs.coeff(k) * m_qr.col(k).end(endLength)) * temp.end(cols-k)).lazy();
m_qr.const_cast_derived().coeffRef(k,k) = beta;
} }
return res; return res;
} }

View File

@ -90,9 +90,9 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
compute(matA, matB, computeEigenvectors); compute(matA, matB, computeEigenvectors);
} }
void compute(const MatrixType& matrix, bool computeEigenvectors = true); SelfAdjointEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true);
void compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true); SelfAdjointEigenSolver& compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true);
/** \returns the computed eigen vectors as a matrix of column vectors */ /** \returns the computed eigen vectors as a matrix of column vectors */
MatrixType eigenvectors(void) const MatrixType eigenvectors(void) const
@ -182,7 +182,7 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int st
* \sa SelfAdjointEigenSolver(MatrixType,bool), compute(MatrixType,MatrixType,bool) * \sa SelfAdjointEigenSolver(MatrixType,bool), compute(MatrixType,MatrixType,bool)
*/ */
template<typename MatrixType> template<typename MatrixType>
void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
{ {
#ifndef NDEBUG #ifndef NDEBUG
m_eigenvectorsOk = computeEigenvectors; m_eigenvectorsOk = computeEigenvectors;
@ -195,7 +195,7 @@ void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool
{ {
m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0)); m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0));
m_eivec.setOnes(); m_eivec.setOnes();
return; return *this;
} }
m_eivec = matrix; m_eivec = matrix;
@ -240,6 +240,7 @@ void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool
m_eivec.col(i).swap(m_eivec.col(k+i)); m_eivec.col(i).swap(m_eivec.col(k+i));
} }
} }
return *this;
} }
/** Computes the eigenvalues of the generalized eigen problem /** Computes the eigenvalues of the generalized eigen problem
@ -250,7 +251,7 @@ void SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool
* \sa SelfAdjointEigenSolver(MatrixType,MatrixType,bool), compute(MatrixType,bool) * \sa SelfAdjointEigenSolver(MatrixType,MatrixType,bool), compute(MatrixType,bool)
*/ */
template<typename MatrixType> template<typename MatrixType>
void SelfAdjointEigenSolver<MatrixType>:: SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::
compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors) compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors)
{ {
ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows()); ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows());
@ -282,6 +283,7 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors
for (int i=0; i<m_eivec.cols(); ++i) for (int i=0; i<m_eivec.cols(); ++i)
m_eivec.col(i) = m_eivec.col(i).normalized(); m_eivec.col(i) = m_eivec.col(i).normalized();
} }
return *this;
} }
#endif // EIGEN_HIDE_HEAVY_CODE #endif // EIGEN_HIDE_HEAVY_CODE
@ -377,24 +379,8 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int st
// G only modifies the two columns k and k+1 // G only modifies the two columns k and k+1
if (matrixQ) if (matrixQ)
{ {
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR Map<Matrix<Scalar,Dynamic,Dynamic> > q(matrixQ,n,n);
#else q.applyJacobiOnTheRight(k,k+1,c,s);
int kn = k*n;
int kn1 = (k+1)*n;
#endif
// let's do the product manually to avoid the need of temporaries...
for (int i=0; i<n; ++i)
{
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
Scalar matrixQ_i_k = matrixQ[i*n+k];
matrixQ[i*n+k] = c * matrixQ_i_k - s * matrixQ[i*n+k+1];
matrixQ[i*n+k+1] = s * matrixQ_i_k + c * matrixQ[i*n+k+1];
#else
Scalar matrixQ_i_k = matrixQ[i+kn];
matrixQ[i+kn] = c * matrixQ_i_k - s * matrixQ[i+kn1];
matrixQ[i+kn1] = s * matrixQ_i_k + c * matrixQ[i+kn1];
#endif
}
} }
} }
} }

View File

@ -198,67 +198,30 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
{ {
assert(matA.rows()==matA.cols()); assert(matA.rows()==matA.cols());
int n = matA.rows(); int n = matA.rows();
for (int i = 0; i<n-2; ++i) Matrix<Scalar,1,Dynamic> aux(n);
for (int i = 0; i<n-1; ++i)
{ {
// let's consider the vector v = i-th column starting at position i+1 int remainingSize = n-i-1;
RealScalar beta;
// start of the householder transformation Scalar h;
// squared norm of the vector v skipping the first element matA.col(i).end(remainingSize).makeHouseholderInPlace(&h, &beta);
RealScalar v1norm2 = matA.col(i).end(n-(i+2)).squaredNorm();
// FIXME comparing against 1
if (ei_isMuchSmallerThan(v1norm2,static_cast<Scalar>(1)))
{
hCoeffs.coeffRef(i) = 0.;
}
else
{
Scalar v0 = matA.col(i).coeff(i+1);
RealScalar beta = ei_sqrt(ei_abs2(v0)+v1norm2);
if (ei_real(v0)>=0.)
beta = -beta;
matA.col(i).end(n-(i+2)) *= (Scalar(1)/(v0-beta));
matA.col(i).coeffRef(i+1) = beta;
Scalar h = (beta - v0) / beta;
// end of the householder transformation
// Apply similarity transformation to remaining columns, // Apply similarity transformation to remaining columns,
// i.e., A = H' A H where H = I - h v v' and v = matA.col(i).end(n-i-1) // i.e., A = H A H' where H = I - h v v' and v = matA.col(i).end(n-i-1)
matA.col(i).coeffRef(i+1) = 1; matA.col(i).coeffRef(i+1) = 1;
hCoeffs.end(n-i-1) = (matA.corner(BottomRight,n-i-1,n-i-1).template selfadjointView<LowerTriangular>() hCoeffs.end(n-i-1) = (matA.corner(BottomRight,remainingSize,remainingSize).template selfadjointView<LowerTriangular>()
* (h * matA.col(i).end(n-i-1))); * (ei_conj(h) * matA.col(i).end(remainingSize)));
hCoeffs.end(n-i-1) += (h*Scalar(-0.5)*(hCoeffs.end(n-i-1).dot(matA.col(i).end(n-i-1)))) * matA.col(i).end(n-i-1); hCoeffs.end(n-i-1) += (ei_conj(h)*Scalar(-0.5)*(hCoeffs.end(remainingSize).dot(matA.col(i).end(remainingSize)))) * matA.col(i).end(n-i-1);
matA.corner(BottomRight, n-i-1, n-i-1).template selfadjointView<LowerTriangular>() matA.corner(BottomRight, remainingSize, remainingSize).template selfadjointView<LowerTriangular>()
.rankUpdate(matA.col(i).end(n-i-1), hCoeffs.end(n-i-1), -1); .rankUpdate(matA.col(i).end(remainingSize), hCoeffs.end(remainingSize), -1);
// note: at that point matA(i+1,i+1) is the (i+1)-th element of the final diagonal
// note: the sequence of the beta values leads to the subdiagonal entries
matA.col(i).coeffRef(i+1) = beta; matA.col(i).coeffRef(i+1) = beta;
hCoeffs.coeffRef(i) = h; hCoeffs.coeffRef(i) = h;
} }
} }
if (NumTraits<Scalar>::IsComplex)
{
// Householder transformation on the remaining single scalar
int i = n-2;
Scalar v0 = matA.col(i).coeff(i+1);
RealScalar beta = ei_abs(v0);
if (ei_real(v0)>=RealScalar(0))
beta = -beta;
matA.col(i).coeffRef(i+1) = beta;
// FIXME comparing against 1
if(ei_isMuchSmallerThan(beta, Scalar(1))) hCoeffs.coeffRef(i) = Scalar(0);
else hCoeffs.coeffRef(i) = (beta - v0) / beta;
}
else
{
hCoeffs.coeffRef(n-2) = 0;
}
}
/** reconstructs and returns the matrix Q */ /** reconstructs and returns the matrix Q */
template<typename MatrixType> template<typename MatrixType>
@ -280,16 +243,8 @@ void Tridiagonalization<MatrixType>::matrixQInPlace(MatrixBase<QDerived>* q) con
Matrix<Scalar,1,Dynamic> aux(n); Matrix<Scalar,1,Dynamic> aux(n);
for (int i = n-2; i>=0; i--) for (int i = n-2; i>=0; i--)
{ {
Scalar tmp = m_matrix.coeff(i+1,i); matQ.corner(BottomRight,n-i-1,n-i-1)
m_matrix.const_cast_derived().coeffRef(i+1,i) = 1; .applyHouseholderOnTheLeft(m_matrix.col(i).end(n-i-2), ei_conj(m_hCoeffs.coeff(i)), &aux.coeffRef(0,0));
aux.end(n-i-1) = (m_hCoeffs.coeff(i) * m_matrix.col(i).end(n-i-1).adjoint() * matQ.corner(BottomRight,n-i-1,n-i-1)).lazy();
// rank one update, TODO ! make it works efficiently as expected
for (int j=i+1;j<n;++j)
matQ.col(j).end(n-i-1) -= aux.coeff(j) * m_matrix.col(i).end(n-i-1);
// matQ.corner(BottomRight,n-i-1,n-i-1) -= (m_matrix.col(i).end(n-i-1) * aux.end(n-i-1)).lazy();
m_matrix.const_cast_derived().coeffRef(i+1,i) = tmp;
} }
} }

View File

@ -0,0 +1,169 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef EIGEN_JACOBISQUARESVD_H
#define EIGEN_JACOBISQUARESVD_H
/** \ingroup SVD_Module
* \nonstableyet
*
* \class JacobiSquareSVD
*
* \brief Jacobi SVD decomposition of a square matrix
*
* \param MatrixType the type of the matrix of which we are computing the SVD decomposition
* \param ComputeU whether the U matrix should be computed
* \param ComputeV whether the V matrix should be computed
*
* \sa MatrixBase::jacobiSvd()
*/
template<typename MatrixType, bool ComputeU, bool ComputeV> class JacobiSquareSVD
{
private:
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
enum {
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
Options = MatrixType::Options
};
typedef Matrix<Scalar, Dynamic, Dynamic, Options> DummyMatrixType;
typedef typename ei_meta_if<ComputeU,
Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime,
Options, MaxRowsAtCompileTime, MaxRowsAtCompileTime>,
DummyMatrixType>::ret MatrixUType;
typedef typename Diagonal<MatrixType,0>::PlainMatrixType SingularValuesType;
typedef Matrix<Scalar, 1, RowsAtCompileTime, Options, 1, MaxRowsAtCompileTime> RowType;
typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> ColType;
public:
JacobiSquareSVD() : m_isInitialized(false) {}
JacobiSquareSVD(const MatrixType& matrix) : m_isInitialized(false)
{
compute(matrix);
}
JacobiSquareSVD& compute(const MatrixType& matrix);
const MatrixUType& matrixU() const
{
ei_assert(m_isInitialized && "SVD is not initialized.");
return m_matrixU;
}
const SingularValuesType& singularValues() const
{
ei_assert(m_isInitialized && "SVD is not initialized.");
return m_singularValues;
}
const MatrixUType& matrixV() const
{
ei_assert(m_isInitialized && "SVD is not initialized.");
return m_matrixV;
}
protected:
MatrixUType m_matrixU;
MatrixUType m_matrixV;
SingularValuesType m_singularValues;
bool m_isInitialized;
};
template<typename MatrixType, bool ComputeU, bool ComputeV>
JacobiSquareSVD<MatrixType, ComputeU, ComputeV>& JacobiSquareSVD<MatrixType, ComputeU, ComputeV>::compute(const MatrixType& matrix)
{
MatrixType work_matrix(matrix);
int size = matrix.rows();
if(ComputeU) m_matrixU = MatrixUType::Identity(size,size);
if(ComputeV) m_matrixV = MatrixUType::Identity(size,size);
m_singularValues.resize(size);
const RealScalar precision = 2 * epsilon<Scalar>();
sweep_again:
for(int p = 1; p < size; ++p)
{
for(int q = 0; q < p; ++q)
{
Scalar c, s;
while(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p)))
> std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*precision)
{
if(work_matrix.makeJacobiForAtA(p,q,&c,&s))
{
work_matrix.applyJacobiOnTheRight(p,q,c,s);
if(ComputeV) m_matrixV.applyJacobiOnTheRight(p,q,c,s);
}
if(work_matrix.makeJacobiForAAt(p,q,&c,&s))
{
ei_normalizeJacobi(&c, &s, work_matrix.coeff(p,p), work_matrix.coeff(q,p)),
work_matrix.applyJacobiOnTheLeft(p,q,c,s);
if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,c,s);
}
}
}
}
RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff();
RealScalar maxAllowedOffDiag = biggestOnDiag * precision;
for(int p = 0; p < size; ++p)
{
for(int q = 0; q < p; ++q)
if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag)
goto sweep_again;
for(int q = p+1; q < size; ++q)
if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag)
goto sweep_again;
}
m_singularValues = work_matrix.diagonal().cwise().abs();
RealScalar biggestSingularValue = m_singularValues.maxCoeff();
for(int i = 0; i < size; ++i)
{
RealScalar a = ei_abs(work_matrix.coeff(i,i));
m_singularValues.coeffRef(i) = a;
if(ComputeU && !ei_isMuchSmallerThan(a, biggestSingularValue)) m_matrixU.col(i) *= work_matrix.coeff(i,i)/a;
}
for(int i = 0; i < size; i++)
{
int pos;
m_singularValues.end(size-i).maxCoeff(&pos);
if(pos)
{
pos += i;
std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos));
if(ComputeU) m_matrixU.col(pos).swap(m_matrixU.col(i));
if(ComputeV) m_matrixV.col(pos).swap(m_matrixV.col(i));
}
}
m_isInitialized = true;
return *this;
}
#endif // EIGEN_JACOBISQUARESVD_H

View File

@ -97,8 +97,7 @@ template<typename MatrixType> class SVD
return m_matV; return m_matV;
} }
void compute(const MatrixType& matrix); SVD& compute(const MatrixType& matrix);
SVD& sort();
template<typename UnitaryType, typename PositiveType> template<typename UnitaryType, typename PositiveType>
void computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const; void computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const;
@ -139,9 +138,11 @@ template<typename MatrixType> class SVD
/** Computes / recomputes the SVD decomposition A = U S V^* of \a matrix /** Computes / recomputes the SVD decomposition A = U S V^* of \a matrix
* *
* \note this code has been adapted from Numerical Recipes, third edition. * \note this code has been adapted from Numerical Recipes, third edition.
*
* \returns a reference to *this
*/ */
template<typename MatrixType> template<typename MatrixType>
void SVD<MatrixType>::compute(const MatrixType& matrix) SVD<MatrixType>& SVD<MatrixType>::compute(const MatrixType& matrix)
{ {
const int m = matrix.rows(); const int m = matrix.rows();
const int n = matrix.cols(); const int n = matrix.cols();
@ -158,7 +159,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
SingularValuesType& W = m_sigma; SingularValuesType& W = m_sigma;
bool flag; bool flag;
int i,its,j,jj,k,l,nm; int i,its,j,k,l,nm;
Scalar anorm, c, f, g, h, s, scale, x, y, z; Scalar anorm, c, f, g, h, s, scale, x, y, z;
bool convergence = true; bool convergence = true;
Scalar eps = precision<Scalar>(); Scalar eps = precision<Scalar>();
@ -308,13 +309,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
h = Scalar(1.0)/h; h = Scalar(1.0)/h;
c = g*h; c = g*h;
s = -f*h; s = -f*h;
for (j=0; j<m; j++) V.applyJacobiOnTheRight(i,nm,c,s);
{
y = A(j,nm);
z = A(j,i);
A(j,nm) = y*c + z*s;
A(j,i) = z*c - y*s;
}
} }
} }
z = W[k]; z = W[k];
@ -347,6 +342,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
y = W[i]; y = W[i];
h = s*g; h = s*g;
g = c*g; g = c*g;
z = pythag(f,h); z = pythag(f,h);
rv1[j] = z; rv1[j] = z;
c = f/z; c = f/z;
@ -355,13 +351,8 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
g = g*c - x*s; g = g*c - x*s;
h = y*s; h = y*s;
y *= c; y *= c;
for (jj=0; jj<n; jj++) V.applyJacobiOnTheRight(i,j,c,s);
{
x = V(jj,j);
z = V(jj,i);
V(jj,j) = x*c + z*s;
V(jj,i) = z*c - x*s;
}
z = pythag(f,h); z = pythag(f,h);
W[j] = z; W[j] = z;
// Rotation can be arbitrary if z = 0. // Rotation can be arbitrary if z = 0.
@ -373,13 +364,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
} }
f = c*g + s*y; f = c*g + s*y;
x = c*y - s*g; x = c*y - s*g;
for (jj=0; jj<m; jj++) A.applyJacobiOnTheRight(i,j,c,s);
{
y = A(jj,j);
z = A(jj,i);
A(jj,j) = y*c + z*s;
A(jj,i) = z*c - y*s;
}
} }
rv1[l] = 0.0; rv1[l] = 0.0;
rv1[k] = f; rv1[k] = f;
@ -392,9 +377,10 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
int k; int k;
W.end(n-i).minCoeff(&k); W.end(n-i).maxCoeff(&k);
if (k != i) if (k != 0)
{ {
k += i;
std::swap(W[k],W[i]); std::swap(W[k],W[i]);
A.col(i).swap(A.col(k)); A.col(i).swap(A.col(k));
V.col(i).swap(V.col(k)); V.col(i).swap(V.col(k));
@ -408,44 +394,6 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
m_matU = A.block(0,0,m,m); m_matU = A.block(0,0,m,m);
m_isInitialized = true; m_isInitialized = true;
}
template<typename MatrixType>
SVD<MatrixType>& SVD<MatrixType>::sort()
{
ei_assert(m_isInitialized && "SVD is not initialized.");
int mu = m_matU.rows();
int mv = m_matV.rows();
int n = m_matU.cols();
for (int i=0; i<n; ++i)
{
int k = i;
Scalar p = m_sigma.coeff(i);
for (int j=i+1; j<n; ++j)
{
if (m_sigma.coeff(j) > p)
{
k = j;
p = m_sigma.coeff(j);
}
}
if (k != i)
{
m_sigma.coeffRef(k) = m_sigma.coeff(i); // i.e.
m_sigma.coeffRef(i) = p; // swaps the i-th and the k-th elements
int j = mu;
for(int s=0; j!=0; ++s, --j)
std::swap(m_matU.coeffRef(s,i), m_matU.coeffRef(s,k));
j = mv;
for (int s=0; j!=0; ++s, --j)
std::swap(m_matV.coeffRef(s,i), m_matV.coeffRef(s,k));
}
}
return *this; return *this;
} }

View File

@ -0,0 +1,116 @@
// This program is free software; 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.
//
// This program 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifndef ACTION_ROT
#define ACTION_ROT
#include "utilities.h"
#include "STL_interface.hh"
#include <string>
#include "init/init_function.hh"
#include "init/init_vector.hh"
#include "init/init_matrix.hh"
using namespace std;
template<class Interface>
class Action_rot {
public :
// Ctor
BTL_DONT_INLINE Action_rot( int size ):_size(size)
{
MESSAGE("Action_rot Ctor");
// STL matrix and vector initialization
typename Interface::stl_matrix tmp;
init_vector<pseudo_random>(A_stl,_size);
init_vector<pseudo_random>(B_stl,_size);
// generic matrix and vector initialization
Interface::vector_from_stl(A_ref,A_stl);
Interface::vector_from_stl(A,A_stl);
Interface::vector_from_stl(B_ref,B_stl);
Interface::vector_from_stl(B,B_stl);
}
// invalidate copy ctor
Action_rot( const Action_rot & )
{
INFOS("illegal call to Action_rot Copy Ctor");
exit(1);
}
// Dtor
BTL_DONT_INLINE ~Action_rot( void ){
MESSAGE("Action_rot Dtor");
Interface::free_vector(A);
Interface::free_vector(B);
Interface::free_vector(A_ref);
Interface::free_vector(B_ref);
}
// action name
static inline std::string name( void )
{
return "rot_" + Interface::name();
}
double nb_op_base( void ){
return 6.0*_size;
}
BTL_DONT_INLINE void initialize( void ){
Interface::copy_vector(A_ref,A,_size);
Interface::copy_vector(B_ref,B,_size);
}
BTL_DONT_INLINE void calculate( void ) {
BTL_ASM_COMMENT("#begin rot");
Interface::rot(A,B,0.5,0.6,_size);
BTL_ASM_COMMENT("end rot");
}
BTL_DONT_INLINE void check_result( void ){
// calculation check
// Interface::vector_to_stl(X,resu_stl);
// STL_interface<typename Interface::real_type>::rot(A_stl,B_stl,X_stl,_size);
// typename Interface::real_type error=
// STL_interface<typename Interface::real_type>::norm_diff(X_stl,resu_stl);
// if (error>1.e-3){
// INFOS("WRONG CALCULATION...residual=" << error);
// exit(0);
// }
}
private :
typename Interface::stl_vector A_stl;
typename Interface::stl_vector B_stl;
typename Interface::gene_vector A_ref;
typename Interface::gene_vector B_ref;
typename Interface::gene_vector A;
typename Interface::gene_vector B;
int _size;
};
#endif

View File

@ -15,6 +15,7 @@
// #include "action_symm.hh" // #include "action_symm.hh"
#include "action_syr2.hh" #include "action_syr2.hh"
#include "action_ger.hh" #include "action_ger.hh"
#include "action_rot.hh"
// #include "action_lu_solve.hh" // #include "action_lu_solve.hh"

View File

@ -15,3 +15,4 @@ hessenberg ; "{/*1.5 Hessenberg decomposition}" ; "matrix size" ; 4:3000
symv ; "{/*1.5 symmetric matrix vector product}" ; "matrix size" ; 4:3000 symv ; "{/*1.5 symmetric matrix vector product}" ; "matrix size" ; 4:3000
syr2 ; "{/*1.5 symmretric rank-2 update (A += u^T v + u v^T)}" ; "matrix size" ; 4:3000 syr2 ; "{/*1.5 symmretric rank-2 update (A += u^T v + u v^T)}" ; "matrix size" ; 4:3000
ger ; "{/*1.5 general rank-1 update (A += u v^T)}" ; "matrix size" ; 4:3000 ger ; "{/*1.5 general rank-1 update (A += u v^T)}" ; "matrix size" ; 4:3000
rot ; "{/*1.5 apply rotation in the plane}" ; "vector size" ; 4:1000000

View File

@ -48,6 +48,7 @@ source mk_mean_script.sh hessenberg $1 11 100 300 1000 $mode $prefix
source mk_mean_script.sh symv $1 11 50 300 1000 $mode $prefix source mk_mean_script.sh symv $1 11 50 300 1000 $mode $prefix
source mk_mean_script.sh syr2 $1 11 50 300 1000 $mode $prefix source mk_mean_script.sh syr2 $1 11 50 300 1000 $mode $prefix
source mk_mean_script.sh ger $1 11 50 300 1000 $mode $prefix source mk_mean_script.sh ger $1 11 50 300 1000 $mode $prefix
source mk_mean_script.sh rot $1 11 2500 100000 250000 $mode $prefix
fi fi

View File

@ -179,6 +179,14 @@ public :
#endif #endif
} }
static inline void rot(gene_vector & A, gene_vector & B, float c, float s, int N){
#ifdef PUREBLAS
srot_(&N,A,&intone,B,&intone,&c,&s);
#else
cblas_srot(N,A,1,B,1,c,s);
#endif
}
static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
#ifdef PUREBLAS #ifdef PUREBLAS
sgemv_(&trans,&N,&N,&fone,A,&N,B,&intone,&fzero,X,&intone); sgemv_(&trans,&N,&N,&fone,A,&N,B,&intone,&fzero,X,&intone);

View File

@ -45,6 +45,7 @@ int main()
bench<Action_syr2<C_BLAS_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT); bench<Action_syr2<C_BLAS_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
bench<Action_ger<C_BLAS_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT); bench<Action_ger<C_BLAS_interface<REAL_TYPE> > >(MIN_MV,MAX_MV,NB_POINT);
bench<Action_rot<C_BLAS_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
bench<Action_matrix_matrix_product<C_BLAS_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT); bench<Action_matrix_matrix_product<C_BLAS_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);
bench<Action_ata_product<C_BLAS_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT); bench<Action_ata_product<C_BLAS_interface<REAL_TYPE> > >(MIN_MM,MAX_MM,NB_POINT);

View File

@ -168,6 +168,10 @@ public :
A.col(j) += X * Y[j]; A.col(j) += X * Y[j];
} }
static EIGEN_DONT_INLINE void rot(gene_vector & A, gene_vector & B, real c, real s, int N){
ei_apply_rotation_in_the_plane(A, B, c, s);
}
static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){ static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){
X = (A.transpose()*B).lazy(); X = (A.transpose()*B).lazy();
} }

View File

@ -27,6 +27,7 @@ int main()
bench<Action_axpy<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT); bench<Action_axpy<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
bench<Action_axpby<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT); bench<Action_axpby<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
bench<Action_rot<eigen2_interface<REAL_TYPE> > >(MIN_AXPY,MAX_AXPY,NB_POINT);
return 0; return 0;
} }

View File

@ -4,7 +4,7 @@ namespace Eigen {
Executive summary: Eigen has intelligent compile-time mechanisms to enable lazy evaluation and removing temporaries where appropriate. Executive summary: Eigen has intelligent compile-time mechanisms to enable lazy evaluation and removing temporaries where appropriate.
It will handle aliasing automatically in most cases, for example with matrix products. The automatic behavior can be overridden It will handle aliasing automatically in most cases, for example with matrix products. The automatic behavior can be overridden
manually by using the MatrixBase::eval() and MatrixBase::lazy() methods. manually by using the MatrixBase::eval() and MatrixBase::noalias() methods.
When you write a line of code involving a complex expression such as When you write a line of code involving a complex expression such as
@ -42,11 +42,11 @@ Eigen chooses lazy evaluation at every stage in that example, which is clearly t
Eigen first evaluates <tt>matrix * matrix</tt> into a temporary matrix, and then copies it into the original \c matrix. This guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products. It also doesn't cost much, as the cost of the matrix product itself is much higher. Eigen first evaluates <tt>matrix * matrix</tt> into a temporary matrix, and then copies it into the original \c matrix. This guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products. It also doesn't cost much, as the cost of the matrix product itself is much higher.
What if you know what you are doing and want to force lazy evaluation? Then use \link MatrixBase::lazy() .lazy()\endlink instead. Here is an example: What if you know that the result does no alias the operand of the product and want to force lazy evaluation? Then use \link MatrixBase::noalias() .noalias()\endlink instead. Here is an example:
\code matrix1 = (matrix2 * matrix2).lazy(); \endcode \code matrix1.noalias() = matrix2 * matrix2; \endcode
Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of lazy() here is to remove the evaluate-before-assigning \link flags flag\endlink and also the evaluate-before-nesting \link flags flag\endlink which we now discuss. Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of noalias() here is to bypass the evaluate-before-assigning \link flags flag\endlink.
<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do <b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
@ -54,8 +54,6 @@ Here, since we know that matrix2 is not the same matrix as matrix1, we know that
the product <tt>matrix3 * matrix4</tt> gets evaluated immediately into a temporary matrix. Indeed, experiments showed that it is often beneficial for performance to evaluate immediately matrix products when they are nested into bigger expressions. the product <tt>matrix3 * matrix4</tt> gets evaluated immediately into a temporary matrix. Indeed, experiments showed that it is often beneficial for performance to evaluate immediately matrix products when they are nested into bigger expressions.
Again, \link MatrixBase::lazy() .lazy()\endlink can be used to force lazy evaluation here.
<b>The third circumstance</b> in which Eigen chooses immediate evaluation, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary. Indeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example: <b>The third circumstance</b> in which Eigen chooses immediate evaluation, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary. Indeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example:
\code matrix1 = matrix2 * (matrix3 + matrix4); \endcode \code matrix1 = matrix2 * (matrix3 + matrix4); \endcode

View File

@ -9,13 +9,13 @@ for small fixed size matrices. For large matrices, however, it might useful to
take some care when writing your expressions in order to minimize useless evaluations take some care when writing your expressions in order to minimize useless evaluations
and optimize the performance. and optimize the performance.
In this page we will give a brief overview of the Eigen's internal mechanism to simplify In this page we will give a brief overview of the Eigen's internal mechanism to simplify
and evaluate complex expressions, and discuss the current limitations. and evaluate complex product expressions, and discuss the current limitations.
In particular we will focus on expressions matching level 2 and 3 BLAS routines, i.e, In particular we will focus on expressions matching level 2 and 3 BLAS routines, i.e,
all kind of matrix products and triangular solvers. all kind of matrix products and triangular solvers.
Indeed, in Eigen we have implemented a set of highly optimized routines which are very similar Indeed, in Eigen we have implemented a set of highly optimized routines which are very similar
to BLAS's ones. Unlike BLAS, those routines are made available to user via a high level and to BLAS's ones. Unlike BLAS, those routines are made available to user via a high level and
natural API. Each of these routines can perform in a single evaluation a wide variety of expressions. natural API. Each of these routines can compute in a single evaluation a wide variety of expressions.
Given an expression, the challenge is then to map it to a minimal set of primitives. Given an expression, the challenge is then to map it to a minimal set of primitives.
As explained latter, this mechanism has some limitations, and knowing them will allow As explained latter, this mechanism has some limitations, and knowing them will allow
you to write faster code by making your expressions more Eigen friendly. you to write faster code by making your expressions more Eigen friendly.
@ -25,18 +25,18 @@ you to write faster code by making your expressions more Eigen friendly.
Let's start with the most common primitive: the matrix product of general dense matrices. Let's start with the most common primitive: the matrix product of general dense matrices.
In the BLAS world this corresponds to the GEMM routine. Our equivalent primitive can In the BLAS world this corresponds to the GEMM routine. Our equivalent primitive can
perform the following operation: perform the following operation:
\f$ C += \alpha op1(A) * op2(B) \f$ \f$ C.noalias() += \alpha op1(A) op2(B) \f$
where A, B, and C are column and/or row major matrices (or sub-matrices), where A, B, and C are column and/or row major matrices (or sub-matrices),
alpha is a scalar value, and op1, op2 can be transpose, adjoint, conjugate, or the identity. alpha is a scalar value, and op1, op2 can be transpose, adjoint, conjugate, or the identity.
When Eigen detects a matrix product, it analyzes both sides of the product to extract a When Eigen detects a matrix product, it analyzes both sides of the product to extract a
unique scalar factor alpha, and for each side its effective storage (order and shape) and conjugate state. unique scalar factor alpha, and for each side its effective storage (order and shape) and conjugate state.
More precisely each side is simplified by iteratively removing trivial expressions such as scalar multiple, More precisely each side is simplified by iteratively removing trivial expressions such as scalar multiple,
negate and conjugate. Transpose and Block expressions are not evaluated and only modify the storage order negate and conjugate. Transpose and Block expressions are not evaluated and they only modify the storage order
and shape. All other expressions are immediately evaluated. and shape. All other expressions are immediately evaluated.
For instance, the following expression: For instance, the following expression:
\code m1 -= (s1 * m2.adjoint() * (-(s3*m3).conjugate()*s2)).lazy() \endcode \code m1.noalias() -= s1 * m2.adjoint() * (-(s3*m3).conjugate()*s2) \endcode
is automatically simplified to: is automatically simplified to:
\code m1 += (s1*s2*conj(s3)) * m2.adjoint() * m3.conjugate() \endcode \code m1.noalias() += (s1*s2*conj(s3)) * m2.adjoint() * m3.conjugate() \endcode
which exactly matches our GEMM routine. which exactly matches our GEMM routine.
\subsection GEMM_Limitations Limitations \subsection GEMM_Limitations Limitations
@ -52,23 +52,26 @@ handled by a single GEMM-like call are correctly detected.
<tr> <tr>
<td>\code m1 += m2 * m3; \endcode</td> <td>\code m1 += m2 * m3; \endcode</td>
<td>\code temp = m2 * m3; m1 += temp; \endcode</td> <td>\code temp = m2 * m3; m1 += temp; \endcode</td>
<td>\code m1 += (m2 * m3).lazy(); \endcode</td> <td>\code m1.noalias() += m2 * m3; \endcode</td>
<td>Use .lazy() to tell Eigen the result and right-hand-sides do not alias.</td> <td>Use .noalias() to tell Eigen the result and right-hand-sides do not alias.
Otherwise the product m2 * m3 is evaluated into a temporary.</td>
</tr> </tr>
<tr> <tr>
<td>\code m1 += (s1 * (m2 * m3)).lazy(); \endcode</td> <td></td>
<td>\code temp = (m2 * m3).lazy(); m1 += s1 * temp; \endcode</td> <td></td>
<td>\code m1 += (s1 * m2 * m3).lazy(); \endcode</td> <td>\code m1.noalias() += s1 * (m2 * m3); \endcode</td>
<td>This is because m2 * m3 is immediately evaluated by the scalar product. <br> <td>This is a special feature of Eigen. Here the product between a scalar
Make sure the matrix product is the top most expression.</td> and a matrix product does not evaluate the matrix product but instead it
returns a matrix product expression tracking the scalar scaling factor. <br>
Without this optimization, the matrix product would be evaluated into a
temporary as in the next example.</td>
</tr> </tr>
<tr> <tr>
<td>\code m1 += s1 * (m2 * m3).lazy(); \endcode</td> <td>\code m1.noalias() += (m2 * m3).transpose(); \endcode</td>
<td>\code m1 += s1 * m2 * m3; // using a naive product \endcode</td> <td>\code temp = m2 * m3; m1 += temp.transpose(); \endcode</td>
<td>\code m1 += (s1 * m2 * m3).lazy(); \endcode</td> <td>\code m1.noalias() += m3.adjoint() * m3.adjoint(); \endcode</td>
<td>Even though this expression is evaluated without temporary, it is actually even <td>This is because the product expression has the EvalBeforeNesting bit which
worse than the previous case because here the .lazy() enforces Eigen to use a enforces the evaluation of the product by the Tranpose expression.</td>
naive (and slow) evaluation of the product.</td>
</tr> </tr>
<tr> <tr>
<td>\code m1 = m1 + m2 * m3; \endcode</td> <td>\code m1 = m1 + m2 * m3; \endcode</td>
@ -78,112 +81,25 @@ handled by a single GEMM-like call are correctly detected.
and so the matrix product will be immediately evaluated.</td> and so the matrix product will be immediately evaluated.</td>
</tr> </tr>
<tr> <tr>
<td>\code m1 += ((s1*m2).block(....) * m3).lazy(); \endcode</td> <td>\code m1.noalias() = m4 + m2 * m3; \endcode</td>
<td>\code temp = (s1*m2).block(....); m1 += (temp * m3).lazy(); \endcode</td> <td>\code temp = m2 * m3; m1 = m4 + temp; \endcode</td>
<td>\code m1 += (s1 * m2.block(....) * m3).lazy(); \endcode</td> <td>\code m1 = m4; m1.noalias() += m2 * m3; \endcode</td>
<td>First of all, here the .noalias() in the first expression is useless because
m2*m3 will be evaluated anyway. However, note how this expression can be rewritten
so that no temporary is evaluated. (tip: for very small fixed size matrix
it is slighlty better to rewrite it like this: m1.noalias() = m2 * m3; m1 += m4;</td>
</tr>
<tr>
<td>\code m1.noalias() += ((s1*m2).block(....) * m3); \endcode</td>
<td>\code temp = (s1*m2).block(....); m1 += temp * m3; \endcode</td>
<td>\code m1.noalias() += s1 * m2.block(....) * m3; \endcode</td>
<td>This is because our expression analyzer is currently not able to extract trivial <td>This is because our expression analyzer is currently not able to extract trivial
expressions nested in a Block expression. Therefore the nested scalar expressions nested in a Block expression. Therefore the nested scalar
multiple cannot be properly extracted.</td> multiple cannot be properly extracted.</td>
</tr> </tr>
</table> </table>
Of course all these remarks hold for all other kind of products that we will describe in the following paragraphs. Of course all these remarks hold for all other kind of products involving triangular or selfadjoint matrices.
<table class="tutorial_code">
<tr>
<td>BLAS equivalent routine</td>
<td>Efficient version <br> (compile to a single optimized evaluation)</td>
<td>Less efficient equivalent version <br> (requires multiple evaluations)</td>
<td>comments</td>
</tr>
<tr>
<td>GEMM</td>
<td>m1 = s1 * m2 * m3</td>
<td>m1 = s1 * (m2 * m3)</td>
<td>This is because m2 * m3 is evaluated by the scalar product.</td>
</tr>
<tr>
<td>GEMM</td>
<td>m1 += s1 * m2.adjoint() * m3</td>
<td>m1 += (s1 * m2).adjoint() * m3</td>
<td>This is because our expression analyzer stops at the first transpose expression and cannot extract the nested scalar multiple.</td>
</tr>
<tr>
<td>GEMM</td>
<td>m1 += m2.adjoint() * m3</td>
<td>m1 += m2.conjugate().transpose() * m3</td>
<td>For the same reason. Use .adjoint() or .transpose().conjugate()</td>
</tr>
<tr>
<td>GEMM</td>
<td>m1 -= (-(s0*m2).conjugate()*s1) * (s2 * m3.adjoint() * s3)</td>
<td></td>
<td>Note that s0 is automatically conjugated during the simplification of the expression.</td>
</tr>
<tr>
<td>SYR</td>
<td>m.sefadjointView<LowerTriangular>().rankUpdate(v,s)</td>
<td></td>
<td>Computes m += s * v * v.adjoint()</td>
</tr>
<tr>
<td>SYR2</td>
<td>m.sefadjointView<LowerTriangular>().rankUpdate(u,v,s)</td>
<td></td>
<td>Computes m += s * u * v.adjoint() + s * v * u.adjoint()</td>
</tr>
<tr>
<td>SYRK</td>
<td>m1.sefadjointView<UpperTriangular>().rankUpdate(m2.adjoint(),s)</td>
<td></td>
<td>Computes m1 += s * m2.adjoint() * m2</td>
</tr>
<tr>
<td>SYMM/HEMM</td>
<td>m3 -= s1 * m1.sefadjointView<UpperTriangular>() * m2.adjoint()</td>
<td></td>
<td></td>
</tr>
<tr>
<td>SYMM/HEMM</td>
<td>m3 += s1 * m2.transpose() * m1.conjugate().sefadjointView<UpperTriangular>()</td>
<td></td>
<td></td>
</tr>
<tr>
<td>TRMM</td>
<td>m3 -= s1 * m1.triangularView<UnitUpperTriangular>() * m2.adjoint()</td>
<td></td>
<td></td>
</tr>
<tr>
<td>TRSV / TRSM</td>
<td>m1.adjoint().triangularView<UnitLowerTriangular>().solveInPlace(m2)</td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
*/ */

View File

@ -1,11 +1,11 @@
std::string sep = "\n----------------------------------------\n"; std::string sep = "\n----------------------------------------\n";
Matrix3f m1; Matrix3d m1;
m1 << 1.111111, 2, 3.33333, 4, 5, 6, 7, 8.888888, 9; m1 << 1.111111, 2, 3.33333, 4, 5, 6, 7, 8.888888, 9;
IOFormat CommaInitFmt(4, Raw, ", ", ", ", "", "", " << ", ";"); IOFormat CommaInitFmt(StreamPrecision, DontAlignCols, ", ", ", ", "", "", " << ", ";");
IOFormat CleanFmt(4, AlignCols, ", ", "\n", "[", "]"); IOFormat CleanFmt(4, 0, ", ", "\n", "[", "]");
IOFormat OctaveFmt(4, AlignCols, ", ", ";\n", "", "", "[", "]"); IOFormat OctaveFmt(StreamPrecision, 0, ", ", ";\n", "", "", "[", "]");
IOFormat HeavyFmt(4, AlignCols, ", ", ";\n", "[", "]", "[", "]"); IOFormat HeavyFmt(FullPrecision, 0, ", ", ";\n", "[", "]", "[", "]");
std::cout << m1 << sep; std::cout << m1 << sep;
std::cout << m1.format(CommaInitFmt) << sep; std::cout << m1.format(CommaInitFmt) << sep;

View File

@ -4,7 +4,7 @@ m = M;
cout << "Here is the matrix m:" << endl << m << endl; cout << "Here is the matrix m:" << endl << m << endl;
cout << "Now we want to replace m by its own transpose." << endl; cout << "Now we want to replace m by its own transpose." << endl;
cout << "If we do m = m.transpose(), then m becomes:" << endl; cout << "If we do m = m.transpose(), then m becomes:" << endl;
m = m.transpose(); m = m.transpose() * 1;
cout << m << endl << "which is wrong!" << endl; cout << m << endl << "which is wrong!" << endl;
cout << "Now let us instead do m = m.transpose().eval(). Then m becomes" << endl; cout << "Now let us instead do m = m.transpose().eval(). Then m becomes" << endl;
m = M; m = M;

View File

@ -14,9 +14,21 @@ namespace Eigen {
* \defgroup AdolcForward_Module Adolc forward module */ * \defgroup AdolcForward_Module Adolc forward module */
/** \ingroup Unsupported_modules /** \ingroup Unsupported_modules
* \defgroup IterativeSolvers_Module Iterative solvers module */ * \defgroup AlignedVector3_Module Aligned vector3 module */
/** \ingroup Unsupported_modules
* \defgroup AutoDiff_Module Auto Diff module */
/** \ingroup Unsupported_modules /** \ingroup Unsupported_modules
* \defgroup BVH_Module BVH module */ * \defgroup BVH_Module BVH module */
/** \ingroup Unsupported_modules
* \defgroup IterativeSolvers_Module Iterative solvers module */
/** \ingroup Unsupported_modules
* \defgroup MatrixFunctions_Module Matrix functions module */
/** \ingroup Unsupported_modules
* \defgroup MoreVectorization More vectorization module */
} // namespace Eigen } // namespace Eigen

24
scripts/eigen_gen_docs Normal file
View File

@ -0,0 +1,24 @@
#!/bin/sh
# configuration
USER='orzel'
# step 1 : update
hg pull -u || (echo "update failed"; exit 1)
# step 2 : build
# todo if 'build is not there, create one:
#mkdir build
(cd build && cmake .. && make -j3 doc) || (echo "make failed"; exit 1)
#todo: n+1 where n = number of cpus
#step 3 : upload
BRANCH=`hg branch`
if [ $BRANCH == "default" ]
then
BRANCH='devel'
fi
# (the '/' at the end of path are very important, see rsync documentation)
rsync -az build/doc/html/ $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/dox-$BRANCH/ || (echo "upload failed"; exit 1)

View File

@ -21,7 +21,7 @@
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with // License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>. // Eigen. If not, see <http://www.gnu.org/licenses/>.
#define EIGEN_NO_ASSERTION_CHECKING
#include "main.h" #include "main.h"
template<typename MatrixType> void adjoint(const MatrixType& m) template<typename MatrixType> void adjoint(const MatrixType& m)
@ -110,7 +110,6 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
m3.transposeInPlace(); m3.transposeInPlace();
VERIFY_IS_APPROX(m3,m1.conjugate()); VERIFY_IS_APPROX(m3,m1.conjugate());
} }
void test_adjoint() void test_adjoint()
@ -125,5 +124,16 @@ void test_adjoint()
} }
// test a large matrix only once // test a large matrix only once
CALL_SUBTEST( adjoint(Matrix<float, 100, 100>()) ); CALL_SUBTEST( adjoint(Matrix<float, 100, 100>()) );
{
MatrixXcf a(10,10), b(10,10);
VERIFY_RAISES_ASSERT(a = a.transpose());
VERIFY_RAISES_ASSERT(a = a.transpose() + b);
VERIFY_RAISES_ASSERT(a = b + a.transpose());
VERIFY_RAISES_ASSERT(a = a.conjugate().transpose());
VERIFY_RAISES_ASSERT(a = a.adjoint());
VERIFY_RAISES_ASSERT(a = a.adjoint() + b);
VERIFY_RAISES_ASSERT(a = b + a.adjoint());
}
} }

View File

@ -120,8 +120,8 @@ void test_eigensolver_selfadjoint()
CALL_SUBTEST( selfadjointeigensolver(Matrix3f()) ); CALL_SUBTEST( selfadjointeigensolver(Matrix3f()) );
CALL_SUBTEST( selfadjointeigensolver(Matrix4d()) ); CALL_SUBTEST( selfadjointeigensolver(Matrix4d()) );
CALL_SUBTEST( selfadjointeigensolver(MatrixXf(10,10)) ); CALL_SUBTEST( selfadjointeigensolver(MatrixXf(10,10)) );
CALL_SUBTEST( selfadjointeigensolver(MatrixXcd(17,17)) );
CALL_SUBTEST( selfadjointeigensolver(MatrixXd(19,19)) ); CALL_SUBTEST( selfadjointeigensolver(MatrixXd(19,19)) );
CALL_SUBTEST( selfadjointeigensolver(MatrixXcd(17,17)) );
// some trivial but implementation-wise tricky cases // some trivial but implementation-wise tricky cases
CALL_SUBTEST( selfadjointeigensolver(MatrixXd(1,1)) ); CALL_SUBTEST( selfadjointeigensolver(MatrixXd(1,1)) );

View File

@ -27,6 +27,8 @@
template<typename MatrixType> void householder(const MatrixType& m) template<typename MatrixType> void householder(const MatrixType& m)
{ {
static bool even = true;
even = !even;
/* this test covers the following files: /* this test covers the following files:
Householder.h Householder.h
*/ */
@ -39,45 +41,54 @@ template<typename MatrixType> void householder(const MatrixType& m)
typedef Matrix<Scalar, ei_decrement_size<MatrixType::RowsAtCompileTime>::ret, 1> EssentialVectorType; typedef Matrix<Scalar, ei_decrement_size<MatrixType::RowsAtCompileTime>::ret, 1> EssentialVectorType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType; typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
RealScalar beta; Matrix<Scalar, EIGEN_ENUM_MAX(MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime), 1> _tmp(std::max(rows,cols));
Scalar* tmp = &_tmp.coeffRef(0,0);
Scalar beta;
RealScalar alpha;
EssentialVectorType essential; EssentialVectorType essential;
VectorType v1 = VectorType::Random(rows), v2; VectorType v1 = VectorType::Random(rows), v2;
v2 = v1; v2 = v1;
v1.makeHouseholder(&essential, &beta); v1.makeHouseholder(&essential, &beta, &alpha);
v1.applyHouseholderOnTheLeft(essential,beta); v1.applyHouseholderOnTheLeft(essential,beta,tmp);
VERIFY_IS_APPROX(v1.norm(), v2.norm()); VERIFY_IS_APPROX(v1.norm(), v2.norm());
VERIFY_IS_MUCH_SMALLER_THAN(v1.end(rows-1).norm(), v1.norm()); VERIFY_IS_MUCH_SMALLER_THAN(v1.end(rows-1).norm(), v1.norm());
v1 = VectorType::Random(rows); v1 = VectorType::Random(rows);
v2 = v1; v2 = v1;
v1.applyHouseholderOnTheLeft(essential,beta); v1.applyHouseholderOnTheLeft(essential,beta,tmp);
VERIFY_IS_APPROX(v1.norm(), v2.norm()); VERIFY_IS_APPROX(v1.norm(), v2.norm());
MatrixType m1(rows, cols), MatrixType m1(rows, cols),
m2(rows, cols); m2(rows, cols);
v1 = VectorType::Random(rows); v1 = VectorType::Random(rows);
if(even) v1.end(rows-1).setZero();
m1.colwise() = v1; m1.colwise() = v1;
m2 = m1; m2 = m1;
m1.col(0).makeHouseholder(&essential, &beta); m1.col(0).makeHouseholder(&essential, &beta, &alpha);
m1.applyHouseholderOnTheLeft(essential,beta); m1.applyHouseholderOnTheLeft(essential,beta,tmp);
VERIFY_IS_APPROX(m1.norm(), m2.norm()); VERIFY_IS_APPROX(m1.norm(), m2.norm());
VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1,0,rows-1,cols).norm(), m1.norm()); VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1,0,rows-1,cols).norm(), m1.norm());
VERIFY_IS_MUCH_SMALLER_THAN(ei_imag(m1(0,0)), ei_real(m1(0,0)));
VERIFY_IS_APPROX(ei_real(m1(0,0)), alpha);
v1 = VectorType::Random(rows); v1 = VectorType::Random(rows);
if(even) v1.end(rows-1).setZero();
SquareMatrixType m3(rows,rows), m4(rows,rows); SquareMatrixType m3(rows,rows), m4(rows,rows);
m3.rowwise() = v1.transpose(); m3.rowwise() = v1.transpose();
m4 = m3; m4 = m3;
m3.row(0).makeHouseholder(&essential, &beta); m3.row(0).makeHouseholder(&essential, &beta, &alpha);
m3.applyHouseholderOnTheRight(essential,beta); m3.applyHouseholderOnTheRight(essential,beta,tmp);
VERIFY_IS_APPROX(m3.norm(), m4.norm()); VERIFY_IS_APPROX(m3.norm(), m4.norm());
VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0,1,rows,rows-1).norm(), m3.norm()); VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0,1,rows,rows-1).norm(), m3.norm());
VERIFY_IS_MUCH_SMALLER_THAN(ei_imag(m3(0,0)), ei_real(m3(0,0)));
VERIFY_IS_APPROX(ei_real(m3(0,0)), alpha);
} }
void test_householder() void test_householder()
{ {
for(int i = 0; i < g_repeat; i++) { for(int i = 0; i < 2*g_repeat; i++) {
CALL_SUBTEST( householder(Matrix<double,2,2>()) ); CALL_SUBTEST( householder(Matrix<double,2,2>()) );
CALL_SUBTEST( householder(Matrix<float,2,3>()) ); CALL_SUBTEST( householder(Matrix<float,2,3>()) );
CALL_SUBTEST( householder(Matrix<double,3,5>()) ); CALL_SUBTEST( householder(Matrix<double,3,5>()) );

View File

@ -45,7 +45,7 @@ namespace Eigen
#define EI_PP_MAKE_STRING2(S) #S #define EI_PP_MAKE_STRING2(S) #S
#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
#define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, AlignCols, " ", "\n", "", "", "", "") #define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "")
#ifndef EIGEN_NO_ASSERTION_CHECKING #ifndef EIGEN_NO_ASSERTION_CHECKING

View File

@ -71,15 +71,19 @@ template<typename MatrixType> void product_notemporary(const MatrixType& m)
VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1); VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1);
VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()).lazy(), 0); VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()).lazy(), 0);
VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0);
// NOTE in this case the slow product is used: // NOTE in this case the slow product is used:
// FIXME: // FIXME:
// VERIFY_EVALUATION_COUNT( m3 = s1 * (m1 * m2.transpose()).lazy(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0);
VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * m2.adjoint()).lazy(), 0); VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * m2.adjoint()).lazy(), 0);
VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * (m1*s3+m2*s2).adjoint()).lazy(), 1); VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * (m1*s3+m2*s2).adjoint()).lazy(), 1);
VERIFY_EVALUATION_COUNT( m3 = ((s1 * m1).adjoint() * s2 * m2).lazy(), 0); VERIFY_EVALUATION_COUNT( m3 = ((s1 * m1).adjoint() * s2 * m2).lazy(), 0);
VERIFY_EVALUATION_COUNT( m3 -= (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0); VERIFY_EVALUATION_COUNT( m3 += (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0);
VERIFY_EVALUATION_COUNT( m3 -= (s1 * (m1.transpose() * m2)).lazy(), 1); VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0);
VERIFY_EVALUATION_COUNT( m3 -= (s1 * (m1.transpose() * m2)).lazy(), 0);
VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0);
VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) += (-m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint()).lazy() ), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) += (-m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint()).lazy() ), 0);
VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) -= (s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1)).lazy() ), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) -= (s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1)).lazy() ), 0);

View File

@ -94,6 +94,11 @@ template<typename Scalar, int Size, int OtherSize> void symm(int size = Size, in
VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<LowerTriangular>() * (s2*rhs3).conjugate(), VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<LowerTriangular>() * (s2*rhs3).conjugate(),
rhs13 = (s1*m1.adjoint()) * (s2*rhs3).conjugate()); rhs13 = (s1*m1.adjoint()) * (s2*rhs3).conjugate());
m2 = m1.template triangularView<UpperTriangular>(); rhs13 = rhs12;
VERIFY_IS_APPROX(rhs12 += (s1 * ((m2.adjoint()).template selfadjointView<LowerTriangular>() * (s2*rhs3).conjugate())).lazy(),
rhs13 += (s1*m1.adjoint()) * (s2*rhs3).conjugate());
// test matrix * selfadjoint // test matrix * selfadjoint
symm_extra<OtherSize>::run(m1,m2,rhs2,rhs22,rhs23,s1,s2); symm_extra<OtherSize>::run(m1,m2,rhs2,rhs22,rhs23,s1,s2);

View File

@ -25,9 +25,9 @@
#include "main.h" #include "main.h"
#define VERIFY_TRSM(TRI,XB) { \ #define VERIFY_TRSM(TRI,XB) { \
XB.setRandom(); ref = XB; \ (XB).setRandom(); ref = (XB); \
TRI.template solveInPlace(XB); \ (TRI).solveInPlace(XB); \
VERIFY_IS_APPROX(TRI.toDense() * XB, ref); \ VERIFY_IS_APPROX((TRI).toDense() * (XB), ref); \
} }
template<typename Scalar> void trsm(int size,int cols) template<typename Scalar> void trsm(int size,int cols)

View File

@ -37,8 +37,8 @@ template<typename MatrixType> void qr(const MatrixType& m)
MatrixType a = MatrixType::Random(rows,cols); MatrixType a = MatrixType::Random(rows,cols);
HouseholderQR<MatrixType> qrOfA(a); HouseholderQR<MatrixType> qrOfA(a);
VERIFY_IS_APPROX(a, qrOfA.matrixQ() * qrOfA.matrixR()); VERIFY_IS_APPROX(a, qrOfA.matrixQ() * qrOfA.matrixR().toDense());
VERIFY_IS_NOT_APPROX(a+MatrixType::Identity(rows, cols), qrOfA.matrixQ() * qrOfA.matrixR()); VERIFY_IS_NOT_APPROX(a+MatrixType::Identity(rows, cols), qrOfA.matrixQ() * qrOfA.matrixR().toDense());
SquareMatrixType b = a.adjoint() * a; SquareMatrixType b = a.adjoint() * a;
@ -59,7 +59,7 @@ template<typename MatrixType> void qr_invertible()
{ {
/* this test covers the following files: QR.h */ /* this test covers the following files: QR.h */
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
int size = ei_random<int>(10,200); int size = ei_random<int>(10,50);
MatrixType m1(size, size), m2(size, size), m3(size, size); MatrixType m1(size, size), m2(size, size), m3(size, size);
m1 = MatrixType::Random(size,size); m1 = MatrixType::Random(size,size);
@ -74,7 +74,6 @@ template<typename MatrixType> void qr_invertible()
HouseholderQR<MatrixType> qr(m1); HouseholderQR<MatrixType> qr(m1);
m3 = MatrixType::Random(size,size); m3 = MatrixType::Random(size,size);
qr.solve(m3, &m2); qr.solve(m3, &m2);
//std::cerr << m3 - m1*m2 << "\n\n";
VERIFY_IS_APPROX(m3, m1*m2); VERIFY_IS_APPROX(m3, m1*m2);
} }
@ -91,20 +90,18 @@ template<typename MatrixType> void qr_verify_assert()
void test_qr() void test_qr()
{ {
for(int i = 0; i < 1; i++) { for(int i = 0; i < 1; i++) {
// FIXME : very weird bug here
// CALL_SUBTEST( qr(Matrix2f()) ); // CALL_SUBTEST( qr(Matrix2f()) );
// CALL_SUBTEST( qr(Matrix4d()) ); CALL_SUBTEST( qr(Matrix4d()) );
// CALL_SUBTEST( qr(MatrixXf(12,8)) ); CALL_SUBTEST( qr(MatrixXf(47,40)) );
// CALL_SUBTEST( qr(MatrixXcd(5,5)) ); CALL_SUBTEST( qr(MatrixXcd(17,7)) );
// CALL_SUBTEST( qr(MatrixXcd(7,3)) );
CALL_SUBTEST( qr(MatrixXf(47,47)) );
} }
for(int i = 0; i < g_repeat; i++) { for(int i = 0; i < g_repeat; i++) {
CALL_SUBTEST( qr_invertible<MatrixXf>() ); CALL_SUBTEST( qr_invertible<MatrixXf>() );
CALL_SUBTEST( qr_invertible<MatrixXd>() ); CALL_SUBTEST( qr_invertible<MatrixXd>() );
// TODO fix issue with complex CALL_SUBTEST( qr_invertible<MatrixXcf>() );
// CALL_SUBTEST( qr_invertible<MatrixXcf>() ); CALL_SUBTEST( qr_invertible<MatrixXcd>() );
// CALL_SUBTEST( qr_invertible<MatrixXcd>() );
} }
CALL_SUBTEST(qr_verify_assert<Matrix3f>()); CALL_SUBTEST(qr_verify_assert<Matrix3f>());

View File

@ -86,7 +86,8 @@ template<typename MatrixType> void submatrices(const MatrixType& m)
//check row() and col() //check row() and col()
VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1)); VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1));
VERIFY_IS_APPROX(m1.col(c1).dot(square.row(r1)), (square.lazy() * m1.conjugate()).eval()(r1,c1)); // FIXME perhaps we should re-enable that without the .eval()
VERIFY_IS_APPROX(m1.col(c1).dot(square.row(r1)), (square * m1.conjugate()).eval()(r1,c1));
//check operator(), both constant and non-constant, on row() and col() //check operator(), both constant and non-constant, on row() and col()
m1.row(r1) += s1 * m1.row(r2); m1.row(r1) += s1 * m1.row(r2);
m1.col(c1) += s1 * m1.col(c2); m1.col(c1) += s1 * m1.col(c2);

View File

@ -95,7 +95,6 @@ template<typename MatrixType> void svd_verify_assert()
VERIFY_RAISES_ASSERT(svd.matrixU()) VERIFY_RAISES_ASSERT(svd.matrixU())
VERIFY_RAISES_ASSERT(svd.singularValues()) VERIFY_RAISES_ASSERT(svd.singularValues())
VERIFY_RAISES_ASSERT(svd.matrixV()) VERIFY_RAISES_ASSERT(svd.matrixV())
VERIFY_RAISES_ASSERT(svd.sort())
VERIFY_RAISES_ASSERT(svd.computeUnitaryPositive(&tmp,&tmp)) VERIFY_RAISES_ASSERT(svd.computeUnitaryPositive(&tmp,&tmp))
VERIFY_RAISES_ASSERT(svd.computePositiveUnitary(&tmp,&tmp)) VERIFY_RAISES_ASSERT(svd.computePositiveUnitary(&tmp,&tmp))
VERIFY_RAISES_ASSERT(svd.computeRotationScaling(&tmp,&tmp)) VERIFY_RAISES_ASSERT(svd.computeRotationScaling(&tmp,&tmp))

View File

@ -152,9 +152,20 @@ template<typename _Scalar> class AlignedVector3
{ {
ei_assert(m_coeffs.w()==Scalar(0)); ei_assert(m_coeffs.w()==Scalar(0));
ei_assert(other.m_coeffs.w()==Scalar(0)); ei_assert(other.m_coeffs.w()==Scalar(0));
Scalar r = m_coeffs.dot(other.m_coeffs);
return m_coeffs.dot(other.m_coeffs); return m_coeffs.dot(other.m_coeffs);
} }
inline void normalize()
{
m_coeffs /= norm();
}
inline AlignedVector3 normalized()
{
return AlignedVector3(m_coeffs / norm());
}
inline Scalar sum() const inline Scalar sum() const
{ {
ei_assert(m_coeffs.w()==Scalar(0)); ei_assert(m_coeffs.w()==Scalar(0));

View File

@ -6,7 +6,7 @@
namespace Eigen { namespace Eigen {
/** \ingroup Unsupported_modules /** \ingroup Unsupported_modules
* \defgroup MoreVectorization additional vectorization module * \defgroup MoreVectorization More vectorization module
*/ */
#include "src/MoreVectorization/MathFunctions.h" #include "src/MoreVectorization/MathFunctions.h"

View File

@ -108,7 +108,7 @@ void ei_pseudo_inverse(const CMatrix &C, CINVMatrix &CINV)
/** \ingroup IterativeSolvers_Module /** \ingroup IterativeSolvers_Module
* Constrained conjugate gradient * Constrained conjugate gradient
* *
* Computes the minimum of \f$ 1/2((Ax).x) - bx \f$ under the contraint \f$ Cx <= f @\$ * Computes the minimum of \f$ 1/2((Ax).x) - bx \f$ under the contraint \f$ Cx \le f \f$
*/ */
template<typename TMatrix, typename CMatrix, template<typename TMatrix, typename CMatrix,
typename VectorX, typename VectorB, typename VectorF> typename VectorX, typename VectorB, typename VectorF>

View File

@ -25,11 +25,7 @@
#ifndef EIGEN_MATRIX_EXPONENTIAL #ifndef EIGEN_MATRIX_EXPONENTIAL
#define EIGEN_MATRIX_EXPONENTIAL #define EIGEN_MATRIX_EXPONENTIAL
#ifdef _MSC_VER /** \brief Compute the matrix exponential.
template <typename Scalar> Scalar log2(Scalar v) { return std::log(v)/std::log(Scalar(2)); }
#endif
/** Compute the matrix exponential.
* *
* \param M matrix whose exponential is to be computed. * \param M matrix whose exponential is to be computed.
* \param result pointer to the matrix in which to store the result. * \param result pointer to the matrix in which to store the result.
@ -58,103 +54,264 @@ template <typename Scalar> Scalar log2(Scalar v) { return std::log(v)/std::log(S
* <em>SIAM J. %Matrix Anal. Applic.</em>, <b>26</b>:1179&ndash;1193, * <em>SIAM J. %Matrix Anal. Applic.</em>, <b>26</b>:1179&ndash;1193,
* 2005. * 2005.
* *
* \note Currently, \p M has to be a matrix of \c double . * \note \p M has to be a matrix of \c float, \c double,
* \c complex<float> or \c complex<double> .
*/ */
template <typename Derived> template <typename Derived>
void ei_matrix_exponential(const MatrixBase<Derived> &M, typename ei_plain_matrix_type<Derived>::type* result) EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase<Derived> &M,
typename MatrixBase<Derived>::PlainMatrixType* result);
/** \internal \brief Internal helper functions for computing the
* matrix exponential.
*/
namespace MatrixExponentialInternal {
#ifdef _MSC_VER
template <typename Scalar> Scalar log2(Scalar v) { return std::log(v)/std::log(Scalar(2)); }
#endif
/** \internal \brief Compute the (3,3)-Pad&eacute; approximant to
* the exponential.
*
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
* approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$.
*
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp Temporary storage, to be provided by the caller
* \param M2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
*/
template <typename MatrixType>
EIGEN_STRONG_INLINE void pade3(const MatrixType &M, const MatrixType& Id, MatrixType& tmp,
MatrixType& M2, MatrixType& U, MatrixType& V)
{ {
typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_traits<MatrixType>::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef typename ei_plain_matrix_type<Derived>::type PlainMatrixType;
ei_assert(M.rows() == M.cols());
EIGEN_STATIC_ASSERT(NumTraits<Scalar>::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT)
PlainMatrixType num, den, U, V;
PlainMatrixType Id = PlainMatrixType::Identity(M.rows(), M.cols());
typename ei_eval<Derived>::type Meval = M.eval();
RealScalar l1norm = Meval.cwise().abs().colwise().sum().maxCoeff();
int squarings = 0;
// Choose degree of Pade approximant, depending on norm of M
if (l1norm < 1.495585217958292e-002) {
// Use (3,3)-Pade
const Scalar b[] = {120., 60., 12., 1.}; const Scalar b[] = {120., 60., 12., 1.};
PlainMatrixType M2; M2 = (M * M).lazy();
M2 = (Meval * Meval).lazy(); tmp = b[3]*M2 + b[1]*Id;
num = b[3]*M2 + b[1]*Id; U = (M * tmp).lazy();
U = (Meval * num).lazy();
V = b[2]*M2 + b[0]*Id; V = b[2]*M2 + b[0]*Id;
}
} else if (l1norm < 2.539398330063230e-001) { /** \internal \brief Compute the (5,5)-Pad&eacute; approximant to
* the exponential.
// Use (5,5)-Pade *
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
* approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$.
*
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp Temporary storage, to be provided by the caller
* \param M2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
*/
template <typename MatrixType>
EIGEN_STRONG_INLINE void pade5(const MatrixType &M, const MatrixType& Id, MatrixType& tmp,
MatrixType& M2, MatrixType& U, MatrixType& V)
{
typedef typename ei_traits<MatrixType>::Scalar Scalar;
const Scalar b[] = {30240., 15120., 3360., 420., 30., 1.}; const Scalar b[] = {30240., 15120., 3360., 420., 30., 1.};
PlainMatrixType M2, M4; M2 = (M * M).lazy();
M2 = (Meval * Meval).lazy(); MatrixType M4 = (M2 * M2).lazy();
M4 = (M2 * M2).lazy(); tmp = b[5]*M4 + b[3]*M2 + b[1]*Id;
num = b[5]*M4 + b[3]*M2 + b[1]*Id; U = (M * tmp).lazy();
U = (Meval * num).lazy();
V = b[4]*M4 + b[2]*M2 + b[0]*Id; V = b[4]*M4 + b[2]*M2 + b[0]*Id;
}
} else if (l1norm < 9.504178996162932e-001) { /** \internal \brief Compute the (7,7)-Pad&eacute; approximant to
* the exponential.
// Use (7,7)-Pade *
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
* approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$.
*
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp Temporary storage, to be provided by the caller
* \param M2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
*/
template <typename MatrixType>
EIGEN_STRONG_INLINE void pade7(const MatrixType &M, const MatrixType& Id, MatrixType& tmp,
MatrixType& M2, MatrixType& U, MatrixType& V)
{
typedef typename ei_traits<MatrixType>::Scalar Scalar;
const Scalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.}; const Scalar b[] = {17297280., 8648640., 1995840., 277200., 25200., 1512., 56., 1.};
PlainMatrixType M2, M4, M6; M2 = (M * M).lazy();
M2 = (Meval * Meval).lazy(); MatrixType M4 = (M2 * M2).lazy();
M4 = (M2 * M2).lazy(); MatrixType M6 = (M4 * M2).lazy();
M6 = (M4 * M2).lazy(); tmp = b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id;
num = b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; U = (M * tmp).lazy();
U = (Meval * num).lazy();
V = b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; V = b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id;
}
} else if (l1norm < 2.097847961257068e+000) { /** \internal \brief Compute the (9,9)-Pad&eacute; approximant to
* the exponential.
// Use (9,9)-Pade *
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
* approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$.
*
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp Temporary storage, to be provided by the caller
* \param M2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
*/
template <typename MatrixType>
EIGEN_STRONG_INLINE void pade9(const MatrixType &M, const MatrixType& Id, MatrixType& tmp,
MatrixType& M2, MatrixType& U, MatrixType& V)
{
typedef typename ei_traits<MatrixType>::Scalar Scalar;
const Scalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240., const Scalar b[] = {17643225600., 8821612800., 2075673600., 302702400., 30270240.,
2162160., 110880., 3960., 90., 1.}; 2162160., 110880., 3960., 90., 1.};
PlainMatrixType M2, M4, M6, M8; M2 = (M * M).lazy();
M2 = (Meval * Meval).lazy(); MatrixType M4 = (M2 * M2).lazy();
M4 = (M2 * M2).lazy(); MatrixType M6 = (M4 * M2).lazy();
M6 = (M4 * M2).lazy(); MatrixType M8 = (M6 * M2).lazy();
M8 = (M6 * M2).lazy(); tmp = b[9]*M8 + b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id;
num = b[9]*M8 + b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id; U = (M * tmp).lazy();
U = (Meval * num).lazy();
V = b[8]*M8 + b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id; V = b[8]*M8 + b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id;
}
} else { /** \internal \brief Compute the (13,13)-Pad&eacute; approximant to
* the exponential.
// Use (13,13)-Pade; scale matrix by power of 2 so that its norm *
// is small enough * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Pad&eacute;
* approximant of \f$ \exp(M) \f$ around \f$ M = 0 \f$.
const Scalar maxnorm = 5.371920351148152; *
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp Temporary storage, to be provided by the caller
* \param M2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
*/
template <typename MatrixType>
EIGEN_STRONG_INLINE void pade13(const MatrixType &M, const MatrixType& Id, MatrixType& tmp,
MatrixType& M2, MatrixType& U, MatrixType& V)
{
typedef typename ei_traits<MatrixType>::Scalar Scalar;
const Scalar b[] = {64764752532480000., 32382376266240000., 7771770303897600., const Scalar b[] = {64764752532480000., 32382376266240000., 7771770303897600.,
1187353796428800., 129060195264000., 10559470521600., 670442572800., 1187353796428800., 129060195264000., 10559470521600., 670442572800.,
33522128640., 1323241920., 40840800., 960960., 16380., 182., 1.}; 33522128640., 1323241920., 40840800., 960960., 16380., 182., 1.};
M2 = (M * M).lazy();
squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm))); MatrixType M4 = (M2 * M2).lazy();
PlainMatrixType A, A2, A4, A6; MatrixType M6 = (M4 * M2).lazy();
A = Meval / pow(Scalar(2), squarings); V = b[13]*M6 + b[11]*M4 + b[9]*M2;
A2 = (A * A).lazy(); tmp = (M6 * V).lazy();
A4 = (A2 * A2).lazy(); tmp += b[7]*M6 + b[5]*M4 + b[3]*M2 + b[1]*Id;
A6 = (A4 * A2).lazy(); U = (M * tmp).lazy();
num = b[13]*A6 + b[11]*A4 + b[9]*A2; tmp = b[12]*M6 + b[10]*M4 + b[8]*M2;
V = (A6 * num).lazy(); V = (M6 * tmp).lazy();
num = V + b[7]*A6 + b[5]*A4 + b[3]*A2 + b[1]*Id; V += b[6]*M6 + b[4]*M4 + b[2]*M2 + b[0]*Id;
U = (A * num).lazy();
num = b[12]*A6 + b[10]*A4 + b[8]*A2;
V = (A6 * num).lazy() + b[6]*A6 + b[4]*A4 + b[2]*A2 + b[0]*Id;
} }
/** \internal \brief Helper class for computing Pad&eacute;
* approximants to the exponential.
*/
template <typename MatrixType, typename RealScalar = typename NumTraits<typename ei_traits<MatrixType>::Scalar>::Real>
struct computeUV_selector
{
/** \internal \brief Compute Pad&eacute; approximant to the exponential.
*
* Computes \p U, \p V and \p squarings such that \f$ (V+U)(V-U)^{-1} \f$
* is a Pad&eacute; of \f$ \exp(2^{-\mbox{squarings}}M) \f$
* around \f$ M = 0 \f$. The degree of the Pad&eacute;
* approximant and the value of squarings are chosen such that
* the approximation error is no more than the round-off error.
*
* \param M Argument of matrix exponential
* \param Id Identity matrix of same size as M
* \param tmp1 Temporary storage, to be provided by the caller
* \param tmp2 Temporary storage, to be provided by the caller
* \param U Even-degree terms in numerator of Pad&eacute; approximant
* \param V Odd-degree terms in numerator of Pad&eacute; approximant
* \param l1norm L<sub>1</sub> norm of M
* \param squarings Pointer to integer containing number of times
* that the result needs to be squared to find the
* matrix exponential
*/
static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2,
MatrixType& U, MatrixType& V, float l1norm, int* squarings);
};
template <typename MatrixType>
struct computeUV_selector<MatrixType, float>
{
static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2,
MatrixType& U, MatrixType& V, float l1norm, int* squarings)
{
*squarings = 0;
if (l1norm < 4.258730016922831e-001) {
pade3(M, Id, tmp1, tmp2, U, V);
} else if (l1norm < 1.880152677804762e+000) {
pade5(M, Id, tmp1, tmp2, U, V);
} else {
const float maxnorm = 3.925724783138660;
*squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm)));
MatrixType A = M / std::pow(typename ei_traits<MatrixType>::Scalar(2), *squarings);
pade7(A, Id, tmp1, tmp2, U, V);
}
}
};
template <typename MatrixType>
struct computeUV_selector<MatrixType, double>
{
static void run(const MatrixType &M, const MatrixType& Id, MatrixType& tmp1, MatrixType& tmp2,
MatrixType& U, MatrixType& V, float l1norm, int* squarings)
{
*squarings = 0;
if (l1norm < 1.495585217958292e-002) {
pade3(M, Id, tmp1, tmp2, U, V);
} else if (l1norm < 2.539398330063230e-001) {
pade5(M, Id, tmp1, tmp2, U, V);
} else if (l1norm < 9.504178996162932e-001) {
pade7(M, Id, tmp1, tmp2, U, V);
} else if (l1norm < 2.097847961257068e+000) {
pade9(M, Id, tmp1, tmp2, U, V);
} else {
const double maxnorm = 5.371920351148152;
*squarings = std::max(0, (int)ceil(log2(l1norm / maxnorm)));
MatrixType A = M / std::pow(typename ei_traits<MatrixType>::Scalar(2), *squarings);
pade13(A, Id, tmp1, tmp2, U, V);
}
}
};
/** \internal \brief Compute the matrix exponential.
*
* \param M matrix whose exponential is to be computed.
* \param result pointer to the matrix in which to store the result.
*/
template <typename MatrixType>
void compute(const MatrixType &M, MatrixType* result)
{
MatrixType num, den, U, V;
MatrixType Id = MatrixType::Identity(M.rows(), M.cols());
float l1norm = M.cwise().abs().colwise().sum().maxCoeff();
int squarings;
computeUV_selector<MatrixType>::run(M, Id, num, den, U, V, l1norm, &squarings);
num = U + V; // numerator of Pade approximant num = U + V; // numerator of Pade approximant
den = -U + V; // denominator of Pade approximant den = -U + V; // denominator of Pade approximant
den.lu().solve(num, result); den.partialLu().solve(num, result);
// Undo scaling by repeated squaring
for (int i=0; i<squarings; i++) for (int i=0; i<squarings; i++)
*result *= *result; *result *= *result; // undo scaling by repeated squaring
}
} // end of namespace MatrixExponentialInternal
template <typename Derived>
EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase<Derived> &M,
typename MatrixBase<Derived>::PlainMatrixType* result)
{
ei_assert(M.rows() == M.cols());
MatrixExponentialInternal::compute(M.eval(), result);
} }
#endif // EIGEN_MATRIX_EXPONENTIAL #endif // EIGEN_MATRIX_EXPONENTIAL

View File

@ -57,6 +57,10 @@ void alignedvector3()
VERIFY_IS_APPROX(f2.cross(f3),r2.cross(r3)); VERIFY_IS_APPROX(f2.cross(f3),r2.cross(r3));
VERIFY_IS_APPROX(f2.norm(),r2.norm()); VERIFY_IS_APPROX(f2.norm(),r2.norm());
VERIFY_IS_APPROX(f2.normalized(),r2.normalized());
VERIFY_IS_APPROX((f2+f1).normalized(),(r2+r1).normalized());
f2.normalize(); f2.normalize();
r2.normalize(); r2.normalize();
VERIFY_IS_APPROX(f2,r2); VERIFY_IS_APPROX(f2,r2);

View File

@ -34,26 +34,47 @@ double binom(int n, int k)
return res; return res;
} }
void test2dRotation() template <typename T>
void test2dRotation(double tol)
{ {
Matrix2d A, B, C; Matrix<T,2,2> A, B, C;
double angle; T angle;
A << 0, 1, -1, 0;
for (int i=0; i<=20; i++) for (int i=0; i<=20; i++)
{ {
angle = pow(10, i / 5. - 2); angle = pow(10, i / 5. - 2);
A << 0, angle, -angle, 0;
B << cos(angle), sin(angle), -sin(angle), cos(angle); B << cos(angle), sin(angle), -sin(angle), cos(angle);
ei_matrix_exponential(A, &C); ei_matrix_exponential(angle*A, &C);
VERIFY(C.isApprox(B, 1e-14)); VERIFY(C.isApprox(B, tol));
} }
} }
void testPascal() template <typename T>
void test2dHyperbolicRotation(double tol)
{
Matrix<std::complex<T>,2,2> A, B, C;
std::complex<T> imagUnit(0,1);
T angle, ch, sh;
for (int i=0; i<=20; i++)
{
angle = (i-10) / 2.0;
ch = std::cosh(angle);
sh = std::sinh(angle);
A << 0, angle*imagUnit, -angle*imagUnit, 0;
B << ch, sh*imagUnit, -sh*imagUnit, ch;
ei_matrix_exponential(A, &C);
VERIFY(C.isApprox(B, tol));
}
}
template <typename T>
void testPascal(double tol)
{ {
for (int size=1; size<20; size++) for (int size=1; size<20; size++)
{ {
MatrixXd A(size,size), B(size,size), C(size,size); Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size);
A.setZero(); A.setZero();
for (int i=0; i<size-1; i++) for (int i=0; i<size-1; i++)
A(i+1,i) = i+1; A(i+1,i) = i+1;
@ -62,11 +83,12 @@ void testPascal()
for (int j=0; j<=i; j++) for (int j=0; j<=i; j++)
B(i,j) = binom(i,j); B(i,j) = binom(i,j);
ei_matrix_exponential(A, &C); ei_matrix_exponential(A, &C);
VERIFY(C.isApprox(B, 1e-14)); VERIFY(C.isApprox(B, tol));
} }
} }
template<typename MatrixType> void randomTest(const MatrixType& m) template<typename MatrixType>
void randomTest(const MatrixType& m, double tol)
{ {
/* this test covers the following files: /* this test covers the following files:
Inverse.h Inverse.h
@ -80,16 +102,24 @@ template<typename MatrixType> void randomTest(const MatrixType& m)
m1 = MatrixType::Random(rows, cols); m1 = MatrixType::Random(rows, cols);
ei_matrix_exponential(m1, &m2); ei_matrix_exponential(m1, &m2);
ei_matrix_exponential(-m1, &m3); ei_matrix_exponential(-m1, &m3);
VERIFY(identity.isApprox(m2 * m3, 1e-13)); VERIFY(identity.isApprox(m2 * m3, tol));
} }
} }
void test_matrixExponential() void test_matrixExponential()
{ {
CALL_SUBTEST(test2dRotation()); CALL_SUBTEST(test2dRotation<double>(1e-14));
CALL_SUBTEST(testPascal()); CALL_SUBTEST(test2dRotation<float>(1e-5));
CALL_SUBTEST(randomTest(Matrix2d())); CALL_SUBTEST(test2dHyperbolicRotation<double>(1e-14));
CALL_SUBTEST(randomTest(Matrix3d())); CALL_SUBTEST(test2dHyperbolicRotation<float>(1e-5));
CALL_SUBTEST(randomTest(Matrix4d())); CALL_SUBTEST(testPascal<float>(1e-5));
CALL_SUBTEST(randomTest(MatrixXd(8,8))); CALL_SUBTEST(testPascal<double>(1e-14));
CALL_SUBTEST(randomTest(Matrix2d(), 1e-13));
CALL_SUBTEST(randomTest(Matrix<double,3,3,RowMajor>(), 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));
} }