From d40c110053c13692ffc0df25fca292d98996d496 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 22 Jan 2010 10:15:41 +0100 Subject: [PATCH 001/109] lot of cleaning: - clean the *_PUBLIC_INTERFACE_* - update Diagonal, ReturnByValue, ForceAlignedAccess, UnaryView, etc. to support array - many other small stuff --- Eigen/src/Array/Array.h | 2 +- Eigen/src/Array/ArrayWrapper.h | 7 +- Eigen/src/Array/Replicate.h | 4 +- Eigen/src/Array/Reverse.h | 4 +- Eigen/src/Array/Select.h | 4 +- Eigen/src/Array/VectorwiseOp.h | 4 +- Eigen/src/Core/Block.h | 4 +- Eigen/src/Core/CwiseBinaryOp.h | 7 +- Eigen/src/Core/CwiseNullaryOp.h | 4 +- Eigen/src/Core/CwiseUnaryOp.h | 28 +++---- Eigen/src/Core/CwiseUnaryView.h | 28 +++---- Eigen/src/Core/DenseBase.h | 2 +- Eigen/src/Core/Diagonal.h | 5 +- Eigen/src/Core/DiagonalProduct.h | 3 +- Eigen/src/Core/ForceAlignedAccess.h | 7 +- Eigen/src/Core/Map.h | 2 +- Eigen/src/Core/Matrix.h | 8 +- Eigen/src/Core/Minor.h | 3 +- Eigen/src/Core/NestByValue.h | 7 +- Eigen/src/Core/ProductBase.h | 7 +- Eigen/src/Core/ReturnByValue.h | 10 ++- Eigen/src/Core/SelfCwiseBinaryOp.h | 4 +- Eigen/src/Core/Swap.h | 2 +- Eigen/src/Core/Transpose.h | 39 ++++----- Eigen/src/Core/VectorBlock.h | 4 +- Eigen/src/Core/products/GeneralUnrolled.h | 5 +- Eigen/src/Core/util/BlasUtil.h | 18 ++--- Eigen/src/Core/util/Macros.h | 61 +++++--------- Eigen/src/Eigen2Support/Flagged.h | 3 +- Eigen/src/Geometry/Homogeneous.h | 5 +- Eigen/src/Sparse/SparseBlock.h | 97 +---------------------- Eigen/src/Sparse/SparseCwiseUnaryOp.h | 6 +- Eigen/src/Sparse/SparseProduct.h | 5 +- 33 files changed, 140 insertions(+), 259 deletions(-) diff --git a/Eigen/src/Array/Array.h b/Eigen/src/Array/Array.h index b8328417a..ceef71afd 100644 --- a/Eigen/src/Array/Array.h +++ b/Eigen/src/Array/Array.h @@ -38,7 +38,7 @@ class Array public: typedef DenseStorageBase, Eigen::ArrayBase, _Options> Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(Array) + EIGEN_DENSE_PUBLIC_INTERFACE(Array) enum { Options = _Options }; typedef typename Base::PlainMatrixType PlainMatrixType; diff --git a/Eigen/src/Array/ArrayWrapper.h b/Eigen/src/Array/ArrayWrapper.h index b62d66d8c..9b7c83951 100644 --- a/Eigen/src/Array/ArrayWrapper.h +++ b/Eigen/src/Array/ArrayWrapper.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -46,7 +46,7 @@ class ArrayWrapper : public ArrayBase > { public: typedef ArrayBase Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) + EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) inline ArrayWrapper(const ExpressionType& matrix) : m_expression(matrix) {} @@ -127,7 +127,8 @@ template class MatrixWrapper : public MatrixBase > { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(MatrixWrapper) + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper); inline MatrixWrapper(const ExpressionType& matrix) : m_expression(matrix) {} diff --git a/Eigen/src/Array/Replicate.h b/Eigen/src/Array/Replicate.h index 3f87e09fe..0b1b58f1b 100644 --- a/Eigen/src/Array/Replicate.h +++ b/Eigen/src/Array/Replicate.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -66,7 +66,7 @@ template class Replicate public: typedef typename MatrixType::template MakeBase< Replicate >::Type Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Replicate) + EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) template inline explicit Replicate(const OriginalMatrixType& matrix) diff --git a/Eigen/src/Array/Reverse.h b/Eigen/src/Array/Reverse.h index 7d2c34816..c908e8d9c 100644 --- a/Eigen/src/Array/Reverse.h +++ b/Eigen/src/Array/Reverse.h @@ -3,7 +3,7 @@ // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2009 Ricard Marxer -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -80,7 +80,7 @@ template class Reverse public: typedef typename MatrixType::template MakeBase< Reverse >::Type Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Reverse) + EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) protected: enum { diff --git a/Eigen/src/Array/Select.h b/Eigen/src/Array/Select.h index b1fab69c9..38c1a716f 100644 --- a/Eigen/src/Array/Select.h +++ b/Eigen/src/Array/Select.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -69,7 +69,7 @@ class Select : ei_no_assignment_operator, public: typedef typename ThenMatrixType::template MakeBase< Select >::Type Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Select) + EIGEN_DENSE_PUBLIC_INTERFACE(Select) Select(const ConditionMatrixType& conditionMatrix, const ThenMatrixType& thenMatrix, diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index eef554d8a..697a07d32 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or @@ -80,7 +80,7 @@ class PartialReduxExpr : ei_no_assignment_operator, public: typedef typename MatrixType::template MakeBase< PartialReduxExpr >::Type Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(PartialReduxExpr) + EIGEN_DENSE_PUBLIC_INTERFACE(PartialReduxExpr) typedef typename ei_traits::MatrixTypeNested MatrixTypeNested; typedef typename ei_traits::_MatrixTypeNested _MatrixTypeNested; diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index fa63d27dc..3b4234c22 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -86,7 +86,7 @@ template >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(Block) + EIGEN_DENSE_PUBLIC_INTERFACE(Block) class InnerIterator; @@ -218,7 +218,7 @@ class Block public: typedef MapBase::Type> Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Block) + EIGEN_DENSE_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 990c553dd..9ed005dce 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -124,8 +124,11 @@ class CwiseBinaryOp : ei_no_assignment_operator, EIGEN_STRONG_INLINE int rows() const { return m_lhs.rows(); } EIGEN_STRONG_INLINE int cols() const { return m_lhs.cols(); } + /** \returns the left hand side nested expression */ const _LhsNested& lhs() const { return m_lhs; } + /** \returns the right hand side nested expression */ const _RhsNested& rhs() const { return m_rhs; } + /** \returns the functor representing the binary operation */ const BinaryOp& functor() const { return m_functor; } protected: @@ -138,11 +141,11 @@ template class CwiseBinaryOpImpl : public Lhs::template MakeBase< CwiseBinaryOp >::Type { + typedef CwiseBinaryOp Derived; public: - typedef CwiseBinaryOp Derived; typedef typename Lhs::template MakeBase< CwiseBinaryOp >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) + EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) EIGEN_STRONG_INLINE const Scalar coeff(int row, int col) const { diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index 129d558b4..c5d5cd97c 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -60,7 +60,7 @@ class CwiseNullaryOp : ei_no_assignment_operator, public: typedef typename MatrixType::template MakeBase< CwiseNullaryOp >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) + EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) CwiseNullaryOp(int rows, int cols, const NullaryOp& func = NullaryOp()) : m_rows(rows), m_cols(cols), m_functor(func) diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index 1abf0fffb..b51bd51af 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or @@ -74,16 +74,14 @@ class CwiseUnaryOp : ei_no_assignment_operator, EIGEN_STRONG_INLINE int rows() const { return m_matrix.rows(); } EIGEN_STRONG_INLINE int cols() const { return m_matrix.cols(); } - /** \internal used for introspection */ - const UnaryOp& _functor() const { return m_functor; } - - /** \internal used for introspection */ - const typename ei_cleantype::type& - _expression() const { return m_matrix; } + /** \returns the functor representing the unary operation */ + const UnaryOp& functor() const { return m_functor; } + /** \returns the nested expression */ const typename ei_cleantype::type& nestedExpression() const { return m_matrix; } + /** \returns the nested expression */ typename ei_cleantype::type& nestedExpression() { return m_matrix.const_cast_derived(); } @@ -98,37 +96,33 @@ template class CwiseUnaryOpImpl : public MatrixType::template MakeBase< CwiseUnaryOp >::Type { - const typename ei_cleantype::type& nestedExpression() const - { return derived().nestedExpression(); } - typename ei_cleantype::type& nestedExpression() - { return derived().nestedExpression(); } + typedef CwiseUnaryOp Derived; public: - typedef CwiseUnaryOp Derived; typedef typename MatrixType::template MakeBase< CwiseUnaryOp >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_STRONG_INLINE const Scalar coeff(int row, int col) const { - return derived()._functor()(nestedExpression().coeff(row, col)); + return derived().functor()(derived().nestedExpression().coeff(row, col)); } template EIGEN_STRONG_INLINE PacketScalar packet(int row, int col) const { - return derived()._functor().packetOp(nestedExpression().template packet(row, col)); + return derived().functor().packetOp(derived().nestedExpression().template packet(row, col)); } EIGEN_STRONG_INLINE const Scalar coeff(int index) const { - return derived()._functor()(nestedExpression().coeff(index)); + return derived().functor()(derived().nestedExpression().coeff(index)); } template EIGEN_STRONG_INLINE PacketScalar packet(int index) const { - return derived()._functor().packetOp(nestedExpression().template packet(index)); + return derived().functor().packetOp(derived().nestedExpression().template packet(index)); } }; diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 2ff5d3d45..2198ed226 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -72,12 +72,14 @@ class CwiseUnaryView : ei_no_assignment_operator, EIGEN_STRONG_INLINE int rows() const { return m_matrix.rows(); } EIGEN_STRONG_INLINE int cols() const { return m_matrix.cols(); } - /** \internal used for introspection */ - const ViewOp& _functor() const { return m_functor; } + /** \returns the functor representing unary operation */ + const ViewOp& functor() const { return m_functor; } + /** \returns the nested expression */ const typename ei_cleantype::type& nestedExpression() const { return m_matrix; } + /** \returns the nested expression */ typename ei_cleantype::type& nestedExpression() { return m_matrix.const_cast_derived(); } @@ -88,36 +90,34 @@ class CwiseUnaryView : ei_no_assignment_operator, }; template -class CwiseUnaryViewImpl : public MatrixBase > +class CwiseUnaryViewImpl + : public MatrixType::template MakeBase< CwiseUnaryView >::Type { - const typename ei_cleantype::type& nestedExpression() const - { return derived().nestedExpression(); } - typename ei_cleantype::type& nestedExpression() - { return derived().nestedExpression(); } + typedef CwiseUnaryView Derived; public: - typedef CwiseUnaryView Derived; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) + typedef typename MatrixType::template MakeBase< CwiseUnaryView >::Type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_STRONG_INLINE const Scalar coeff(int row, int col) const { - return derived()._functor()(nestedExpression().coeff(row, col)); + return derived().functor()(derived().nestedExpression().coeff(row, col)); } EIGEN_STRONG_INLINE const Scalar coeff(int index) const { - return derived()._functor()(nestedExpression().coeff(index)); + return derived().functor()(derived().nestedExpression().coeff(index)); } EIGEN_STRONG_INLINE Scalar& coeffRef(int row, int col) { - return derived()._functor()(nestedExpression().const_cast_derived().coeffRef(row, col)); + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); } EIGEN_STRONG_INLINE Scalar& coeffRef(int index) { - return derived()._functor()(nestedExpression().const_cast_derived().coeffRef(index)); + return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); } }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index e07b02a51..8ea0f3ddf 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 344dbca40..3720952cd 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -64,7 +64,7 @@ struct ei_traits > }; template class Diagonal - : public MatrixBase > + : public MatrixType::template MakeBase< Diagonal >::Type { // some compilers may fail to optimize std::max etc in case of compile-time constants... EIGEN_STRONG_INLINE int absIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } @@ -73,7 +73,8 @@ template class Diagonal public: - EIGEN_GENERIC_PUBLIC_INTERFACE(Diagonal) + typedef typename MatrixType::template MakeBase::Type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) inline Diagonal(const MatrixType& matrix, int index = Index) : m_matrix(matrix), m_index(index) {} diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index 87068d9ba..868b4419a 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -48,7 +48,8 @@ class DiagonalProduct : ei_no_assignment_operator, { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(DiagonalProduct) + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) : m_matrix(matrix), m_diagonal(diagonal) diff --git a/Eigen/src/Core/ForceAlignedAccess.h b/Eigen/src/Core/ForceAlignedAccess.h index b3fbb3c5c..927f43413 100644 --- a/Eigen/src/Core/ForceAlignedAccess.h +++ b/Eigen/src/Core/ForceAlignedAccess.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -41,11 +41,12 @@ struct ei_traits > : public ei_traits class ForceAlignedAccess - : public MatrixBase > + : public ExpressionType::template MakeBase< ForceAlignedAccess >::Type { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(ForceAlignedAccess) + typedef typename ExpressionType::template MakeBase >::Type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} diff --git a/Eigen/src/Core/Map.h b/Eigen/src/Core/Map.h index f3939c09f..83688dbca 100644 --- a/Eigen/src/Core/Map.h +++ b/Eigen/src/Core/Map.h @@ -64,7 +64,7 @@ template class Map public: typedef MapBase::Type> Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Map) + EIGEN_DENSE_PUBLIC_INTERFACE(Map) inline int stride() const { return this->innerSize(); } diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index f309f8abd..6f194ffba 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -134,10 +134,10 @@ class Matrix * \sa DenseStorageBase */ typedef DenseStorageBase, Eigen::MatrixBase, _Options> Base; - + enum { Options = _Options }; - _EIGEN_GENERIC_PUBLIC_INTERFACE(Matrix) + EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) typedef typename Base::PlainMatrixType PlainMatrixType; @@ -297,7 +297,7 @@ class Matrix } /** \brief Copy constructor for generic expressions. - * \sa MatrixBase::operator=(const AnyMatrixBase&) + * \sa MatrixBase::operator=(const AnyMatrixBase&) */ template EIGEN_STRONG_INLINE Matrix(const AnyMatrixBase &other) @@ -311,7 +311,7 @@ class Matrix } /** \internal - * \brief Override MatrixBase::swap() since for dynamic-sized matrices + * \brief Override MatrixBase::swap() since for dynamic-sized matrices * of same type it is enough to swap the data pointers. */ template diff --git a/Eigen/src/Core/Minor.h b/Eigen/src/Core/Minor.h index 629dbe609..e7e164a16 100644 --- a/Eigen/src/Core/Minor.h +++ b/Eigen/src/Core/Minor.h @@ -64,7 +64,8 @@ template class Minor { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(Minor) + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Minor) inline Minor(const MatrixType& matrix, int row, int col) diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h index 85a672779..d70ab1ecb 100644 --- a/Eigen/src/Core/NestByValue.h +++ b/Eigen/src/Core/NestByValue.h @@ -42,11 +42,12 @@ struct ei_traits > : public ei_traits class NestByValue - : public MatrixBase > + : public ExpressionType::template MakeBase< NestByValue >::Type { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(NestByValue) + typedef typename ExpressionType::template MakeBase >::Type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} @@ -97,7 +98,7 @@ template class NestByValue { m_expression.const_cast_derived().template writePacket(index, x); } - + operator const ExpressionType&() const { return m_expression; } protected: diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 1d19ef72a..44dd587d9 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -56,7 +56,7 @@ struct ei_nested, N, EvalType> #define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ typedef ProductBase Base; \ - _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ typedef typename Base::LhsNested LhsNested; \ typedef typename Base::_LhsNested _LhsNested; \ typedef typename Base::LhsBlasTraits LhsBlasTraits; \ @@ -75,7 +75,7 @@ class ProductBase : public MatrixBase { public: typedef MatrixBase Base; - _EIGEN_GENERIC_PUBLIC_INTERFACE(ProductBase) + EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) typedef typename Lhs::Nested LhsNested; typedef typename ei_cleantype::type _LhsNested; @@ -89,7 +89,6 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; - using Base::derived; typedef typename Base::PlainMatrixType PlainMatrixType; ProductBase(const Lhs& lhs, const Rhs& rhs) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index e35493236..0199d3740 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // // Eigen is free software; you can redistribute it and/or @@ -57,12 +57,14 @@ struct ei_nested, n, PlainMatrixType> typedef typename ei_traits::ReturnMatrixType type; }; -template - class ReturnByValue : public MatrixBase > +template class ReturnByValue + : public ei_traits::ReturnMatrixType::template MakeBase >::Type { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(ReturnByValue) typedef typename ei_traits::ReturnMatrixType ReturnMatrixType; + typedef typename ReturnMatrixType::template MakeBase >::Type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) + template inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index df35d0ee9..7ae2e82a4 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -47,7 +47,7 @@ template class SelfCwiseBinaryOp public: typedef typename MatrixType::template MakeBase< SelfCwiseBinaryOp >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp) + EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp) typedef typename ei_packet_traits::type Packet; diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 60b6fffc9..186268af0 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -40,7 +40,7 @@ template class SwapWrapper public: typedef typename ExpressionType::template MakeBase >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper) + EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper) typedef typename ei_packet_traits::type Packet; inline SwapWrapper(ExpressionType& xpr) : m_expression(xpr) {} diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 35b8b2ed3..1113792fd 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -71,13 +72,11 @@ template class Transpose inline int rows() const { return m_matrix.cols(); } inline int cols() const { return m_matrix.rows(); } - /** \internal used for introspection */ - const typename ei_cleantype::type& - _expression() const { return m_matrix; } - + /** \returns the nested expression */ const typename ei_cleantype::type& nestedExpression() const { return m_matrix; } + /** \returns the nested expression */ typename ei_cleantype::type& nestedExpression() { return m_matrix.const_cast_derived(); } @@ -89,65 +88,57 @@ template class Transpose template class TransposeImpl : public MatrixType::template MakeBase >::Type { - const typename ei_cleantype::type& nestedExpression() const - { return derived().nestedExpression(); } - typename ei_cleantype::type& nestedExpression() - { return derived().nestedExpression(); } - public: - //EIGEN_DENSE_PUBLpename IC_INTERFACE(TransposeImpl,MatrixBase >) typedef typename MatrixType::template MakeBase >::Type Base; - _EIGEN_DENSE_PUBLIC_INTERFACE(Transpose) + EIGEN_DENSE_PUBLIC_INTERFACE(Transpose) -// EIGEN_EXPRESSION_IMPL_COMMON(MatrixBase >) - - inline int stride() const { return nestedExpression().stride(); } - inline Scalar* data() { return nestedExpression().data(); } - inline const Scalar* data() const { return nestedExpression().data(); } + inline int stride() const { return derived().nestedExpression().stride(); } + inline Scalar* data() { return derived().nestedExpression().data(); } + inline const Scalar* data() const { return derived().nestedExpression().data(); } inline Scalar& coeffRef(int row, int col) { - return nestedExpression().const_cast_derived().coeffRef(col, row); + return const_cast_derived().nestedExpression().coeffRef(col, row); } inline Scalar& coeffRef(int index) { - return nestedExpression().const_cast_derived().coeffRef(index); + return const_cast_derived().nestedExpression().coeffRef(index); } inline const CoeffReturnType coeff(int row, int col) const { - return nestedExpression().coeff(col, row); + return derived().nestedExpression().coeff(col, row); } inline const CoeffReturnType coeff(int index) const { - return nestedExpression().coeff(index); + return derived().nestedExpression().coeff(index); } template inline const PacketScalar packet(int row, int col) const { - return nestedExpression().template packet(col, row); + return derived().nestedExpression().template packet(col, row); } template inline void writePacket(int row, int col, const PacketScalar& x) { - nestedExpression().const_cast_derived().template writePacket(col, row, x); + const_cast_derived().nestedExpression().template writePacket(col, row, x); } template inline const PacketScalar packet(int index) const { - return nestedExpression().template packet(index); + return derived().nestedExpression().template packet(index); } template inline void writePacket(int index, const PacketScalar& x) { - nestedExpression().const_cast_derived().template writePacket(index, x); + const_cast_derived().nestedExpression().template writePacket(index, x); } }; diff --git a/Eigen/src/Core/VectorBlock.h b/Eigen/src/Core/VectorBlock.h index 6dd8da938..cbf97aeb3 100644 --- a/Eigen/src/Core/VectorBlock.h +++ b/Eigen/src/Core/VectorBlock.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or @@ -75,7 +75,7 @@ template class VectorBlock IsColVector = ei_traits::ColsAtCompileTime==1 }; public: - _EIGEN_GENERIC_PUBLIC_INTERFACE(VectorBlock) + EIGEN_DENSE_PUBLIC_INTERFACE(VectorBlock) using Base::operator=; diff --git a/Eigen/src/Core/products/GeneralUnrolled.h b/Eigen/src/Core/products/GeneralUnrolled.h index f04c27a95..32aa3afe6 100644 --- a/Eigen/src/Core/products/GeneralUnrolled.h +++ b/Eigen/src/Core/products/GeneralUnrolled.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -104,7 +104,8 @@ template class GeneralProduct Base; + EIGEN_DENSE_PUBLIC_INTERFACE(GeneralProduct) private: diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h index 916a125e3..3777464dc 100644 --- a/Eigen/src/Core/util/BlasUtil.h +++ b/Eigen/src/Core/util/BlasUtil.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -185,8 +185,8 @@ struct ei_blas_traits, NestedXpr> > IsComplex = NumTraits::IsComplex, NeedToConjugate = Base::NeedToConjugate ? 0 : IsComplex }; - 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 ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline Scalar extractScalarFactor(const XprType& x) { return ei_conj(Base::extractScalarFactor(x.nestedExpression())); } }; // pop scalar multiple @@ -197,9 +197,9 @@ struct ei_blas_traits, NestedXpr> > typedef ei_blas_traits Base; typedef CwiseUnaryOp, NestedXpr> XprType; typedef typename Base::ExtractType ExtractType; - static inline ExtractType extract(const XprType& x) { return Base::extract(x._expression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) - { return x._functor().m_other * Base::extractScalarFactor(x._expression()); } + { return x.functor().m_other * Base::extractScalarFactor(x.nestedExpression()); } }; // pop opposite @@ -210,9 +210,9 @@ struct ei_blas_traits, NestedXpr> > typedef ei_blas_traits Base; typedef CwiseUnaryOp, NestedXpr> XprType; typedef typename Base::ExtractType ExtractType; - static inline ExtractType extract(const XprType& x) { return Base::extract(x._expression()); } + static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } static inline Scalar extractScalarFactor(const XprType& x) - { return - Base::extractScalarFactor(x._expression()); } + { return - Base::extractScalarFactor(x.nestedExpression()); } }; // pop/push transpose @@ -232,8 +232,8 @@ struct ei_blas_traits > enum { IsTransposed = Base::IsTransposed ? 0 : 1 }; - static inline const ExtractType extract(const XprType& x) { return Base::extract(x._expression()); } - static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x._expression()); } + static inline const ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x.nestedExpression()); } }; #endif // EIGEN_BLASUTIL_H diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 6e31f1580..dc1aa150b 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or @@ -281,50 +281,30 @@ using Eigen::ei_cos; * Just a side note. Commenting within defines works only by documenting * behind the object (via '!<'). Comments cannot be multi-line and thus * we have these extra long lines. What is confusing doxygen over here is -* that we use '\' and basically have a bunch of typedefs with their +* that we use '\' and basically have a bunch of typedefs with their * documentation in a single line. **/ -#define _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ +#define EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Derived) \ + typedef typename Eigen::ei_traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ + typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ + typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ + typedef typename Eigen::ei_nested::type Nested; \ + enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ + Flags = Eigen::ei_traits::Flags, \ + CoeffReadCost = Eigen::ei_traits::CoeffReadCost, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; + + +#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ typedef typename Eigen::ei_traits::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex. */ \ typedef typename Eigen::NumTraits::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex, T were corresponding to RealScalar. */ \ typedef typename Base::PacketScalar PacketScalar; \ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ typedef typename Eigen::ei_nested::type Nested; \ - enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ - MaxRowsAtCompileTime = Eigen::ei_traits::MaxRowsAtCompileTime, \ - MaxColsAtCompileTime = Eigen::ei_traits::MaxColsAtCompileTime, \ - Flags = Eigen::ei_traits::Flags, \ - CoeffReadCost = Eigen::ei_traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - -#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ - typedef Eigen::MatrixBase Base; \ - _EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) - -#define EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Derived) \ - typedef typename Eigen::ei_traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Base::CoeffReturnType CoeffReturnType; \ - typedef typename Eigen::ei_nested::type Nested; \ - enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ - Flags = Eigen::ei_traits::Flags, \ - CoeffReadCost = Eigen::ei_traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - - -#define _EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Eigen::ei_traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Base::PacketScalar PacketScalar; \ - typedef typename Base::CoeffReturnType CoeffReturnType; \ - typedef typename Eigen::ei_nested::type Nested; \ enum { RowsAtCompileTime = Eigen::ei_traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits::ColsAtCompileTime, \ MaxRowsAtCompileTime = Eigen::ei_traits::MaxRowsAtCompileTime, \ @@ -334,11 +314,8 @@ using Eigen::ei_cos; SizeAtCompileTime = Base::SizeAtCompileTime, \ MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; - -#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef Eigen::MatrixBase Base; \ - _EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + using Base::derived; \ + using Base::const_cast_derived; #define EIGEN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b) diff --git a/Eigen/src/Eigen2Support/Flagged.h b/Eigen/src/Eigen2Support/Flagged.h index bed110b64..470db1d7b 100644 --- a/Eigen/src/Eigen2Support/Flagged.h +++ b/Eigen/src/Eigen2Support/Flagged.h @@ -52,7 +52,8 @@ template clas { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(Flagged) + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) typedef typename ei_meta_if::ret, ExpressionType, const ExpressionType&>::ret ExpressionTypeNested; typedef typename ExpressionType::InnerIterator InnerIterator; diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index b0232e77c..76ca66c57 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -70,7 +70,8 @@ template class Homogeneous enum { Direction = _Direction }; - EIGEN_GENERIC_PUBLIC_INTERFACE(Homogeneous) + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Homogeneous) inline Homogeneous(const MatrixType& matrix) : m_matrix(matrix) diff --git a/Eigen/src/Sparse/SparseBlock.h b/Eigen/src/Sparse/SparseBlock.h index a8c1f9047..2e16856eb 100644 --- a/Eigen/src/Sparse/SparseBlock.h +++ b/Eigen/src/Sparse/SparseBlock.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Daniel Gomez Ferro +// Copyright (C) 2008-2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -406,98 +405,4 @@ template const SparseInnerVectorSet SparseMatrixBase::innerVectors(int outerStart, int outerSize) const { return SparseInnerVectorSet(derived(), outerStart, outerSize); } -# if 0 -template -class Block - : public SparseMatrixBase > -{ -public: - - _EIGEN_GENERIC_PUBLIC_INTERFACE(Block, SparseMatrixBase) - class InnerIterator; - - /** Column or Row constructor - */ - inline Block(const MatrixType& matrix, int i) - : m_matrix(matrix), - // It is a row if and only if BlockRows==1 and BlockCols==MatrixType::ColsAtCompileTime, - // and it is a column if and only if BlockRows==MatrixType::RowsAtCompileTime and BlockCols==1, - // all other cases are invalid. - // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. - m_startRow( (BlockRows==1) && (BlockCols==MatrixType::ColsAtCompileTime) ? i : 0), - m_startCol( (BlockRows==MatrixType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(matrix.rows()), // if it is a row, then m_blockRows has a fixed-size of 1, so no pb to try to overwrite it - m_blockCols(matrix.cols()) // same for m_blockCols - { - ei_assert( (i>=0) && ( - ((BlockRows==1) && (BlockCols==MatrixType::ColsAtCompileTime) && i= 0 && BlockRows >= 1 && startRow + BlockRows <= matrix.rows() - && startCol >= 0 && BlockCols >= 1 && startCol + BlockCols <= matrix.cols()); - } - - /** Dynamic-size constructor - */ - inline Block(const MatrixType& matrix, - int startRow, int startCol, - int blockRows, int blockCols) - : m_matrix(matrix), m_startRow(startRow), m_startCol(startCol), - m_blockRows(blockRows), m_blockCols(blockCols) - { - ei_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) - && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); - ei_assert(startRow >= 0 && blockRows >= 1 && startRow + blockRows <= matrix.rows() - && startCol >= 0 && blockCols >= 1 && startCol + blockCols <= matrix.cols()); - } - - inline int rows() const { return m_blockRows.value(); } - inline int cols() const { return m_blockCols.value(); } - - inline int stride(void) const { return m_matrix.stride(); } - - inline Scalar& coeffRef(int row, int col) - { - return m_matrix.const_cast_derived() - .coeffRef(row + m_startRow.value(), col + m_startCol.value()); - } - - inline const Scalar coeff(int row, int col) const - { - return m_matrix.coeff(row + m_startRow.value(), col + m_startCol.value()); - } - - inline Scalar& coeffRef(int index) - { - return m_matrix.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const Scalar coeff(int index) const - { - return m_matrix - .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - protected: - - const typename MatrixType::Nested m_matrix; - const ei_int_if_dynamic m_startRow; - const ei_int_if_dynamic m_startCol; - const ei_int_if_dynamic m_blockRows; - const ei_int_if_dynamic m_blockCols; - -}; -#endif - #endif // EIGEN_SPARSE_BLOCK_H diff --git a/Eigen/src/Sparse/SparseCwiseUnaryOp.h b/Eigen/src/Sparse/SparseCwiseUnaryOp.h index eb2c99375..1d1e22c5c 100644 --- a/Eigen/src/Sparse/SparseCwiseUnaryOp.h +++ b/Eigen/src/Sparse/SparseCwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -60,7 +60,7 @@ class CwiseUnaryOpImpl::InnerIterator public: EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, int outer) - : m_iter(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived()._functor()) + : m_iter(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) {} EIGEN_STRONG_INLINE InnerIterator& operator++() @@ -101,7 +101,7 @@ class CwiseUnaryViewImpl::InnerIterator public: EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryView, int outer) - : m_iter(unaryView.derived().nestedExpression(),outer), m_functor(unaryView.derived()._functor()) + : m_iter(unaryView.derived().nestedExpression(),outer), m_functor(unaryView.derived().functor()) {} EIGEN_STRONG_INLINE InnerIterator& operator++() diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index 7aa81312e..a56bc7601 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2010 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -93,7 +93,8 @@ class SparseProduct : ei_no_assignment_operator, { public: - EIGEN_GENERIC_PUBLIC_INTERFACE(SparseProduct) + typedef typename ei_traits >::Base Base; + EIGEN_DENSE_PUBLIC_INTERFACE(SparseProduct) private: From be11a254acda119dc65b5f5af2a94275fa7caa81 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 22 Jan 2010 10:17:43 +0100 Subject: [PATCH 002/109] rm ExpressionMaker stuff (weird as I was pretty sure that I had already removed them) --- Eigen/src/Core/ExpressionMaker.h | 55 ------------------------ Eigen/src/Sparse/SparseExpressionMaker.h | 42 ------------------ 2 files changed, 97 deletions(-) delete mode 100644 Eigen/src/Core/ExpressionMaker.h delete mode 100644 Eigen/src/Sparse/SparseExpressionMaker.h diff --git a/Eigen/src/Core/ExpressionMaker.h b/Eigen/src/Core/ExpressionMaker.h deleted file mode 100644 index 7e2b81d4a..000000000 --- a/Eigen/src/Core/ExpressionMaker.h +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_EXPRESSIONMAKER_H -#define EIGEN_EXPRESSIONMAKER_H - -// computes the shape of a matrix from its traits flag -template struct ei_shape_of -{ - enum { ret = ei_traits::Flags&SparseBit ? IsSparse : IsDense }; -}; - - -// Since the Sparse module is completely separated from the Core module, there is -// no way to write the type of a generic expression working for both dense and sparse -// matrix. Unless we change the overall design, here is a workaround. -// There is an example in unsuported/Eigen/src/AutoDiff/AutoDiffScalar. - -template::ret> -struct MakeCwiseUnaryOp -{ - typedef CwiseUnaryOp Type; -}; - -template::ret> -struct MakeCwiseBinaryOp -{ - typedef CwiseBinaryOp Type; -}; - -// TODO complete the list - - -#endif // EIGEN_EXPRESSIONMAKER_H diff --git a/Eigen/src/Sparse/SparseExpressionMaker.h b/Eigen/src/Sparse/SparseExpressionMaker.h deleted file mode 100644 index 8e31d55ef..000000000 --- a/Eigen/src/Sparse/SparseExpressionMaker.h +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - -#ifndef EIGEN_SPARSE_EXPRESSIONMAKER_H -#define EIGEN_SPARSE_EXPRESSIONMAKER_H - -template -struct MakeCwiseUnaryOp -{ - typedef SparseCwiseUnaryOp Type; -}; - -template -struct MakeCwiseBinaryOp -{ - typedef SparseCwiseBinaryOp Type; -}; - -// TODO complete the list - -#endif // EIGEN_SPARSE_EXPRESSIONMAKER_H From d08035f3e125d2d21cf7f254572e8fc1fd7889a8 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Fri, 22 Jan 2010 19:26:29 +0100 Subject: [PATCH 003/109] fix the script again (definitely?) + cleaning --- scripts/eigen_gen_docs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/eigen_gen_docs b/scripts/eigen_gen_docs index f6727eff1..4c9214e51 100644 --- a/scripts/eigen_gen_docs +++ b/scripts/eigen_gen_docs @@ -8,16 +8,12 @@ USER=${USER:-'orzel'} # step 1 : build # todo if 'build is not there, create one: #mkdir build -(cd build && cmake .. && make -j3 doc) || echo "make failed"; exit 1 +(cd build && cmake .. && make -j3 doc) || { echo "make failed"; exit 1; } #todo: n+1 where n = number of cpus #step 2 : 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) +rsync -az build/doc/html/ $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/dox-devel/ || { echo "upload failed"; exit 1; } +echo "Uploaded successfully" From 858539a6af404d4e46a1524c356c985d14b8d169 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sun, 24 Jan 2010 22:56:28 +0000 Subject: [PATCH 004/109] Use matrices with clustered eigenvalues in matrix function test. This is in order to get better code coverage. Test matrix_function_3 now fails regularly because ComplexSchur reaches the max number of iterations; further study needed. --- unsupported/test/matrix_function.cpp | 49 ++++++++++++++++++---------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index 0eb30eecb..3e25c6a6f 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -25,18 +25,37 @@ #include "main.h" #include +// Returns either a matrix with iid random entries or a matrix with +// clustered eigenvalues. Matrices with clustered eigenvalue clusters +// lead to different code paths in MatrixFunction.h and are thus +// useful for testing. template -void testMatrixExponential(const MatrixType& m) +MatrixType createRandomMatrix(const int size) +{ + typedef typename MatrixType::Scalar Scalar; + MatrixType result; + if (ei_random(0,1) == 0) { + result = MatrixType::Random(size, size); + } else { + MatrixType diag = MatrixType::Zero(size, size); + for (int i = 0; i < size; ++i) { + diag(i, i) = static_cast(ei_random(0,2)) + + ei_random() * static_cast(0.01); + } + MatrixType A = MatrixType::Random(size, size); + result = A.inverse() * diag * A; + } + return result; +} + +template +void testMatrixExponential(const MatrixType& A) { typedef typename ei_traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef std::complex ComplexScalar; - const int rows = m.rows(); - const int cols = m.cols(); - for (int i = 0; i < g_repeat; i++) { - MatrixType A = MatrixType::Random(rows, cols); MatrixType expA1, expA2; ei_matrix_exponential(A, &expA1); ei_matrix_function(A, StdStemFunctions::exp, &expA2); @@ -45,13 +64,9 @@ void testMatrixExponential(const MatrixType& m) } template -void testHyperbolicFunctions(const MatrixType& m) +void testHyperbolicFunctions(const MatrixType& A) { - const int rows = m.rows(); - const int cols = m.cols(); - for (int i = 0; i < g_repeat; i++) { - MatrixType A = MatrixType::Random(rows, cols); MatrixType sinhA, coshA, expA; ei_matrix_sinh(A, &sinhA); ei_matrix_cosh(A, &coshA); @@ -62,7 +77,7 @@ void testHyperbolicFunctions(const MatrixType& m) } template -void testGonioFunctions(const MatrixType& m) +void testGonioFunctions(const MatrixType& A) { typedef ei_traits Traits; typedef typename Traits::Scalar Scalar; @@ -71,13 +86,10 @@ void testGonioFunctions(const MatrixType& m) typedef Matrix ComplexMatrix; - const int rows = m.rows(); - const int cols = m.cols(); ComplexScalar imagUnit(0,1); ComplexScalar two(2,0); for (int i = 0; i < g_repeat; i++) { - MatrixType A = MatrixType::Random(rows, cols); ComplexMatrix Ac = A.template cast(); ComplexMatrix exp_iA; @@ -98,9 +110,12 @@ void testGonioFunctions(const MatrixType& m) template void testMatrixType(const MatrixType& m) { - testMatrixExponential(m); - testHyperbolicFunctions(m); - testGonioFunctions(m); + for (int i = 0; i < g_repeat; i++) { + MatrixType A = createRandomMatrix(m.rows()); + testMatrixExponential(A); + testHyperbolicFunctions(A); + testGonioFunctions(A); + } } void test_matrix_function() From 6ae7d842a31e1e1937f88a1acf513c7bf51aee9c Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 24 Jan 2010 21:44:18 -0500 Subject: [PATCH 005/109] generate a compilation error when using ReturnByValue::coeff() or coeffRef(), instead of doing an infinite recursion --- Eigen/src/Core/ReturnByValue.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 0199d3740..920269365 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -70,6 +70,18 @@ template class ReturnByValue { static_cast(this)->evalTo(dst); } inline int rows() const { return static_cast(this)->rows(); } inline int cols() const { return static_cast(this)->cols(); } + +#ifndef EIGEN_PARSED_BY_DOXYGEN +#define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT + class Unusable{ + Unusable(const Unusable&) {} + Unusable& operator=(const Unusable&) {return *this;} + }; + const Unusable& coeff(int) const { return *reinterpret_cast(this); } + const Unusable& coeff(int,int) const { return *reinterpret_cast(this); } + Unusable& coeffRef(int) { return *reinterpret_cast(this); } + Unusable& coeffRef(int,int) { return *reinterpret_cast(this); } +#endif }; template From cbf6022e5ad2ce22e5d925a186391a9d5745ef47 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 25 Jan 2010 07:07:31 +0100 Subject: [PATCH 006/109] useless cleaning --- .../Eigen/src/NonLinearOptimization/dogleg.h | 2 - .../Eigen/src/NonLinearOptimization/fdjac1.h | 8 ++- .../Eigen/src/NonLinearOptimization/qform.h | 47 ++++------------ .../Eigen/src/NonLinearOptimization/qrfac.h | 54 +++++-------------- 4 files changed, 26 insertions(+), 85 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index dd6b39cb4..cf488b0bf 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -118,7 +118,5 @@ algo_end: temp = (1.-alpha) * std::min(sgnorm,delta); x = temp * wa1 + alpha * x; - return; - } diff --git a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h index 376df7c40..e9c8fa991 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h +++ b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h @@ -22,7 +22,7 @@ int ei_fdjac1( Matrix< Scalar, Dynamic, 1 > wa1(n); Matrix< Scalar, Dynamic, 1 > wa2(n); - eps = ei_sqrt((std::max(epsfcn,epsmch))); + eps = ei_sqrt(std::max(epsfcn,epsmch)); msum = ml + mu + 1; if (msum >= n) { /* computation of dense approximate jacobian. */ @@ -49,18 +49,16 @@ int ei_fdjac1( x[j] = wa2[j] + h; } iflag = Functor(x, wa1); - if (iflag < 0) { + if (iflag < 0) return iflag; - } for (j = k; msum< 0 ? j > n: j < n; j += msum) { x[j] = wa2[j]; h = eps * ei_abs(wa2[j]); if (h == 0.) h = eps; for (i = 0; i < n; ++i) { fjac(i,j) = 0.; - if (i >= j - mu && i <= j + ml) { + if (i >= j - mu && i <= j + ml) fjac(i,j) = (wa1[i] - fvec[i]) / h; - } } } } diff --git a/unsupported/Eigen/src/NonLinearOptimization/qform.h b/unsupported/Eigen/src/NonLinearOptimization/qform.h index 47bbd1fbe..1c3e3e267 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qform.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qform.h @@ -7,7 +7,7 @@ void ei_qform(int m, int n, Scalar *q, int int q_dim1, q_offset; /* Local variables */ - int i, j, k, l, jm1, np1; + int i, j, k, l; Scalar sum, temp; int minmn; @@ -22,34 +22,18 @@ void ei_qform(int m, int n, Scalar *q, int /* zero out upper triangle of q in the first min(m,n) columns. */ minmn = std::min(m,n); - if (minmn < 2) { - goto L30; - } for (j = 2; j <= minmn; ++j) { - jm1 = j - 1; - for (i = 1; i <= jm1; ++i) { + for (i = 1; i <= j-1; ++i) q[i + j * q_dim1] = 0.; - /* L10: */ - } - /* L20: */ } -L30: /* initialize remaining columns to those of the identity matrix. */ - np1 = n + 1; - if (m < np1) { - goto L60; - } - for (j = np1; j <= m; ++j) { - for (i = 1; i <= m; ++i) { + for (j = n+1; j <= m; ++j) { + for (i = 1; i <= m; ++i) q[i + j * q_dim1] = 0.; - /* L40: */ - } q[j + j * q_dim1] = 1.; - /* L50: */ } -L60: /* accumulate q from its factored form. */ @@ -58,32 +42,19 @@ L60: for (i = k; i <= m; ++i) { wa[i] = q[i + k * q_dim1]; q[i + k * q_dim1] = 0.; - /* L70: */ } q[k + k * q_dim1] = 1.; - if (wa[k] == 0.) { - goto L110; - } + if (wa[k] == 0.) + continue; for (j = k; j <= m; ++j) { sum = 0.; - for (i = k; i <= m; ++i) { + for (i = k; i <= m; ++i) sum += q[i + j * q_dim1] * wa[i]; - /* L80: */ - } temp = sum / wa[k]; - for (i = k; i <= m; ++i) { + for (i = k; i <= m; ++i) q[i + j * q_dim1] -= temp * wa[i]; - /* L90: */ - } - /* L100: */ } -L110: - /* L120: */ - ; } - return; - /* last card of subroutine qform. */ - -} /* qform_ */ +} diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrfac.h b/unsupported/Eigen/src/NonLinearOptimization/qrfac.h index 0c1ecf394..ff297293d 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrfac.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrfac.h @@ -39,22 +39,17 @@ void ei_qrfac(int m, int n, Scalar *a, int minmn = std::min(m,n); for (j = 1; j <= minmn; ++j) { - if (! (pivot)) { + if (! (pivot)) goto L40; - } /* bring the column of largest norm into the pivot position. */ kmax = j; - for (k = j; k <= n; ++k) { - if (rdiag[k] > rdiag[kmax]) { + for (k = j; k <= n; ++k) + if (rdiag[k] > rdiag[kmax]) kmax = k; - } - /* L20: */ - } - if (kmax == j) { + if (kmax == j) goto L40; - } for (i = 1; i <= m; ++i) { temp = a[i + j * a_dim1]; a[i + j * a_dim1] = a[i + kmax * a_dim1]; @@ -72,60 +67,39 @@ L40: /* j-th column of a to a multiple of the j-th unit vector. */ ajnorm = Map< Matrix< Scalar, Dynamic, 1 > >(&a[j + j * a_dim1],m-j+1).blueNorm(); - if (ajnorm == 0.) { + if (ajnorm == 0.) goto L100; - } - if (a[j + j * a_dim1] < 0.) { + if (a[j + j * a_dim1] < 0.) ajnorm = -ajnorm; - } - for (i = j; i <= m; ++i) { + for (i = j; i <= m; ++i) a[i + j * a_dim1] /= ajnorm; - /* L50: */ - } a[j + j * a_dim1] += 1.; /* apply the transformation to the remaining columns */ /* and update the norms. */ jp1 = j + 1; - if (n < jp1) { - goto L100; - } for (k = jp1; k <= n; ++k) { sum = 0.; - for (i = j; i <= m; ++i) { + for (i = j; i <= m; ++i) sum += a[i + j * a_dim1] * a[i + k * a_dim1]; - /* L60: */ - } temp = sum / a[j + j * a_dim1]; - for (i = j; i <= m; ++i) { + for (i = j; i <= m; ++i) a[i + k * a_dim1] -= temp * a[i + j * a_dim1]; - /* L70: */ - } - if (! (pivot) || rdiag[k] == 0.) { - goto L80; - } + if (! (pivot) || rdiag[k] == 0.) + continue; temp = a[j + k * a_dim1] / rdiag[k]; /* Computing MAX */ /* Computing 2nd power */ rdiag[k] *= ei_sqrt((std::max(Scalar(0.), Scalar(1.)-ei_abs2(temp)))); /* Computing 2nd power */ - if (Scalar(.05) * ei_abs2(rdiag[k] / wa[k]) > epsmch) { - goto L80; - } + if (Scalar(.05) * ei_abs2(rdiag[k] / wa[k]) > epsmch) + continue; rdiag[k] = Map< Matrix< Scalar, Dynamic, 1 > >(&a[jp1 + k * a_dim1],m-j).blueNorm(); wa[k] = rdiag[k]; -L80: - /* L90: */ - ; } L100: rdiag[j] = -ajnorm; - /* L110: */ } - return; - - /* last card of subroutine qrfac. */ - -} /* qrfac_ */ +} From 1cb0be05b0f287172dbbfb14a576d89600ffbebe Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 25 Jan 2010 07:08:08 +0100 Subject: [PATCH 007/109] useful cleaning --- unsupported/Eigen/src/NonLinearOptimization/lmpar.h | 3 +-- unsupported/Eigen/src/NonLinearOptimization/qrsolv.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index ab8549f1a..65e9d799e 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -2,7 +2,7 @@ template void ei_lmpar( Matrix< Scalar, Dynamic, Dynamic > &r, - VectorXi &ipvt, // TODO : const once ipvt mess fixed + const VectorXi &ipvt, const Matrix< Scalar, Dynamic, 1 > &diag, const Matrix< Scalar, Dynamic, 1 > &qtb, Scalar delta, @@ -166,4 +166,3 @@ void ei_lmpar( par = 0.; return; } - diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h index 1ee21d5ed..6ffba42c5 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h @@ -2,7 +2,7 @@ template void ei_qrsolv( Matrix< Scalar, Dynamic, Dynamic > &r, - VectorXi &ipvt, // TODO : const once ipvt mess fixed + const VectorXi &ipvt, const Matrix< Scalar, Dynamic, 1 > &diag, const Matrix< Scalar, Dynamic, 1 > &qtb, Matrix< Scalar, Dynamic, 1 > &x, From ee0e39284c8ddd94ae82604e8bb51a846e3dc644 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 25 Jan 2010 07:22:28 +0100 Subject: [PATCH 008/109] Replace the qr factorization from (c)minpack (qrfac) by Eigen's own stuff. Results as checked by unit tests are very slightly worse, but not much. --- unsupported/Eigen/NonLinearOptimization | 1 - .../HybridNonLinearSolver.h | 30 ++++- .../LevenbergMarquardt.h | 27 ++++- .../Eigen/src/NonLinearOptimization/qrfac.h | 105 ------------------ unsupported/test/NonLinearOptimization.cpp | 42 +++---- 5 files changed, 71 insertions(+), 134 deletions(-) delete mode 100644 unsupported/Eigen/src/NonLinearOptimization/qrfac.h diff --git a/unsupported/Eigen/NonLinearOptimization b/unsupported/Eigen/NonLinearOptimization index f15e09386..a239018b0 100644 --- a/unsupported/Eigen/NonLinearOptimization +++ b/unsupported/Eigen/NonLinearOptimization @@ -129,7 +129,6 @@ namespace Eigen { #include "src/NonLinearOptimization/r1updt.h" #include "src/NonLinearOptimization/r1mpyq.h" #include "src/NonLinearOptimization/rwupdt.h" -#include "src/NonLinearOptimization/qrfac.h" #include "src/NonLinearOptimization/fdjac1.h" #include "src/NonLinearOptimization/qform.h" #include "src/NonLinearOptimization/lmpar.h" diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 3bf3d12ea..91efdac68 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -218,7 +218,7 @@ HybridNonLinearSolver::solveOneStep( const int mode ) { - int i, j, l, iwa[1]; + int i, j, l; jeval = true; /* calculate the jacobian matrix. */ @@ -249,7 +249,13 @@ HybridNonLinearSolver::solveOneStep( } /* compute the qr factorization of the jacobian. */ - ei_qrfac(n, n, fjac.data(), fjac.rows(), false, iwa, wa1.data()); + wa2 = fjac.colwise().blueNorm(); + HouseholderQR qrfac(fjac); // no pivoting: + fjac = qrfac.matrixQR(); + wa1 = fjac.diagonal(); + fjac.diagonal() = qrfac.hCoeffs(); + // TODO : avoid this: + for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors /* form (q transpose)*fvec and store in qtf. */ @@ -280,6 +286,11 @@ HybridNonLinearSolver::solveOneStep( /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); +#if 0 + std::cout << "ei_qform: " << fjac << std::endl; + fjac = qrfac.matrixQ(); + std::cout << "qrfac.matrixQ():" << fjac << std::endl; +#endif /* rescale if necessary. */ @@ -530,7 +541,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( const int mode ) { - int i, j, l, iwa[1]; + int i, j, l; jeval = true; if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1; if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1; @@ -563,7 +574,13 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( } /* compute the qr factorization of the jacobian. */ - ei_qrfac(n, n, fjac.data(), fjac.rows(), false, iwa, wa1.data()); + wa2 = fjac.colwise().blueNorm(); + HouseholderQR qrfac(fjac); // no pivoting: + fjac = qrfac.matrixQR(); + wa1 = fjac.diagonal(); + fjac.diagonal() = qrfac.hCoeffs(); + // TODO : avoid this: + for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors /* form (q transpose)*fvec and store in qtf. */ @@ -594,6 +611,11 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); +#if 0 + std::cout << "ei_qform: " << fjac << std::endl; + fjac = qrfac.matrixQ(); + std::cout << "qrfac.matrixQ():" << fjac << std::endl; +#endif /* rescale if necessary. */ diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 8df48d2ab..9f3707952 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -254,8 +254,13 @@ LevenbergMarquardt::minimizeOneStep( /* compute the qr factorization of the jacobian. */ wa2 = fjac.colwise().blueNorm(); - ei_qrfac(m, n, fjac.data(), fjac.rows(), true, ipvt.data(), wa1.data()); - ipvt.array() -= 1; // qrfac() creates ipvt with fortran convention (1->n), convert it to c (0->n-1) + ColPivHouseholderQR qrfac(fjac); + fjac = qrfac.matrixQR(); + wa1 = fjac.diagonal(); + fjac.diagonal() = qrfac.hCoeffs(); + ipvt = qrfac.colsPermutation().indices(); + // TODO : avoid this: + for(int i=0; i< fjac.cols(); i++) fjac.col(i).segment(i+1, fjac.rows()-i-1) *= fjac(i,i); // rescale vectors /* on the first iteration and if mode is 1, scale according */ /* to the norms of the columns of the initial jacobian. */ @@ -295,6 +300,12 @@ LevenbergMarquardt::minimizeOneStep( qtf[j] = wa4[j]; } +#if 0 + std::cout << "qtf: " << qtf << std::endl; + FVectorType monqtf = qrfac.matrixQ().transpose() * fvec; + std::cout << "mon qtf :" << monqtf << std::endl; +#endif + /* compute the norm of the scaled gradient. */ gnorm = 0.; @@ -540,10 +551,16 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( wa2[j] = fjac.col(j).head(j).stableNorm(); } if (sing) { - ipvt.array() += 1; wa2 = fjac.colwise().blueNorm(); - ei_qrfac(n, n, fjac.data(), fjac.rows(), true, ipvt.data(), wa1.data()); - ipvt.array() -= 1; // qrfac() creates ipvt with fortran convention (1->n), convert it to c (0->n-1) + // TODO We have no unit test covering this branch.. untested + ColPivHouseholderQR qrfac(fjac); + fjac = qrfac.matrixQR(); + wa1 = fjac.diagonal(); + fjac.diagonal() = qrfac.hCoeffs(); + ipvt = qrfac.colsPermutation().indices(); + // TODO : avoid this: + for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors + for (j = 0; j < n; ++j) { if (fjac(j,j) != 0.) { sum = 0.; diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrfac.h b/unsupported/Eigen/src/NonLinearOptimization/qrfac.h deleted file mode 100644 index ff297293d..000000000 --- a/unsupported/Eigen/src/NonLinearOptimization/qrfac.h +++ /dev/null @@ -1,105 +0,0 @@ - -template -void ei_qrfac(int m, int n, Scalar *a, int - lda, int pivot, int *ipvt, Scalar *rdiag) -{ - /* System generated locals */ - int a_dim1, a_offset; - - /* Local variables */ - int i, j, k, jp1; - Scalar sum; - int kmax; - Scalar temp; - int minmn; - Scalar ajnorm; - - Matrix< Scalar, Dynamic, 1 > wa(n+1); - - /* Parameter adjustments */ - --rdiag; - a_dim1 = lda; - a_offset = 1 + a_dim1 * 1; - a -= a_offset; - --ipvt; - - /* Function Body */ - const Scalar epsmch = epsilon(); - - /* compute the initial column norms and initialize several arrays. */ - - for (j = 1; j <= n; ++j) { - rdiag[j] = Map< Matrix< Scalar, Dynamic, 1 > >(&a[j * a_dim1 + 1],m).blueNorm(); - wa[j] = rdiag[j]; - if (pivot) - ipvt[j] = j; - } - - /* reduce a to r with householder transformations. */ - - minmn = std::min(m,n); - for (j = 1; j <= minmn; ++j) { - if (! (pivot)) - goto L40; - - /* bring the column of largest norm into the pivot position. */ - - kmax = j; - for (k = j; k <= n; ++k) - if (rdiag[k] > rdiag[kmax]) - kmax = k; - if (kmax == j) - goto L40; - for (i = 1; i <= m; ++i) { - temp = a[i + j * a_dim1]; - a[i + j * a_dim1] = a[i + kmax * a_dim1]; - a[i + kmax * a_dim1] = temp; - /* L30: */ - } - rdiag[kmax] = rdiag[j]; - wa[kmax] = wa[j]; - k = ipvt[j]; - ipvt[j] = ipvt[kmax]; - ipvt[kmax] = k; -L40: - - /* compute the householder transformation to reduce the */ - /* j-th column of a to a multiple of the j-th unit vector. */ - - ajnorm = Map< Matrix< Scalar, Dynamic, 1 > >(&a[j + j * a_dim1],m-j+1).blueNorm(); - if (ajnorm == 0.) - goto L100; - if (a[j + j * a_dim1] < 0.) - ajnorm = -ajnorm; - for (i = j; i <= m; ++i) - a[i + j * a_dim1] /= ajnorm; - a[j + j * a_dim1] += 1.; - - /* apply the transformation to the remaining columns */ - /* and update the norms. */ - - jp1 = j + 1; - for (k = jp1; k <= n; ++k) { - sum = 0.; - for (i = j; i <= m; ++i) - sum += a[i + j * a_dim1] * a[i + k * a_dim1]; - temp = sum / a[j + j * a_dim1]; - for (i = j; i <= m; ++i) - a[i + k * a_dim1] -= temp * a[i + j * a_dim1]; - if (! (pivot) || rdiag[k] == 0.) - continue; - temp = a[j + k * a_dim1] / rdiag[k]; - /* Computing MAX */ - /* Computing 2nd power */ - rdiag[k] *= ei_sqrt((std::max(Scalar(0.), Scalar(1.)-ei_abs2(temp)))); - /* Computing 2nd power */ - if (Scalar(.05) * ei_abs2(rdiag[k] / wa[k]) > epsmch) - continue; - rdiag[k] = Map< Matrix< Scalar, Dynamic, 1 > >(&a[jp1 + k * a_dim1],m-j).blueNorm(); - wa[k] = rdiag[k]; - } -L100: - rdiag[j] = -ajnorm; - } -} - diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index ae587f016..baca18052 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -1010,7 +1010,7 @@ void testNistLanczos1(void) VERIFY( 79 == lm.nfev); VERIFY( 72 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.429604433690E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428127827535E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1031,7 +1031,7 @@ void testNistLanczos1(void) VERIFY( 9 == lm.nfev); VERIFY( 8 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.43049947737308E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.43059335827267E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1170,9 +1170,9 @@ void testNistMGH10(void) info = lm.minimize(x); // check return value - VERIFY( 2 == info); - VERIFY( 285 == lm.nfev); - VERIFY( 250 == lm.njev); + VERIFY( 3 == info); + VERIFY( 281 == lm.nfev); + VERIFY( 248 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01); // check x @@ -1269,9 +1269,9 @@ void testNistBoxBOD(void) info = lm.minimize(x); // check return value - VERIFY( 1 == info); - VERIFY( 15 == lm.nfev); - VERIFY( 14 == lm.njev); + VERIFY( 1 == info); + VERIFY( 17 == lm.nfev); + VERIFY( 14 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03); // check x @@ -1331,9 +1331,9 @@ void testNistMGH17(void) info = lm.minimize(x); // check return value - VERIFY( 1 == info); - VERIFY( 599 == lm.nfev); - VERIFY( 544 == lm.njev); + VERIFY( 2 == info); + VERIFY( 603 == lm.nfev); + VERIFY( 544 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); // check x @@ -1418,16 +1418,16 @@ void testNistMGH09(void) info = lm.minimize(x); // check return value - VERIFY( 1 == info); - VERIFY( 503== lm.nfev); - VERIFY( 385 == lm.njev); + VERIFY( 1 == info); + VERIFY( 494== lm.nfev); + VERIFY( 382 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04); // check x - VERIFY_IS_APPROX(x[0], 0.19280624); // should be 1.9280693458E-01 - VERIFY_IS_APPROX(x[1], 0.19129774); // should be 1.9128232873E-01 - VERIFY_IS_APPROX(x[2], 0.12305940); // should be 1.2305650693E-01 - VERIFY_IS_APPROX(x[3], 0.13606946); // should be 1.3606233068E-01 + VERIFY_IS_APPROX(x[0], 0.192807830); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.191262206); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.123052716); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.136053014); // should be 1.3606233068E-01 /* * Second try @@ -1833,7 +1833,6 @@ void test_NonLinearOptimization() /* * Can be useful for debugging... - printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev); printf("info, nfev : %d, %d\n", info, lm.nfev); printf("info, nfev, njev : %d, %d, %d\n", info, solver.nfev, solver.njev); printf("info, nfev : %d, %d\n", info, solver.nfev); @@ -1843,5 +1842,10 @@ void test_NonLinearOptimization() printf("x[3] : %.32g\n", x[3]); printf("fvec.blueNorm() : %.32g\n", solver.fvec.blueNorm()); printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm()); + + printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev); + printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm()); + printf("fvec.squaredNorm() : %.32g\n", lm.fvec.squaredNorm()); + std::cout << x << std::endl; */ From 92be7f461b71d63c04057565dda13b249453dc0a Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 25 Jan 2010 07:23:38 +0100 Subject: [PATCH 009/109] define ei_lmpar2() that takes a ColPivHouseholderQR as argument. We still need to keep the old one around, though. --- .../LevenbergMarquardt.h | 2 +- .../Eigen/src/NonLinearOptimization/lmpar.h | 170 ++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 9f3707952..51beeb1be 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -336,7 +336,7 @@ LevenbergMarquardt::minimizeOneStep( /* determine the levenberg-marquardt parameter. */ - ei_lmpar(fjac, ipvt, diag, qtf, delta, par, wa1); + ei_lmpar2(qrfac, diag, qtf, delta, par, wa1); /* store the direction p and x + p. calculate the norm of p. */ diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index 65e9d799e..22d168078 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -166,3 +166,173 @@ void ei_lmpar( par = 0.; return; } + +template +void ei_lmpar2( + const ColPivHouseholderQR > &qr, + const Matrix< Scalar, Dynamic, 1 > &diag, + const Matrix< Scalar, Dynamic, 1 > &qtb, + Scalar delta, + Scalar &par, + Matrix< Scalar, Dynamic, 1 > &x) + +{ + /* Local variables */ + int i, j, l; + Scalar fp; + Scalar parc, parl; + int iter; + Scalar temp, paru; + Scalar gnorm; + Scalar dxnorm; + + + /* Function Body */ + const Scalar dwarf = std::numeric_limits::min(); + const int n = qr.matrixQR().cols(); + assert(n==diag.size()); + assert(n==qtb.size()); + assert(n==x.size()); + + Matrix< Scalar, Dynamic, 1 > wa1, wa2; + + /* compute and store in x the gauss-newton direction. if the */ + /* jacobian is rank-deficient, obtain a least squares solution. */ + + int nsing = n-1; + wa1 = qtb; + for (j = 0; j < n; ++j) { + if (qr.matrixQR()(j,j) == 0. && nsing == n-1) + nsing = j - 1; + if (nsing < n-1) + wa1[j] = 0.; + } + for (j = nsing; j>=0; --j) { + wa1[j] /= qr.matrixQR()(j,j); + temp = wa1[j]; + for (i = 0; i < j ; ++i) + wa1[i] -= qr.matrixQR()(i,j) * temp; + } + + for (j = 0; j < n; ++j) + x[qr.colsPermutation().indices()(j)] = wa1[j]; + + /* initialize the iteration counter. */ + /* evaluate the function at the origin, and test */ + /* for acceptance of the gauss-newton direction. */ + + iter = 0; + wa2 = diag.cwiseProduct(x); + dxnorm = wa2.blueNorm(); + fp = dxnorm - delta; + if (fp <= Scalar(0.1) * delta) { + par = 0; + return; + } + + /* if the jacobian is not rank deficient, the newton */ + /* step provides a lower bound, parl, for the zero of */ + /* the function. otherwise set this bound to zero. */ + + parl = 0.; + if (nsing >= n-1) { + for (j = 0; j < n; ++j) { + l = qr.colsPermutation().indices()(j); + wa1[j] = diag[l] * (wa2[l] / dxnorm); + } + // it's actually a triangularView.solveInplace(), though in a weird + // way: + for (j = 0; j < n; ++j) { + Scalar sum = 0.; + for (i = 0; i < j; ++i) + sum += qr.matrixQR()(i,j) * wa1[i]; + wa1[j] = (wa1[j] - sum) / qr.matrixQR()(j,j); + } + temp = wa1.blueNorm(); + parl = fp / delta / temp / temp; + } + + /* calculate an upper bound, paru, for the zero of the function. */ + + for (j = 0; j < n; ++j) + wa1[j] = qr.matrixQR().col(j).head(j+1).dot(qtb.head(j+1)) / diag[qr.colsPermutation().indices()(j)]; + + gnorm = wa1.stableNorm(); + paru = gnorm / delta; + if (paru == 0.) + paru = dwarf / std::min(delta,Scalar(0.1)); + + /* if the input par lies outside of the interval (parl,paru), */ + /* set par to the closer endpoint. */ + + par = std::max(par,parl); + par = std::min(par,paru); + if (par == 0.) + par = gnorm / dxnorm; + + /* beginning of an iteration. */ + + Matrix< Scalar, Dynamic, Dynamic > r = qr.matrixQR(); // TODO : fixme + while (true) { + ++iter; + + /* evaluate the function at the current value of par. */ + + if (par == 0.) + par = std::max(dwarf,Scalar(.001) * paru); /* Computing MAX */ + + wa1 = ei_sqrt(par)* diag; + + Matrix< Scalar, Dynamic, 1 > sdiag(n); + ei_qrsolv(r, qr.colsPermutation().indices(), wa1, qtb, x, sdiag); + + wa2 = diag.cwiseProduct(x); + dxnorm = wa2.blueNorm(); + temp = fp; + fp = dxnorm - delta; + + /* if the function is small enough, accept the current value */ + /* of par. also test for the exceptional cases where parl */ + /* is zero or the number of iterations has reached 10. */ + + if (ei_abs(fp) <= Scalar(0.1) * delta || (parl == 0. && fp <= temp && temp < 0.) || iter == 10) + break; + + /* compute the newton correction. */ + + for (j = 0; j < n; ++j) { + l = qr.colsPermutation().indices()[j]; + wa1[j] = diag[l] * (wa2[l] / dxnorm); + } + for (j = 0; j < n; ++j) { + wa1[j] /= sdiag[j]; + temp = wa1[j]; + for (i = j+1; i < n; ++i) + wa1[i] -= r(i,j) * temp; + } + temp = wa1.blueNorm(); + parc = fp / delta / temp / temp; + + /* depending on the sign of the function, update parl or paru. */ + + if (fp > 0.) + parl = std::max(parl,par); + if (fp < 0.) + paru = std::min(paru,par); + + /* compute an improved estimate for par. */ + + /* Computing MAX */ + par = std::max(parl,par+parc); + + /* end of an iteration. */ + + } + + /* termination. */ + + if (iter == 0) + par = 0.; + return; +} + From 9651e0c5039e7fe20f7d296d43a8518f7297c574 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 25 Jan 2010 11:34:52 +0100 Subject: [PATCH 010/109] Use eigen methods for solving triangular systems. We loose again very slightly on both speed and precision on some tests. --- .../Eigen/src/NonLinearOptimization/lmpar.h | 46 ++++--------------- .../Eigen/src/NonLinearOptimization/qrsolv.h | 39 ++++++++-------- unsupported/test/NonLinearOptimization.cpp | 6 +-- 3 files changed, 31 insertions(+), 60 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index 22d168078..5cb7e4051 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -199,23 +199,12 @@ void ei_lmpar2( /* compute and store in x the gauss-newton direction. if the */ /* jacobian is rank-deficient, obtain a least squares solution. */ - int nsing = n-1; - wa1 = qtb; - for (j = 0; j < n; ++j) { - if (qr.matrixQR()(j,j) == 0. && nsing == n-1) - nsing = j - 1; - if (nsing < n-1) - wa1[j] = 0.; - } - for (j = nsing; j>=0; --j) { - wa1[j] /= qr.matrixQR()(j,j); - temp = wa1[j]; - for (i = 0; i < j ; ++i) - wa1[i] -= qr.matrixQR()(i,j) * temp; - } +// const int rank = qr.nonzeroPivots(); // exactly double(0.) + const int rank = qr.rank(); // use a threshold + wa1 = qtb; wa1.segment(rank,n-rank).setZero(); + qr.matrixQR().corner(TopLeft, rank, rank).template triangularView().solveInPlace(wa1.head(rank)); - for (j = 0; j < n; ++j) - x[qr.colsPermutation().indices()(j)] = wa1[j]; + x = qr.colsPermutation()*wa1; /* initialize the iteration counter. */ /* evaluate the function at the origin, and test */ @@ -235,19 +224,12 @@ void ei_lmpar2( /* the function. otherwise set this bound to zero. */ parl = 0.; - if (nsing >= n-1) { + if (rank==n) { for (j = 0; j < n; ++j) { l = qr.colsPermutation().indices()(j); wa1[j] = diag[l] * (wa2[l] / dxnorm); } - // it's actually a triangularView.solveInplace(), though in a weird - // way: - for (j = 0; j < n; ++j) { - Scalar sum = 0.; - for (i = 0; i < j; ++i) - sum += qr.matrixQR()(i,j) * wa1[i]; - wa1[j] = (wa1[j] - sum) / qr.matrixQR()(j,j); - } + qr.matrixQR().corner(TopLeft, n, n).transpose().template triangularView().solveInPlace(wa1); temp = wa1.blueNorm(); parl = fp / delta / temp / temp; } @@ -272,7 +254,7 @@ void ei_lmpar2( /* beginning of an iteration. */ - Matrix< Scalar, Dynamic, Dynamic > r = qr.matrixQR(); // TODO : fixme + Matrix< Scalar, Dynamic, Dynamic > s = qr.matrixQR(); while (true) { ++iter; @@ -284,7 +266,7 @@ void ei_lmpar2( wa1 = ei_sqrt(par)* diag; Matrix< Scalar, Dynamic, 1 > sdiag(n); - ei_qrsolv(r, qr.colsPermutation().indices(), wa1, qtb, x, sdiag); + ei_qrsolv(s, qr.colsPermutation().indices(), wa1, qtb, x, sdiag); wa2 = diag.cwiseProduct(x); dxnorm = wa2.blueNorm(); @@ -308,7 +290,7 @@ void ei_lmpar2( wa1[j] /= sdiag[j]; temp = wa1[j]; for (i = j+1; i < n; ++i) - wa1[i] -= r(i,j) * temp; + wa1[i] -= s(i,j) * temp; } temp = wa1.blueNorm(); parc = fp / delta / temp / temp; @@ -321,16 +303,8 @@ void ei_lmpar2( paru = std::min(paru,par); /* compute an improved estimate for par. */ - - /* Computing MAX */ par = std::max(parl,par+parc); - - /* end of an iteration. */ - } - - /* termination. */ - if (iter == 0) par = 0.; return; diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h index 6ffba42c5..880d9d6e3 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h @@ -1,7 +1,8 @@ template void ei_qrsolv( - Matrix< Scalar, Dynamic, Dynamic > &r, + Matrix< Scalar, Dynamic, Dynamic > &s, + // TODO : use a PermutationMatrix once ei_lmpar is no more: const VectorXi &ipvt, const Matrix< Scalar, Dynamic, 1 > &diag, const Matrix< Scalar, Dynamic, 1 > &qtb, @@ -11,21 +12,23 @@ void ei_qrsolv( { /* Local variables */ int i, j, k, l; - Scalar sum, temp; - int n = r.cols(); + Scalar temp; + int n = s.cols(); Matrix< Scalar, Dynamic, 1 > wa(n); /* Function Body */ + // the following will only change the lower triangular part of s, including + // the diagonal, though the diagonal is restored afterward /* copy r and (q transpose)*b to preserve input and initialize s. */ /* in particular, save the diagonal elements of r in x. */ - x = r.diagonal(); + x = s.diagonal(); wa = qtb; for (j = 0; j < n; ++j) for (i = j+1; i < n; ++i) - r(i,j) = r(j,i); + s(i,j) = s(j,i); /* eliminate the diagonal matrix d using a givens rotation. */ for (j = 0; j < n; ++j) { @@ -48,43 +51,37 @@ void ei_qrsolv( /* determine a givens rotation which eliminates the */ /* appropriate element in the current row of d. */ PlanarRotation givens; - givens.makeGivens(-r(k,k), sdiag[k]); + givens.makeGivens(-s(k,k), sdiag[k]); /* compute the modified diagonal element of r and */ /* the modified element of ((q transpose)*b,0). */ - r(k,k) = givens.c() * r(k,k) + givens.s() * sdiag[k]; + s(k,k) = givens.c() * s(k,k) + givens.s() * sdiag[k]; temp = givens.c() * wa[k] + givens.s() * qtbpj; qtbpj = -givens.s() * wa[k] + givens.c() * qtbpj; wa[k] = temp; /* accumulate the tranformation in the row of s. */ for (i = k+1; i=0; j--) { - sum = 0.; - for (i = j+1; i <= nsing; ++i) - sum += r(i,j) * wa[i]; - wa[j] = (wa[j] - sum) / sdiag[j]; - } + s.corner(TopLeft, nsing, nsing).transpose().template triangularView().solveInPlace(wa.head(nsing)); + + // restore + sdiag = s.diagonal(); + s.diagonal() = x; /* permute the components of z back to components of x. */ for (j = 0; j < n; ++j) x[ipvt[j]] = wa[j]; diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index baca18052..c1687b8c3 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -1010,7 +1010,7 @@ void testNistLanczos1(void) VERIFY( 79 == lm.nfev); VERIFY( 72 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428127827535E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.427932429905E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1332,8 +1332,8 @@ void testNistMGH17(void) // check return value VERIFY( 2 == info); - VERIFY( 603 == lm.nfev); - VERIFY( 544 == lm.njev); + VERIFY( 606 == lm.nfev); + VERIFY( 545 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); // check x From 1403cea087df98dae21408518c33a22f8d2d99d1 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 04:55:36 +0100 Subject: [PATCH 011/109] =?UTF-8?q?fix=20a=20bug=20introduced=20between=20?= =?UTF-8?q?the=20cminpack=20version=20of=20Manolis=20Lourakis=20and=20the?= =?UTF-8?q?=20one=20from=20Fr=C3=A9d=C3=A9ric=20Devernay.=20Here,=20we=20w?= =?UTF-8?q?ant=20to=20compute=20the=20max=20over=20the=20column,=20the=20-?= =?UTF-8?q?1=20is=20not=20needed=20in=20fortran=20because=20indices=20star?= =?UTF-8?q?t=20at=201,=20contrary=20to=20c/c++.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unsupported/Eigen/src/NonLinearOptimization/dogleg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index cf488b0bf..bbd0840ae 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -38,7 +38,7 @@ void ei_dogleg( for (i = 0; i <= j; ++i) { /* Computing MAX */ temp = std::max(temp,ei_abs(r[l])); - l = l + n - i; + l = l + n - i - 1; } temp = epsmch * temp; if (temp == 0.) From bdb0e9fcd03a21c2451a893424bb71955917ed07 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 26 Jan 2010 16:02:19 +0000 Subject: [PATCH 012/109] Clean up one compilation error and two warnings. --- Eigen/src/Core/IO.h | 13 ++++++++++--- cmake/EigenTesting.cmake | 1 + unsupported/Eigen/AlignedVector3 | 3 ++- unsupported/Eigen/AutoDiff | 2 -- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index d132064a6..8f91e272e 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -143,9 +143,16 @@ std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOForm } else if(fmt.precision == FullPrecision) { - explicit_precision = NumTraits::HasFloatingPoint - ? std::ceil(-ei_log(epsilon())/ei_log(10.0)) - : 0; + if (NumTraits::HasFloatingPoint) + { + typedef typename NumTraits::Real RealScalar; + RealScalar explicit_precision_fp = std::ceil(-ei_log(epsilon())/ei_log(10.0)); + explicit_precision = static_cast(explicit_precision_fp); + } + else + { + explicit_precision = 0; + } } else { diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index b8cd63ac1..4d02a470a 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -219,6 +219,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) option(EIGEN_COVERAGE_TESTING "Enable/disable gcov" OFF) if(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage") + set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/test/") else(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "") endif(EIGEN_COVERAGE_TESTING) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index 37018bfc6..15510a258 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -64,7 +64,8 @@ template class AlignedVector3 CoeffType m_coeffs; public: - EIGEN_GENERIC_PUBLIC_INTERFACE(AlignedVector3) + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(AlignedVector3) using Base::operator*; inline int rows() const { return 3; } diff --git a/unsupported/Eigen/AutoDiff b/unsupported/Eigen/AutoDiff index a8b3ea90a..97164525c 100644 --- a/unsupported/Eigen/AutoDiff +++ b/unsupported/Eigen/AutoDiff @@ -25,8 +25,6 @@ #ifndef EIGEN_AUTODIFF_MODULE #define EIGEN_AUTODIFF_MODULE -#include - namespace Eigen { /** \ingroup Unsupported_modules From c759814f1123f245d13e460444ddb0b39df6433b Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 01:43:58 +0100 Subject: [PATCH 013/109] some more (thoroughly checked) eigenization --- .../Eigen/src/NonLinearOptimization/lmpar.h | 12 +++------ unsupported/test/NonLinearOptimization.cpp | 27 +++++++++++-------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index 5cb7e4051..54c84960a 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -178,7 +178,7 @@ void ei_lmpar2( { /* Local variables */ - int i, j, l; + int i, j; Scalar fp; Scalar parc, parl; int iter; @@ -225,10 +225,7 @@ void ei_lmpar2( parl = 0.; if (rank==n) { - for (j = 0; j < n; ++j) { - l = qr.colsPermutation().indices()(j); - wa1[j] = diag[l] * (wa2[l] / dxnorm); - } + wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2)/dxnorm; qr.matrixQR().corner(TopLeft, n, n).transpose().template triangularView().solveInPlace(wa1); temp = wa1.blueNorm(); parl = fp / delta / temp / temp; @@ -282,10 +279,7 @@ void ei_lmpar2( /* compute the newton correction. */ - for (j = 0; j < n; ++j) { - l = qr.colsPermutation().indices()[j]; - wa1[j] = diag[l] * (wa2[l] / dxnorm); - } + wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2/dxnorm); for (j = 0; j < n; ++j) { wa1[j] /= sdiag[j]; temp = wa1[j]; diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index c1687b8c3..39c897241 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -1010,7 +1010,7 @@ void testNistLanczos1(void) VERIFY( 79 == lm.nfev); VERIFY( 72 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.427932429905E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.429961002287e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1170,7 +1170,7 @@ void testNistMGH10(void) info = lm.minimize(x); // check return value - VERIFY( 3 == info); + VERIFY( 2 == info); VERIFY( 281 == lm.nfev); VERIFY( 248 == lm.njev); // check norm^2 @@ -1332,8 +1332,8 @@ void testNistMGH17(void) // check return value VERIFY( 2 == info); - VERIFY( 606 == lm.nfev); - VERIFY( 545 == lm.njev); + VERIFY( 605 == lm.nfev); + VERIFY( 544 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); // check x @@ -1419,15 +1419,15 @@ void testNistMGH09(void) // check return value VERIFY( 1 == info); - VERIFY( 494== lm.nfev); - VERIFY( 382 == lm.njev); + VERIFY( 486 == lm.nfev); + VERIFY( 377 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04); // check x - VERIFY_IS_APPROX(x[0], 0.192807830); // should be 1.9280693458E-01 - VERIFY_IS_APPROX(x[1], 0.191262206); // should be 1.9128232873E-01 - VERIFY_IS_APPROX(x[2], 0.123052716); // should be 1.2305650693E-01 - VERIFY_IS_APPROX(x[3], 0.136053014); // should be 1.3606233068E-01 + VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01 + VERIFY_IS_APPROX(x[1], 0.1912649346); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.1230532308); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.1360542773); // should be 1.3606233068E-01 /* * Second try @@ -1844,8 +1844,13 @@ void test_NonLinearOptimization() printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm()); printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev); - printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm()); + printf("fvec.squaredNorm() : %.13g\n", lm.fvec.squaredNorm()); printf("fvec.squaredNorm() : %.32g\n", lm.fvec.squaredNorm()); std::cout << x << std::endl; + std::cout.precision(9); + std::cout << x[0] << std::endl; + std::cout << x[1] << std::endl; + std::cout << x[2] << std::endl; + std::cout << x[3] << std::endl; */ From 4b859c85545b45ff60f94ef002ee248678d3569b Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 01:59:32 +0100 Subject: [PATCH 014/109] cleaning --- .../NonLinearOptimization/HybridNonLinearSolver.h | 5 ----- .../src/NonLinearOptimization/LevenbergMarquardt.h | 12 +++++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 91efdac68..8f7285203 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -286,11 +286,6 @@ HybridNonLinearSolver::solveOneStep( /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); -#if 0 - std::cout << "ei_qform: " << fjac << std::endl; - fjac = qrfac.matrixQ(); - std::cout << "qrfac.matrixQ():" << fjac << std::endl; -#endif /* rescale if necessary. */ diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 51beeb1be..b9e3c808e 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -286,6 +286,13 @@ LevenbergMarquardt::minimizeOneStep( /* form (q transpose)*fvec and store the first n components in */ /* qtf. */ +#if 0 + // find a way to only compute the first n items, we have m>>n here. + wa4 = fvec; + wa4.applyOnTheLeft(qrfac.householderQ().adjoint()); + wa4 = wa4.head(n); + fjac.diagonal() = wa1; +#else wa4 = fvec; for (j = 0; j < n; ++j) { if (fjac(j,j) != 0.) { @@ -299,11 +306,6 @@ LevenbergMarquardt::minimizeOneStep( fjac(j,j) = wa1[j]; qtf[j] = wa4[j]; } - -#if 0 - std::cout << "qtf: " << qtf << std::endl; - FVectorType monqtf = qrfac.matrixQ().transpose() * fvec; - std::cout << "mon qtf :" << monqtf << std::endl; #endif /* compute the norm of the scaled gradient. */ From 91561cded44d53de0724b89cad9b60cc86c7bd80 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 05:59:58 +0100 Subject: [PATCH 015/109] use a plain matrix to store the upper triangular matrix 'R', instead of the "compact inside a vector" scheme used by fortran/minpack. The most difficult part is to fix all related code. Tests pass. --- .../HybridNonLinearSolver.h | 61 +++++------------ .../Eigen/src/NonLinearOptimization/dogleg.h | 35 +++------- .../Eigen/src/NonLinearOptimization/r1updt.h | 68 ++++++------------- 3 files changed, 48 insertions(+), 116 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 8f7285203..3ad901391 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -74,6 +74,8 @@ public: }; typedef Matrix< Scalar, Dynamic, 1 > FVectorType; typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType; + /* TODO: if eigen provides a triangular storage, use it here */ + typedef Matrix< Scalar, Dynamic, Dynamic > UpperTriangularType; Status hybrj1( FVectorType &x, @@ -113,8 +115,9 @@ public: void resetParameters(void) { parameters = Parameters(); } Parameters parameters; - FVectorType fvec, R, qtf, diag; + FVectorType fvec, qtf, diag; JacobianType fjac; + UpperTriangularType R; int nfev; int njev; int iter; @@ -173,7 +176,6 @@ HybridNonLinearSolver::solveInit( wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n); fvec.resize(n); qtf.resize(n); - R.resize( (n*(n+1))/2); fjac.resize(n, n); if (mode != 2) diag.resize(n); @@ -218,7 +220,7 @@ HybridNonLinearSolver::solveOneStep( const int mode ) { - int i, j, l; + int i, j; jeval = true; /* calculate the jacobian matrix. */ @@ -272,17 +274,10 @@ HybridNonLinearSolver::solveOneStep( /* copy the triangular factor of the qr factorization into r. */ + R = qrfac.matrixQR(); sing = false; - for (j = 0; j < n; ++j) { - l = j; - for (i = 0; i < j; ++i) { - R[l] = fjac(i,j); - l = l + n - i -1; - } - R[l] = wa1[j]; - if (wa1[j] == 0.) - sing = true; - } + for (j = 0; j < n; ++j) + if (wa1[j] == 0.) sing = true; /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); @@ -328,13 +323,10 @@ HybridNonLinearSolver::solveOneStep( /* compute the scaled predicted reduction. */ - l = 0; for (i = 0; i < n; ++i) { sum = 0.; - for (j = i; j < n; ++j) { - sum += R[l] * wa1[j]; - ++l; - } + for (j = i; j < n; ++j) + sum += R(i,j) * wa1[j]; wa3[i] = qtf[i] + sum; } temp = wa3.stableNorm(); @@ -421,7 +413,7 @@ HybridNonLinearSolver::solveOneStep( /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R.data(), R.size(), wa1.data(), wa2.data(), wa3.data(), &sing); + ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); @@ -488,7 +480,6 @@ HybridNonLinearSolver::solveNumericalDiffInit( wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(n); qtf.resize(n); - R.resize( (n*(n+1))/2); fjac.resize(n, n); fvec.resize(n); if (mode != 2) @@ -536,7 +527,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( const int mode ) { - int i, j, l; + int i, j; jeval = true; if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1; if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1; @@ -591,26 +582,13 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( } /* copy the triangular factor of the qr factorization into r. */ - + R = qrfac.matrixQR(); sing = false; - for (j = 0; j < n; ++j) { - l = j; - for (i = 0; i < j; ++i) { - R[l] = fjac(i,j); - l = l + n - i -1; - } - R[l] = wa1[j]; - if (wa1[j] == 0.) - sing = true; - } + for (j = 0; j < n; ++j) + if (wa1[j] == 0.) sing = true; /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); -#if 0 - std::cout << "ei_qform: " << fjac << std::endl; - fjac = qrfac.matrixQ(); - std::cout << "qrfac.matrixQ():" << fjac << std::endl; -#endif /* rescale if necessary. */ @@ -653,13 +631,10 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* compute the scaled predicted reduction. */ - l = 0; for (i = 0; i < n; ++i) { sum = 0.; - for (j = i; j < n; ++j) { - sum += R[l] * wa1[j]; - ++l; - } + for (j = i; j < n; ++j) + sum += R(i,j) * wa1[j]; wa3[i] = qtf[i] + sum; } temp = wa3.stableNorm(); @@ -747,7 +722,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R.data(), R.size(), wa1.data(), wa2.data(), wa3.data(), &sing); + ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index bbd0840ae..36ed962f1 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -1,14 +1,14 @@ template void ei_dogleg( - Matrix< Scalar, Dynamic, 1 > &r, + const Matrix< Scalar, Dynamic, Dynamic > &qrfac, const Matrix< Scalar, Dynamic, 1 > &diag, const Matrix< Scalar, Dynamic, 1 > &qtb, Scalar delta, Matrix< Scalar, Dynamic, 1 > &x) { /* Local variables */ - int i, j, k, l, jj; + int i, j, k; Scalar sum, temp, alpha, bnorm; Scalar gnorm, qnorm; Scalar sgnorm; @@ -20,26 +20,16 @@ void ei_dogleg( assert(n==qtb.size()); assert(n==x.size()); - /* first, calculate the gauss-newton direction. */ - - jj = n * (n + 1) / 2; for (k = 0; k < n; ++k) { j = n - k - 1; - jj -= k+1; - l = jj + 1; sum = 0.; for (i = j+1; i < n; ++i) { - sum += r[l] * x[i]; - ++l; + sum += qrfac(j,i) * x[i]; } - temp = r[jj]; + temp = qrfac(j,j); if (temp == 0.) { - l = j; - for (i = 0; i <= j; ++i) { - /* Computing MAX */ - temp = std::max(temp,ei_abs(r[l])); - l = l + n - i - 1; - } + for (i = 0; i <= j; ++i) + temp = std::max(temp,ei_abs(qrfac(i,j))); temp = epsmch * temp; if (temp == 0.) temp = epsmch; @@ -58,13 +48,10 @@ void ei_dogleg( /* the gauss-newton direction is not acceptable. */ /* next, calculate the scaled gradient direction. */ - l = 0; for (j = 0; j < n; ++j) { temp = qtb[j]; - for (i = j; i < n; ++i) { - wa1[i] += r[l] * temp; - ++l; - } + for (i = j; i < n; ++i) + wa1[i] += qrfac(j,i) * temp; wa1[j] /= diag[j]; } @@ -81,16 +68,12 @@ void ei_dogleg( /* at which the quadratic is minimized. */ wa1.array() /= (diag*gnorm).array(); - l = 0; for (j = 0; j < n; ++j) { sum = 0.; for (i = j; i < n; ++i) { - sum += r[l] * wa1[i]; - ++l; - /* L100: */ + sum += qrfac(j,i) * wa1[i]; } wa2[j] = sum; - /* L110: */ } temp = wa2.stableNorm(); sgnorm = gnorm / temp / temp; diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h index f2ddb189b..e5e907582 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h @@ -1,34 +1,27 @@ - template -void ei_r1updt(int m, int n, Scalar *s, int /* ls */, const Scalar *u, Scalar *v, Scalar *w, bool *sing) +template +void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, Scalar *v, Scalar *w, bool *sing) { /* Local variables */ - int i, j, l, jj, nm1; + int i, j, nm1; Scalar tan__; int nmj; Scalar cos__, sin__, tau, temp, cotan; + // ei_r1updt had a broader usecase, but we dont use it here. And, more + // importantly, we can not test it. + assert(m==n); + /* Parameter adjustments */ --w; --u; --v; - --s; /* Function Body */ const Scalar giant = std::numeric_limits::max(); - /* initialize the diagonal element pointer. */ - - jj = n * ((m << 1) - n + 1) / 2 - (m - n); - /* move the nontrivial part of the last column of s into w. */ - - l = jj; - for (i = n; i <= m; ++i) { - w[i] = s[l]; - ++l; - /* L10: */ - } + w[n] = s(n-1,n-1); /* rotate the vector v into a multiple of the n-th unit vector */ /* in such a way that a spike is introduced into w. */ @@ -39,7 +32,6 @@ void ei_r1updt(int m, int n, Scalar *s, int /* ls */, const Scalar *u, Scalar *v } for (nmj = 1; nmj <= nm1; ++nmj) { j = n - nmj; - jj -= m - j + 1; w[j] = 0.; if (v[j] == 0.) { goto L50; @@ -75,16 +67,12 @@ L30: /* apply the transformation to s and extend the spike in w. */ - l = jj; for (i = j; i <= m; ++i) { - temp = cos__ * s[l] - sin__ * w[i]; - w[i] = sin__ * s[l] + cos__ * w[i]; - s[l] = temp; - ++l; - /* L40: */ + temp = cos__ * s(j-1,i-1) - sin__ * w[i]; + w[i] = sin__ * s(j-1,i-1) + cos__ * w[i]; + s(j-1,i-1) = temp; } L50: - /* L60: */ ; } L70: @@ -110,9 +98,9 @@ L70: /* determine a givens rotation which eliminates the */ /* j-th element of the spike. */ - if (ei_abs(s[jj]) >= ei_abs(w[j])) + if (ei_abs(s(j-1,j-1)) >= ei_abs(w[j])) goto L90; - cotan = s[jj] / w[j]; + cotan = s(j-1,j-1) / w[j]; /* Computing 2nd power */ sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); cos__ = sin__ * cotan; @@ -122,7 +110,7 @@ L70: } goto L100; L90: - tan__ = w[j] / s[jj]; + tan__ = w[j] / s(j-1,j-1); /* Computing 2nd power */ cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); sin__ = cos__ * tan__; @@ -131,13 +119,10 @@ L100: /* apply the transformation to s and reduce the spike in w. */ - l = jj; for (i = j; i <= m; ++i) { - temp = cos__ * s[l] + sin__ * w[i]; - w[i] = -sin__ * s[l] + cos__ * w[i]; - s[l] = temp; - ++l; - /* L110: */ + temp = cos__ * s(j-1,i-1) + sin__ * w[i]; + w[i] = -sin__ * s(j-1,i-1) + cos__ * w[i]; + s(j-1,i-1) = temp; } /* store the information necessary to recover the */ @@ -148,28 +133,17 @@ L120: /* test for zero diagonal elements in the output s. */ - if (s[jj] == 0.) { + if (s(j-1,j-1) == 0.) { *sing = true; } - jj += m - j + 1; - /* L130: */ } L140: - /* move w back into the last column of the output s. */ + s(n-1,n-1) = w[n]; - l = jj; - for (i = n; i <= m; ++i) { - s[l] = w[i]; - ++l; - /* L150: */ - } - if (s[jj] == 0.) { + if (s(j-1,j-1) == 0.) { *sing = true; } return; - - /* last card of subroutine r1updt. */ - -} /* r1updt_ */ +} From a3034ee0790fb65f69f024335cf35acbf6de5a44 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 06:05:01 +0100 Subject: [PATCH 016/109] cleaning --- .../Eigen/src/NonLinearOptimization/r1updt.h | 179 ++++++++---------- 1 file changed, 75 insertions(+), 104 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h index e5e907582..71a704d24 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h @@ -25,119 +25,90 @@ void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar /* rotate the vector v into a multiple of the n-th unit vector */ /* in such a way that a spike is introduced into w. */ - nm1 = n - 1; - if (nm1 < 1) { - goto L70; - } - for (nmj = 1; nmj <= nm1; ++nmj) { - j = n - nmj; - w[j] = 0.; - if (v[j] == 0.) { - goto L50; + if (nm1 >= 1) + for (nmj = 1; nmj <= nm1; ++nmj) { + j = n - nmj; + w[j] = 0.; + if (v[j] != 0.) { + /* determine a givens rotation which eliminates the */ + /* j-th element of v. */ + if (ei_abs(v[n]) < ei_abs(v[j])) { + cotan = v[n] / v[j]; + /* Computing 2nd power */ + sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); + cos__ = sin__ * cotan; + tau = 1.; + if (ei_abs(cos__) * giant > 1.) { + tau = 1. / cos__; + } + } else { + tan__ = v[j] / v[n]; + /* Computing 2nd power */ + cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); + sin__ = cos__ * tan__; + tau = sin__; + } + + /* apply the transformation to v and store the information */ + /* necessary to recover the givens rotation. */ + v[n] = sin__ * v[j] + cos__ * v[n]; + v[j] = tau; + + /* apply the transformation to s and extend the spike in w. */ + for (i = j; i <= m; ++i) { + temp = cos__ * s(j-1,i-1) - sin__ * w[i]; + w[i] = sin__ * s(j-1,i-1) + cos__ * w[i]; + s(j-1,i-1) = temp; + } + } } - /* determine a givens rotation which eliminates the */ - /* j-th element of v. */ - - if (ei_abs(v[n]) >= ei_abs(v[j])) - goto L20; - cotan = v[n] / v[j]; - /* Computing 2nd power */ - sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__ = sin__ * cotan; - tau = 1.; - if (ei_abs(cos__) * giant > 1.) { - tau = 1. / cos__; - } - goto L30; -L20: - tan__ = v[j] / v[n]; - /* Computing 2nd power */ - cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__ = cos__ * tan__; - tau = sin__; -L30: - - /* apply the transformation to v and store the information */ - /* necessary to recover the givens rotation. */ - - v[n] = sin__ * v[j] + cos__ * v[n]; - v[j] = tau; - - /* apply the transformation to s and extend the spike in w. */ - - for (i = j; i <= m; ++i) { - temp = cos__ * s(j-1,i-1) - sin__ * w[i]; - w[i] = sin__ * s(j-1,i-1) + cos__ * w[i]; - s(j-1,i-1) = temp; - } -L50: - ; - } -L70: - /* add the spike from the rank 1 update to w. */ - - for (i = 1; i <= m; ++i) { + for (i = 1; i <= m; ++i) w[i] += v[n] * u[i]; - /* L80: */ - } /* eliminate the spike. */ - *sing = false; - if (nm1 < 1) { - goto L140; - } - for (j = 1; j <= nm1; ++j) { - if (w[j] == 0.) { - goto L120; + if (nm1 >= 1) + for (j = 1; j <= nm1; ++j) { + if (w[j] != 0.) { + /* determine a givens rotation which eliminates the */ + /* j-th element of the spike. */ + if (ei_abs(s(j-1,j-1)) < ei_abs(w[j])) { + cotan = s(j-1,j-1) / w[j]; + /* Computing 2nd power */ + sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); + cos__ = sin__ * cotan; + tau = 1.; + if (ei_abs(cos__) * giant > 1.) { + tau = 1. / cos__; + } + } else { + tan__ = w[j] / s(j-1,j-1); + /* Computing 2nd power */ + cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); + sin__ = cos__ * tan__; + tau = sin__; + } + + /* apply the transformation to s and reduce the spike in w. */ + for (i = j; i <= m; ++i) { + temp = cos__ * s(j-1,i-1) + sin__ * w[i]; + w[i] = -sin__ * s(j-1,i-1) + cos__ * w[i]; + s(j-1,i-1) = temp; + } + + /* store the information necessary to recover the */ + /* givens rotation. */ + w[j] = tau; + } + + /* test for zero diagonal elements in the output s. */ + if (s(j-1,j-1) == 0.) { + *sing = true; + } } - - /* determine a givens rotation which eliminates the */ - /* j-th element of the spike. */ - - if (ei_abs(s(j-1,j-1)) >= ei_abs(w[j])) - goto L90; - cotan = s(j-1,j-1) / w[j]; - /* Computing 2nd power */ - sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__ = sin__ * cotan; - tau = 1.; - if (ei_abs(cos__) * giant > 1.) { - tau = 1. / cos__; - } - goto L100; -L90: - tan__ = w[j] / s(j-1,j-1); - /* Computing 2nd power */ - cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__ = cos__ * tan__; - tau = sin__; -L100: - - /* apply the transformation to s and reduce the spike in w. */ - - for (i = j; i <= m; ++i) { - temp = cos__ * s(j-1,i-1) + sin__ * w[i]; - w[i] = -sin__ * s(j-1,i-1) + cos__ * w[i]; - s(j-1,i-1) = temp; - } - - /* store the information necessary to recover the */ - /* givens rotation. */ - - w[j] = tau; -L120: - - /* test for zero diagonal elements in the output s. */ - - if (s(j-1,j-1) == 0.) { - *sing = true; - } - } -L140: /* move w back into the last column of the output s. */ s(n-1,n-1) = w[n]; From ba2a9cce037a23a5f3c40c772687322c0cdd750a Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 07:36:15 +0100 Subject: [PATCH 017/109] some more eigenization --- .../HybridNonLinearSolver.h | 132 +++--------------- .../Eigen/src/NonLinearOptimization/dogleg.h | 38 +++-- 2 files changed, 39 insertions(+), 131 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 3ad901391..ee5b63c44 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -186,7 +186,6 @@ HybridNonLinearSolver::solveInit( njev = 0; /* check the input parameters for errors. */ - if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0. ) return ImproperInputParameters; if (mode == 2) @@ -196,14 +195,12 @@ HybridNonLinearSolver::solveInit( /* evaluate the function at the starting point */ /* and calculate its norm. */ - nfev = 1; if ( functor(x, fvec) < 0) return UserAksed; fnorm = fvec.stableNorm(); /* initialize iteration counter and monitors. */ - iter = 1; ncsuc = 0; ncfail = 0; @@ -224,7 +221,6 @@ HybridNonLinearSolver::solveOneStep( jeval = true; /* calculate the jacobian matrix. */ - if ( functor.df(x, fjac) < 0) return UserAksed; ++njev; @@ -235,11 +231,8 @@ HybridNonLinearSolver::solveOneStep( /* to the norms of the columns of the initial jacobian. */ if (iter == 1) { if (mode != 2) - for (j = 0; j < n; ++j) { - diag[j] = wa2[j]; - if (wa2[j] == 0.) - diag[j] = 1.; - } + for (j = 0; j < n; ++j) + diag[j] = (wa2[j]==0.) ? 1. : wa2[j]; /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ @@ -260,7 +253,6 @@ HybridNonLinearSolver::solveOneStep( for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors /* form (q transpose)*fvec and store in qtf. */ - qtf = fvec; for (j = 0; j < n; ++j) if (fjac(j,j) != 0.) { @@ -273,76 +265,54 @@ HybridNonLinearSolver::solveOneStep( } /* copy the triangular factor of the qr factorization into r. */ - R = qrfac.matrixQR(); - sing = false; - for (j = 0; j < n; ++j) - if (wa1[j] == 0.) sing = true; + sing = wa1.cwiseAbs().minCoeff()==0.; /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); /* rescale if necessary. */ - - /* Computing MAX */ if (mode != 2) diag = diag.cwiseMax(wa2); - /* beginning of the inner loop. */ - while (true) { - /* determine the direction p. */ - ei_dogleg(R, diag, qtf, delta, wa1); /* store the direction p and x + p. calculate the norm of p. */ - wa1 = -wa1; wa2 = x + wa1; wa3 = diag.cwiseProduct(wa1); pnorm = wa3.stableNorm(); /* on the first iteration, adjust the initial step bound. */ - if (iter == 1) delta = std::min(delta,pnorm); /* evaluate the function at x + p and calculate its norm. */ - if ( functor(wa2, wa4) < 0) return UserAksed; ++nfev; fnorm1 = wa4.stableNorm(); /* compute the scaled actual reduction. */ - actred = -1.; if (fnorm1 < fnorm) /* Computing 2nd power */ actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction. */ - - for (i = 0; i < n; ++i) { - sum = 0.; - for (j = i; j < n; ++j) - sum += R(i,j) * wa1[j]; - wa3[i] = qtf[i] + sum; - } + wa3 = R.template triangularView()*wa1 + qtf; temp = wa3.stableNorm(); prered = 0.; if (temp < fnorm) /* Computing 2nd power */ prered = 1. - ei_abs2(temp / fnorm); - /* compute the ratio of the actual to the predicted */ - /* reduction. */ - + /* compute the ratio of the actual to the predicted reduction. */ ratio = 0.; if (prered > 0.) ratio = actred / prered; /* update the step bound. */ - if (ratio < Scalar(.1)) { ncsuc = 0; ++ncfail; @@ -350,7 +320,7 @@ HybridNonLinearSolver::solveOneStep( } else { ncfail = 0; ++ncsuc; - if (ratio >= Scalar(.5) || ncsuc > 1) /* Computing MAX */ + if (ratio >= Scalar(.5) || ncsuc > 1) delta = std::max(delta, pnorm / Scalar(.5)); if (ei_abs(ratio - 1.) <= Scalar(.1)) { delta = pnorm / Scalar(.5); @@ -358,7 +328,6 @@ HybridNonLinearSolver::solveOneStep( } /* test for successful iteration. */ - if (ratio >= Scalar(1e-4)) { /* successful iteration. update x, fvec, and their norms. */ x = wa2; @@ -370,7 +339,6 @@ HybridNonLinearSolver::solveOneStep( } /* determine the progress of the iteration. */ - ++nslow1; if (actred >= Scalar(.001)) nslow1 = 0; @@ -380,12 +348,10 @@ HybridNonLinearSolver::solveOneStep( nslow2 = 0; /* test for convergence. */ - if (delta <= parameters.xtol * xnorm || fnorm == 0.) return RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ - if (nfev >= parameters.maxfev) return TooManyFunctionEvaluation; if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) @@ -396,37 +362,27 @@ HybridNonLinearSolver::solveOneStep( return NotMakingProgressIterations; /* criterion for recalculating jacobian. */ - if (ncfail == 2) break; // leave inner loop and go for the next outer loop iteration /* calculate the rank one modification to the jacobian */ /* and update qtf if necessary. */ - - for (j = 0; j < n; ++j) { - sum = wa4.dot(fjac.col(j)); - wa2[j] = (sum - wa3[j]) / pnorm; - wa1[j] = diag[j] * (diag[j] * wa1[j] / pnorm); - if (ratio >= Scalar(1e-4)) - qtf[j] = sum; - } + wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm ); + wa2 = fjac.transpose() * wa4; + if (ratio >= Scalar(1e-4)) + qtf = wa2; + wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); - /* end of the inner loop. */ - jeval = false; } - /* end of the outer loop. */ - return Running; } - template typename HybridNonLinearSolver::Status HybridNonLinearSolver::solve( @@ -493,7 +449,6 @@ HybridNonLinearSolver::solveNumericalDiffInit( njev = 0; /* check the input parameters for errors. */ - if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.nb_of_subdiagonals< 0 || parameters.nb_of_superdiagonals< 0 || parameters.factor <= 0. ) return ImproperInputParameters; if (mode == 2) @@ -503,14 +458,12 @@ HybridNonLinearSolver::solveNumericalDiffInit( /* evaluate the function at the starting point */ /* and calculate its norm. */ - nfev = 1; if ( functor(x, fvec) < 0) return UserAksed; fnorm = fvec.stableNorm(); /* initialize iteration counter and monitors. */ - iter = 1; ncsuc = 0; ncfail = 0; @@ -544,11 +497,8 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* to the norms of the columns of the initial jacobian. */ if (iter == 1) { if (mode != 2) - for (j = 0; j < n; ++j) { - diag[j] = wa2[j]; - if (wa2[j] == 0.) - diag[j] = 1.; - } + for (j = 0; j < n; ++j) + diag[j] = (wa2[j]==0.) ? 1. : wa2[j]; /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ @@ -569,7 +519,6 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors /* form (q transpose)*fvec and store in qtf. */ - qtf = fvec; for (j = 0; j < n; ++j) if (fjac(j,j) != 0.) { @@ -583,74 +532,53 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* copy the triangular factor of the qr factorization into r. */ R = qrfac.matrixQR(); - sing = false; - for (j = 0; j < n; ++j) - if (wa1[j] == 0.) sing = true; + sing = wa1.cwiseAbs().minCoeff()==0.; /* accumulate the orthogonal factor in fjac. */ ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); /* rescale if necessary. */ - - /* Computing MAX */ if (mode != 2) diag = diag.cwiseMax(wa2); - /* beginning of the inner loop. */ - while (true) { - /* determine the direction p. */ - ei_dogleg(R, diag, qtf, delta, wa1); /* store the direction p and x + p. calculate the norm of p. */ - wa1 = -wa1; wa2 = x + wa1; wa3 = diag.cwiseProduct(wa1); pnorm = wa3.stableNorm(); /* on the first iteration, adjust the initial step bound. */ - if (iter == 1) delta = std::min(delta,pnorm); /* evaluate the function at x + p and calculate its norm. */ - if ( functor(wa2, wa4) < 0) return UserAksed; ++nfev; fnorm1 = wa4.stableNorm(); /* compute the scaled actual reduction. */ - actred = -1.; if (fnorm1 < fnorm) /* Computing 2nd power */ actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction. */ - - for (i = 0; i < n; ++i) { - sum = 0.; - for (j = i; j < n; ++j) - sum += R(i,j) * wa1[j]; - wa3[i] = qtf[i] + sum; - } + wa3 = R.template triangularView()*wa1 + qtf; temp = wa3.stableNorm(); prered = 0.; if (temp < fnorm) /* Computing 2nd power */ prered = 1. - ei_abs2(temp / fnorm); - /* compute the ratio of the actual to the predicted */ - /* reduction. */ - + /* compute the ratio of the actual to the predicted reduction. */ ratio = 0.; if (prered > 0.) ratio = actred / prered; /* update the step bound. */ - if (ratio < Scalar(.1)) { ncsuc = 0; ++ncfail; @@ -658,7 +586,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( } else { ncfail = 0; ++ncsuc; - if (ratio >= Scalar(.5) || ncsuc > 1) /* Computing MAX */ + if (ratio >= Scalar(.5) || ncsuc > 1) delta = std::max(delta, pnorm / Scalar(.5)); if (ei_abs(ratio - 1.) <= Scalar(.1)) { delta = pnorm / Scalar(.5); @@ -666,7 +594,6 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( } /* test for successful iteration. */ - if (ratio >= Scalar(1e-4)) { /* successful iteration. update x, fvec, and their norms. */ x = wa2; @@ -678,7 +605,6 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( } /* determine the progress of the iteration. */ - ++nslow1; if (actred >= Scalar(.001)) nslow1 = 0; @@ -688,12 +614,10 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( nslow2 = 0; /* test for convergence. */ - if (delta <= parameters.xtol * xnorm || fnorm == 0.) return RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ - if (nfev >= parameters.maxfev) return TooManyFunctionEvaluation; if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) @@ -703,35 +627,25 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( if (nslow1 == 10) return NotMakingProgressIterations; - /* criterion for recalculating jacobian approximation */ - /* by forward differences. */ - + /* criterion for recalculating jacobian. */ if (ncfail == 2) break; // leave inner loop and go for the next outer loop iteration /* calculate the rank one modification to the jacobian */ /* and update qtf if necessary. */ - - for (j = 0; j < n; ++j) { - sum = wa4.dot(fjac.col(j)); - wa2[j] = (sum - wa3[j]) / pnorm; - wa1[j] = diag[j] * (diag[j] * wa1[j] / pnorm); - if (ratio >= Scalar(1e-4)) - qtf[j] = sum; - } + wa1 = diag.cwiseProduct( diag.cwiseProduct(wa1)/pnorm ); + wa2 = fjac.transpose() * wa4; + if (ratio >= Scalar(1e-4)) + qtf = wa2; + wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); - /* end of the inner loop. */ - jeval = false; } - /* end of the outer loop. */ - return Running; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index 36ed962f1..18b0963b2 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -8,46 +8,45 @@ void ei_dogleg( Matrix< Scalar, Dynamic, 1 > &x) { /* Local variables */ - int i, j, k; + int i, j; Scalar sum, temp, alpha, bnorm; Scalar gnorm, qnorm; Scalar sgnorm; /* Function Body */ const Scalar epsmch = epsilon(); - const int n = diag.size(); - Matrix< Scalar, Dynamic, 1 > wa1(n), wa2(n); + const int n = qrfac.cols(); assert(n==qtb.size()); assert(n==x.size()); + assert(n==diag.size()); + Matrix< Scalar, Dynamic, 1 > wa1(n), wa2(n); - for (k = 0; k < n; ++k) { - j = n - k - 1; - sum = 0.; - for (i = j+1; i < n; ++i) { - sum += qrfac(j,i) * x[i]; - } + /* first, calculate the gauss-newton direction. */ + for (j = n-1; j >=0; --j) { temp = qrfac(j,j); if (temp == 0.) { - for (i = 0; i <= j; ++i) - temp = std::max(temp,ei_abs(qrfac(i,j))); - temp = epsmch * temp; + temp = epsmch * qrfac.col(j).head(j+1).maxCoeff(); if (temp == 0.) temp = epsmch; } - x[j] = (qtb[j] - sum) / temp; + if (j==n-1) + x[j] = qtb[j] / temp; + else + x[j] = (qtb[j] - qrfac.row(j).tail(n-j-1).dot(x.tail(n-j-1))) / temp; } /* test whether the gauss-newton direction is acceptable. */ - - wa1.fill(0.); wa2 = diag.cwiseProduct(x); qnorm = wa2.stableNorm(); if (qnorm <= delta) return; + // TODO : this path is not tested by Eigen unit tests + /* the gauss-newton direction is not acceptable. */ /* next, calculate the scaled gradient direction. */ + wa1.fill(0.); for (j = 0; j < n; ++j) { temp = qtb[j]; for (i = j; i < n; ++i) @@ -57,7 +56,6 @@ void ei_dogleg( /* calculate the norm of the scaled gradient and test for */ /* the special case in which the scaled gradient is zero. */ - gnorm = wa1.stableNorm(); sgnorm = 0.; alpha = delta / qnorm; @@ -66,8 +64,9 @@ void ei_dogleg( /* calculate the point along the scaled gradient */ /* at which the quadratic is minimized. */ - wa1.array() /= (diag*gnorm).array(); + // TODO : once unit tests cover this part,: + // wa2 = qrfac.template triangularView() * wa1; for (j = 0; j < n; ++j) { sum = 0.; for (i = j; i < n; ++i) { @@ -79,7 +78,6 @@ void ei_dogleg( sgnorm = gnorm / temp / temp; /* test whether the scaled gradient direction is acceptable. */ - alpha = 0.; if (sgnorm >= delta) goto algo_end; @@ -87,18 +85,14 @@ void ei_dogleg( /* the scaled gradient direction is not acceptable. */ /* finally, calculate the point along the dogleg */ /* at which the quadratic is minimized. */ - bnorm = qtb.stableNorm(); temp = bnorm / gnorm * (bnorm / qnorm) * (sgnorm / delta); - /* Computing 2nd power */ temp = temp - delta / qnorm * ei_abs2(sgnorm / delta) + ei_sqrt(ei_abs2(temp - delta / qnorm) + (1.-ei_abs2(delta / qnorm)) * (1.-ei_abs2(sgnorm / delta))); - /* Computing 2nd power */ alpha = delta / qnorm * (1. - ei_abs2(sgnorm / delta)) / temp; algo_end: /* form appropriate convex combination of the gauss-newton */ /* direction and the scaled gradient direction. */ - temp = (1.-alpha) * std::min(sgnorm,delta); x = temp * wa1 + alpha * x; } From 113995355b1063a8d2971f50df0df66c3721097d Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 08:42:48 +0100 Subject: [PATCH 018/109] get rid of ei_qform + lot of other cleaning, now that we do not depend on minpack qr factorization. --- .../HybridNonLinearSolver.h | 51 ++++------------ .../Eigen/src/NonLinearOptimization/qform.h | 60 ------------------- 2 files changed, 10 insertions(+), 101 deletions(-) delete mode 100644 unsupported/Eigen/src/NonLinearOptimization/qform.h diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index ee5b63c44..4b985db74 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -217,7 +217,7 @@ HybridNonLinearSolver::solveOneStep( const int mode ) { - int i, j; + int j; jeval = true; /* calculate the jacobian matrix. */ @@ -246,30 +246,15 @@ HybridNonLinearSolver::solveOneStep( /* compute the qr factorization of the jacobian. */ wa2 = fjac.colwise().blueNorm(); HouseholderQR qrfac(fjac); // no pivoting: - fjac = qrfac.matrixQR(); - wa1 = fjac.diagonal(); - fjac.diagonal() = qrfac.hCoeffs(); - // TODO : avoid this: - for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors - - /* form (q transpose)*fvec and store in qtf. */ - qtf = fvec; - for (j = 0; j < n; ++j) - if (fjac(j,j) != 0.) { - sum = 0.; - for (i = j; i < n; ++i) - sum += fjac(i,j) * qtf[i]; - temp = -sum / fjac(j,j); - for (i = j; i < n; ++i) - qtf[i] += fjac(i,j) * temp; - } /* copy the triangular factor of the qr factorization into r. */ R = qrfac.matrixQR(); - sing = wa1.cwiseAbs().minCoeff()==0.; /* accumulate the orthogonal factor in fjac. */ - ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); + fjac = qrfac.householderQ(); + + /* form (q transpose)*fvec and store in qtf. */ + qtf = fjac.transpose() * fvec; /* rescale if necessary. */ if (mode != 2) @@ -480,13 +465,12 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( const int mode ) { - int i, j; + int j; jeval = true; if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1; if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1; /* calculate the jacobian matrix. */ - if (ei_fdjac1(functor, x, fvec, fjac, parameters.nb_of_subdiagonals, parameters.nb_of_superdiagonals, parameters.epsfcn) <0) return UserAksed; nfev += std::min(parameters.nb_of_subdiagonals+parameters.nb_of_superdiagonals+ 1, n); @@ -512,30 +496,15 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* compute the qr factorization of the jacobian. */ wa2 = fjac.colwise().blueNorm(); HouseholderQR qrfac(fjac); // no pivoting: - fjac = qrfac.matrixQR(); - wa1 = fjac.diagonal(); - fjac.diagonal() = qrfac.hCoeffs(); - // TODO : avoid this: - for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors - - /* form (q transpose)*fvec and store in qtf. */ - qtf = fvec; - for (j = 0; j < n; ++j) - if (fjac(j,j) != 0.) { - sum = 0.; - for (i = j; i < n; ++i) - sum += fjac(i,j) * qtf[i]; - temp = -sum / fjac(j,j); - for (i = j; i < n; ++i) - qtf[i] += fjac(i,j) * temp; - } /* copy the triangular factor of the qr factorization into r. */ R = qrfac.matrixQR(); - sing = wa1.cwiseAbs().minCoeff()==0.; /* accumulate the orthogonal factor in fjac. */ - ei_qform(n, n, fjac.data(), fjac.rows(), wa1.data()); + fjac = qrfac.householderQ(); + + /* form (q transpose)*fvec and store in qtf. */ + qtf = fjac.transpose() * fvec; /* rescale if necessary. */ if (mode != 2) diff --git a/unsupported/Eigen/src/NonLinearOptimization/qform.h b/unsupported/Eigen/src/NonLinearOptimization/qform.h deleted file mode 100644 index 1c3e3e267..000000000 --- a/unsupported/Eigen/src/NonLinearOptimization/qform.h +++ /dev/null @@ -1,60 +0,0 @@ - -template -void ei_qform(int m, int n, Scalar *q, int - ldq, Scalar *wa) -{ - /* System generated locals */ - int q_dim1, q_offset; - - /* Local variables */ - int i, j, k, l; - Scalar sum, temp; - int minmn; - - /* Parameter adjustments */ - --wa; - q_dim1 = ldq; - q_offset = 1 + q_dim1 * 1; - q -= q_offset; - - /* Function Body */ - - /* zero out upper triangle of q in the first min(m,n) columns. */ - - minmn = std::min(m,n); - for (j = 2; j <= minmn; ++j) { - for (i = 1; i <= j-1; ++i) - q[i + j * q_dim1] = 0.; - } - - /* initialize remaining columns to those of the identity matrix. */ - - for (j = n+1; j <= m; ++j) { - for (i = 1; i <= m; ++i) - q[i + j * q_dim1] = 0.; - q[j + j * q_dim1] = 1.; - } - - /* accumulate q from its factored form. */ - - for (l = 1; l <= minmn; ++l) { - k = minmn - l + 1; - for (i = k; i <= m; ++i) { - wa[i] = q[i + k * q_dim1]; - q[i + k * q_dim1] = 0.; - } - q[k + k * q_dim1] = 1.; - if (wa[k] == 0.) - continue; - for (j = k; j <= m; ++j) { - sum = 0.; - for (i = k; i <= m; ++i) - sum += q[i + j * q_dim1] * wa[i]; - temp = sum / wa[k]; - for (i = k; i <= m; ++i) - q[i + j * q_dim1] -= temp * wa[i]; - } - } - -} - From d791b51112a0c1f129ff700142113e390cde0833 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 10:50:43 +0100 Subject: [PATCH 019/109] remove spaces --- .../HybridNonLinearSolver.h | 1 - .../LevenbergMarquardt.h | 43 ------------------- .../Eigen/src/NonLinearOptimization/lmpar.h | 25 ----------- 3 files changed, 69 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 4b985db74..cbf89b1c6 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -429,7 +429,6 @@ HybridNonLinearSolver::solveNumericalDiffInit( /* Function Body */ - nfev = 0; njev = 0; diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index b9e3c808e..0d6e051ca 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -207,7 +207,6 @@ LevenbergMarquardt::minimizeInit( njev = 0; /* check the input parameters for errors. */ - if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) return ImproperInputParameters; @@ -218,14 +217,12 @@ LevenbergMarquardt::minimizeInit( /* evaluate the function at the starting point */ /* and calculate its norm. */ - nfev = 1; if ( functor(x, fvec) < 0) return UserAsked; fnorm = fvec.stableNorm(); /* initialize levenberg-marquardt parameter and iteration counter. */ - par = 0.; iter = 1; @@ -242,7 +239,6 @@ LevenbergMarquardt::minimizeOneStep( int i, j, l; /* calculate the jacobian matrix. */ - int df_ret = functor.df(x, fjac); if (df_ret<0) return UserAsked; @@ -252,7 +248,6 @@ LevenbergMarquardt::minimizeOneStep( else njev++; /* compute the qr factorization of the jacobian. */ - wa2 = fjac.colwise().blueNorm(); ColPivHouseholderQR qrfac(fjac); fjac = qrfac.matrixQR(); @@ -264,7 +259,6 @@ LevenbergMarquardt::minimizeOneStep( /* on the first iteration and if mode is 1, scale according */ /* to the norms of the columns of the initial jacobian. */ - if (iter == 1) { if (mode != 2) for (j = 0; j < n; ++j) { @@ -275,7 +269,6 @@ LevenbergMarquardt::minimizeOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); xnorm = wa3.stableNorm(); delta = parameters.factor * xnorm; @@ -285,7 +278,6 @@ LevenbergMarquardt::minimizeOneStep( /* form (q transpose)*fvec and store the first n components in */ /* qtf. */ - #if 0 // find a way to only compute the first n items, we have m>>n here. wa4 = fvec; @@ -309,7 +301,6 @@ LevenbergMarquardt::minimizeOneStep( #endif /* compute the norm of the scaled gradient. */ - gnorm = 0.; if (fnorm != 0.) for (j = 0; j < n; ++j) { @@ -324,12 +315,10 @@ LevenbergMarquardt::minimizeOneStep( } /* test for convergence of the gradient norm. */ - if (gnorm <= parameters.gtol) return CosinusTooSmall; /* rescale if necessary. */ - if (mode != 2) /* Computing MAX */ diag = diag.cwiseMax(wa2); @@ -337,37 +326,31 @@ LevenbergMarquardt::minimizeOneStep( do { /* determine the levenberg-marquardt parameter. */ - ei_lmpar2(qrfac, diag, qtf, delta, par, wa1); /* store the direction p and x + p. calculate the norm of p. */ - wa1 = -wa1; wa2 = x + wa1; wa3 = diag.cwiseProduct(wa1); pnorm = wa3.stableNorm(); /* on the first iteration, adjust the initial step bound. */ - if (iter == 1) delta = std::min(delta,pnorm); /* evaluate the function at x + p and calculate its norm. */ - if ( functor(wa2, wa4) < 0) return UserAsked; ++nfev; fnorm1 = wa4.stableNorm(); /* compute the scaled actual reduction. */ - actred = -1.; if (Scalar(.1) * fnorm1 < fnorm) /* Computing 2nd power */ actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction and */ /* the scaled directional derivative. */ - wa3.fill(0.); for (j = 0; j < n; ++j) { l = ipvt[j]; @@ -383,13 +366,11 @@ LevenbergMarquardt::minimizeOneStep( /* compute the ratio of the actual to the predicted */ /* reduction. */ - ratio = 0.; if (prered != 0.) ratio = actred / prered; /* update the step bound. */ - if (ratio <= Scalar(.25)) { if (actred >= 0.) temp = Scalar(.5); @@ -406,7 +387,6 @@ LevenbergMarquardt::minimizeOneStep( } /* test for successful iteration. */ - if (ratio >= Scalar(1e-4)) { /* successful iteration. update x, fvec, and their norms. */ x = wa2; @@ -418,7 +398,6 @@ LevenbergMarquardt::minimizeOneStep( } /* tests for convergence. */ - if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) return RelativeErrorAndReductionTooSmall; if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) @@ -427,7 +406,6 @@ LevenbergMarquardt::minimizeOneStep( return RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ - if (nfev >= parameters.maxfev) return TooManyFunctionEvaluation; if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) @@ -489,7 +467,6 @@ LevenbergMarquardt::minimizeOptimumStorageInit( njev = 0; /* check the input parameters for errors. */ - if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) return ImproperInputParameters; @@ -500,14 +477,12 @@ LevenbergMarquardt::minimizeOptimumStorageInit( /* evaluate the function at the starting point */ /* and calculate its norm. */ - nfev = 1; if ( functor(x, fvec) < 0) return UserAsked; fnorm = fvec.stableNorm(); /* initialize levenberg-marquardt parameter and iteration counter. */ - par = 0.; iter = 1; @@ -529,7 +504,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* calculated one row at a time, while simultaneously */ /* forming (q transpose)*fvec and storing the first */ /* n components in qtf. */ - qtf.fill(0.); fjac.fill(0.); int rownb = 2; @@ -543,7 +517,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* if the jacobian is rank deficient, call qrfac to */ /* reorder its columns and update the components of qtf. */ - sing = false; for (j = 0; j < n; ++j) { if (fjac(j,j) == 0.) { @@ -578,7 +551,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* on the first iteration and if mode is 1, scale according */ /* to the norms of the columns of the initial jacobian. */ - if (iter == 1) { if (mode != 2) for (j = 0; j < n; ++j) { @@ -589,7 +561,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); xnorm = wa3.stableNorm(); delta = parameters.factor * xnorm; @@ -598,7 +569,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( } /* compute the norm of the scaled gradient. */ - gnorm = 0.; if (fnorm != 0.) for (j = 0; j < n; ++j) { @@ -613,12 +583,10 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( } /* test for convergence of the gradient norm. */ - if (gnorm <= parameters.gtol) return CosinusTooSmall; /* rescale if necessary. */ - if (mode != 2) /* Computing MAX */ diag = diag.cwiseMax(wa2); @@ -626,37 +594,31 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( do { /* determine the levenberg-marquardt parameter. */ - ei_lmpar(fjac, ipvt, diag, qtf, delta, par, wa1); /* store the direction p and x + p. calculate the norm of p. */ - wa1 = -wa1; wa2 = x + wa1; wa3 = diag.cwiseProduct(wa1); pnorm = wa3.stableNorm(); /* on the first iteration, adjust the initial step bound. */ - if (iter == 1) delta = std::min(delta,pnorm); /* evaluate the function at x + p and calculate its norm. */ - if ( functor(wa2, wa4) < 0) return UserAsked; ++nfev; fnorm1 = wa4.stableNorm(); /* compute the scaled actual reduction. */ - actred = -1.; if (Scalar(.1) * fnorm1 < fnorm) /* Computing 2nd power */ actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction and */ /* the scaled directional derivative. */ - wa3.fill(0.); for (j = 0; j < n; ++j) { l = ipvt[j]; @@ -672,13 +634,11 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* compute the ratio of the actual to the predicted */ /* reduction. */ - ratio = 0.; if (prered != 0.) ratio = actred / prered; /* update the step bound. */ - if (ratio <= Scalar(.25)) { if (actred >= 0.) temp = Scalar(.5); @@ -695,7 +655,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( } /* test for successful iteration. */ - if (ratio >= Scalar(1e-4)) { /* successful iteration. update x, fvec, and their norms. */ x = wa2; @@ -707,7 +666,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( } /* tests for convergence. */ - if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) return RelativeErrorAndReductionTooSmall; if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) @@ -716,7 +674,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( return RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ - if (nfev >= parameters.maxfev) return TooManyFunctionEvaluation; if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index 54c84960a..7f471f60e 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -30,7 +30,6 @@ void ei_lmpar( /* compute and store in x the gauss-newton direction. if the */ /* jacobian is rank-deficient, obtain a least squares solution. */ - int nsing = n-1; wa1 = qtb; for (j = 0; j < n; ++j) { @@ -52,7 +51,6 @@ void ei_lmpar( /* initialize the iteration counter. */ /* evaluate the function at the origin, and test */ /* for acceptance of the gauss-newton direction. */ - iter = 0; wa2 = diag.cwiseProduct(x); dxnorm = wa2.blueNorm(); @@ -65,7 +63,6 @@ void ei_lmpar( /* if the jacobian is not rank deficient, the newton */ /* step provides a lower bound, parl, for the zero of */ /* the function. otherwise set this bound to zero. */ - parl = 0.; if (nsing >= n-1) { for (j = 0; j < n; ++j) { @@ -85,7 +82,6 @@ void ei_lmpar( } /* calculate an upper bound, paru, for the zero of the function. */ - for (j = 0; j < n; ++j) wa1[j] = r.col(j).head(j+1).dot(qtb.head(j+1)) / diag[ipvt[j]]; @@ -96,22 +92,18 @@ void ei_lmpar( /* if the input par lies outside of the interval (parl,paru), */ /* set par to the closer endpoint. */ - par = std::max(par,parl); par = std::min(par,paru); if (par == 0.) par = gnorm / dxnorm; /* beginning of an iteration. */ - while (true) { ++iter; /* evaluate the function at the current value of par. */ - if (par == 0.) par = std::max(dwarf,Scalar(.001) * paru); /* Computing MAX */ - wa1 = ei_sqrt(par)* diag; Matrix< Scalar, Dynamic, 1 > sdiag(n); @@ -125,12 +117,10 @@ void ei_lmpar( /* if the function is small enough, accept the current value */ /* of par. also test for the exceptional cases where parl */ /* is zero or the number of iterations has reached 10. */ - if (ei_abs(fp) <= Scalar(0.1) * delta || (parl == 0. && fp <= temp && temp < 0.) || iter == 10) break; /* compute the newton correction. */ - for (j = 0; j < n; ++j) { l = ipvt[j]; wa1[j] = diag[l] * (wa2[l] / dxnorm); @@ -145,23 +135,19 @@ void ei_lmpar( parc = fp / delta / temp / temp; /* depending on the sign of the function, update parl or paru. */ - if (fp > 0.) parl = std::max(parl,par); if (fp < 0.) paru = std::min(paru,par); /* compute an improved estimate for par. */ - /* Computing MAX */ par = std::max(parl,par+parc); /* end of an iteration. */ - } /* termination. */ - if (iter == 0) par = 0.; return; @@ -198,7 +184,6 @@ void ei_lmpar2( /* compute and store in x the gauss-newton direction. if the */ /* jacobian is rank-deficient, obtain a least squares solution. */ - // const int rank = qr.nonzeroPivots(); // exactly double(0.) const int rank = qr.rank(); // use a threshold wa1 = qtb; wa1.segment(rank,n-rank).setZero(); @@ -209,7 +194,6 @@ void ei_lmpar2( /* initialize the iteration counter. */ /* evaluate the function at the origin, and test */ /* for acceptance of the gauss-newton direction. */ - iter = 0; wa2 = diag.cwiseProduct(x); dxnorm = wa2.blueNorm(); @@ -222,7 +206,6 @@ void ei_lmpar2( /* if the jacobian is not rank deficient, the newton */ /* step provides a lower bound, parl, for the zero of */ /* the function. otherwise set this bound to zero. */ - parl = 0.; if (rank==n) { wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2)/dxnorm; @@ -232,7 +215,6 @@ void ei_lmpar2( } /* calculate an upper bound, paru, for the zero of the function. */ - for (j = 0; j < n; ++j) wa1[j] = qr.matrixQR().col(j).head(j+1).dot(qtb.head(j+1)) / diag[qr.colsPermutation().indices()(j)]; @@ -243,23 +225,19 @@ void ei_lmpar2( /* if the input par lies outside of the interval (parl,paru), */ /* set par to the closer endpoint. */ - par = std::max(par,parl); par = std::min(par,paru); if (par == 0.) par = gnorm / dxnorm; /* beginning of an iteration. */ - Matrix< Scalar, Dynamic, Dynamic > s = qr.matrixQR(); while (true) { ++iter; /* evaluate the function at the current value of par. */ - if (par == 0.) par = std::max(dwarf,Scalar(.001) * paru); /* Computing MAX */ - wa1 = ei_sqrt(par)* diag; Matrix< Scalar, Dynamic, 1 > sdiag(n); @@ -273,12 +251,10 @@ void ei_lmpar2( /* if the function is small enough, accept the current value */ /* of par. also test for the exceptional cases where parl */ /* is zero or the number of iterations has reached 10. */ - if (ei_abs(fp) <= Scalar(0.1) * delta || (parl == 0. && fp <= temp && temp < 0.) || iter == 10) break; /* compute the newton correction. */ - wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2/dxnorm); for (j = 0; j < n; ++j) { wa1[j] /= sdiag[j]; @@ -290,7 +266,6 @@ void ei_lmpar2( parc = fp / delta / temp / temp; /* depending on the sign of the function, update parl or paru. */ - if (fp > 0.) parl = std::max(parl,par); if (fp < 0.) From 8a690299c678bfe476dd83b2e559055e7c7ca6f7 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 11:48:32 +0100 Subject: [PATCH 020/109] fix possible segfault --- unsupported/Eigen/src/NonLinearOptimization/r1updt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h index 71a704d24..08744ce39 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h @@ -3,7 +3,7 @@ template void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, Scalar *v, Scalar *w, bool *sing) { /* Local variables */ - int i, j, nm1; + int i, j=1, nm1; Scalar tan__; int nmj; Scalar cos__, sin__, tau, temp, cotan; From 69f11c08a125b2a6f2ba150d9b78f2b9ea04737b Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 12:09:52 +0100 Subject: [PATCH 021/109] more eigenization, dropped 'ipvt' in lm --- .../LevenbergMarquardt.h | 112 +++++------------- .../Eigen/src/NonLinearOptimization/lmpar.h | 1 - unsupported/test/NonLinearOptimization.cpp | 31 +++-- 3 files changed, 42 insertions(+), 102 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 0d6e051ca..1a3ca12ae 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -125,7 +125,7 @@ public: Parameters parameters; FVectorType fvec, qtf, diag; JacobianType fjac; - VectorXi ipvt; + PermutationMatrix permutation; int nfev; int njev; int iter; @@ -195,7 +195,6 @@ LevenbergMarquardt::minimizeInit( wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(m); fvec.resize(m); - ipvt.resize(n); fjac.resize(m, n); if (mode != 2) diag.resize(n); @@ -236,7 +235,7 @@ LevenbergMarquardt::minimizeOneStep( const int mode ) { - int i, j, l; + int j; /* calculate the jacobian matrix. */ int df_ret = functor.df(x, fjac); @@ -251,21 +250,14 @@ LevenbergMarquardt::minimizeOneStep( wa2 = fjac.colwise().blueNorm(); ColPivHouseholderQR qrfac(fjac); fjac = qrfac.matrixQR(); - wa1 = fjac.diagonal(); - fjac.diagonal() = qrfac.hCoeffs(); - ipvt = qrfac.colsPermutation().indices(); - // TODO : avoid this: - for(int i=0; i< fjac.cols(); i++) fjac.col(i).segment(i+1, fjac.rows()-i-1) *= fjac(i,i); // rescale vectors + permutation = qrfac.colsPermutation(); /* on the first iteration and if mode is 1, scale according */ /* to the norms of the columns of the initial jacobian. */ if (iter == 1) { if (mode != 2) - for (j = 0; j < n; ++j) { - diag[j] = wa2[j]; - if (wa2[j] == 0.) - diag[j] = 1.; - } + for (j = 0; j < n; ++j) + diag[j] = (wa2[j]==0.)? 1. : wa2[j]; /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ @@ -278,48 +270,23 @@ LevenbergMarquardt::minimizeOneStep( /* form (q transpose)*fvec and store the first n components in */ /* qtf. */ -#if 0 - // find a way to only compute the first n items, we have m>>n here. wa4 = fvec; wa4.applyOnTheLeft(qrfac.householderQ().adjoint()); - wa4 = wa4.head(n); - fjac.diagonal() = wa1; -#else - wa4 = fvec; - for (j = 0; j < n; ++j) { - if (fjac(j,j) != 0.) { - sum = 0.; - for (i = j; i < m; ++i) - sum += fjac(i,j) * wa4[i]; - temp = -sum / fjac(j,j); - for (i = j; i < m; ++i) - wa4[i] += fjac(i,j) * temp; - } - fjac(j,j) = wa1[j]; - qtf[j] = wa4[j]; - } -#endif + qtf = wa4.head(n); /* compute the norm of the scaled gradient. */ gnorm = 0.; if (fnorm != 0.) - for (j = 0; j < n; ++j) { - l = ipvt[j]; - if (wa2[l] != 0.) { - sum = 0.; - for (i = 0; i <= j; ++i) - sum += fjac(i,j) * (qtf[i] / fnorm); - /* Computing MAX */ - gnorm = std::max(gnorm, ei_abs(sum / wa2[l])); - } - } + for (j = 0; j < n; ++j) + if (wa2[permutation.indices()[j]] != 0.) + gnorm = std::max(gnorm, ei_abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]])); /* test for convergence of the gradient norm. */ if (gnorm <= parameters.gtol) return CosinusTooSmall; /* rescale if necessary. */ - if (mode != 2) /* Computing MAX */ + if (mode != 2) diag = diag.cwiseMax(wa2); /* beginning of the inner loop. */ @@ -346,21 +313,14 @@ LevenbergMarquardt::minimizeOneStep( /* compute the scaled actual reduction. */ actred = -1.; - if (Scalar(.1) * fnorm1 < fnorm) /* Computing 2nd power */ + if (Scalar(.1) * fnorm1 < fnorm) actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction and */ /* the scaled directional derivative. */ - wa3.fill(0.); - for (j = 0; j < n; ++j) { - l = ipvt[j]; - temp = wa1[l]; - for (i = 0; i <= j; ++i) - wa3[i] += fjac(i,j) * temp; - } + wa3 = fjac.template triangularView() * (qrfac.colsPermutation().inverse() *wa1); temp1 = ei_abs2(wa3.stableNorm() / fnorm); temp2 = ei_abs2(ei_sqrt(par) * pnorm / fnorm); - /* Computing 2nd power */ prered = temp1 + temp2 / Scalar(.5); dirder = -(temp1 + temp2); @@ -455,7 +415,6 @@ LevenbergMarquardt::minimizeOptimumStorageInit( wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(m); fvec.resize(m); - ipvt.resize(n); fjac.resize(m, n); if (mode != 2) diag.resize(n); @@ -497,7 +456,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( const int mode ) { - int i, j, l; + int i, j; bool sing; /* compute the qr factorization of the jacobian matrix */ @@ -519,20 +478,20 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* reorder its columns and update the components of qtf. */ sing = false; for (j = 0; j < n; ++j) { - if (fjac(j,j) == 0.) { + if (fjac(j,j) == 0.) sing = true; - } - ipvt[j] = j; wa2[j] = fjac.col(j).head(j).stableNorm(); } + permutation.setIdentity(n); if (sing) { wa2 = fjac.colwise().blueNorm(); - // TODO We have no unit test covering this branch.. untested + // TODO We have no unit test covering this code path, do not modify + // before it is carefully tested ColPivHouseholderQR qrfac(fjac); fjac = qrfac.matrixQR(); wa1 = fjac.diagonal(); fjac.diagonal() = qrfac.hCoeffs(); - ipvt = qrfac.colsPermutation().indices(); + permutation = qrfac.colsPermutation(); // TODO : avoid this: for(int ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors @@ -553,11 +512,8 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* to the norms of the columns of the initial jacobian. */ if (iter == 1) { if (mode != 2) - for (j = 0; j < n; ++j) { - diag[j] = wa2[j]; - if (wa2[j] == 0.) - diag[j] = 1.; - } + for (j = 0; j < n; ++j) + diag[j] = (wa2[j]==0.)? 1. : wa2[j]; /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ @@ -571,30 +527,23 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* compute the norm of the scaled gradient. */ gnorm = 0.; if (fnorm != 0.) - for (j = 0; j < n; ++j) { - l = ipvt[j]; - if (wa2[l] != 0.) { - sum = 0.; - for (i = 0; i <= j; ++i) - sum += fjac(i,j) * (qtf[i] / fnorm); - /* Computing MAX */ - gnorm = std::max(gnorm, ei_abs(sum / wa2[l])); - } - } + for (j = 0; j < n; ++j) + if (wa2[permutation.indices()[j]] != 0.) + gnorm = std::max(gnorm, ei_abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]])); /* test for convergence of the gradient norm. */ if (gnorm <= parameters.gtol) return CosinusTooSmall; /* rescale if necessary. */ - if (mode != 2) /* Computing MAX */ + if (mode != 2) diag = diag.cwiseMax(wa2); /* beginning of the inner loop. */ do { /* determine the levenberg-marquardt parameter. */ - ei_lmpar(fjac, ipvt, diag, qtf, delta, par, wa1); + ei_lmpar(fjac, permutation.indices(), diag, qtf, delta, par, wa1); /* store the direction p and x + p. calculate the norm of p. */ wa1 = -wa1; @@ -614,21 +563,14 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* compute the scaled actual reduction. */ actred = -1.; - if (Scalar(.1) * fnorm1 < fnorm) /* Computing 2nd power */ + if (Scalar(.1) * fnorm1 < fnorm) actred = 1. - ei_abs2(fnorm1 / fnorm); /* compute the scaled predicted reduction and */ /* the scaled directional derivative. */ - wa3.fill(0.); - for (j = 0; j < n; ++j) { - l = ipvt[j]; - temp = wa1[l]; - for (i = 0; i <= j; ++i) - wa3[i] += fjac(i,j) * temp; - } + wa3 = fjac.corner(TopLeft,n,n).template triangularView() * (permutation.inverse() * wa1); temp1 = ei_abs2(wa3.stableNorm() / fnorm); temp2 = ei_abs2(ei_sqrt(par) * pnorm / fnorm); - /* Computing 2nd power */ prered = temp1 + temp2 / Scalar(.5); dirder = -(temp1 + temp2); diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index 7f471f60e..cd4698d76 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -178,7 +178,6 @@ void ei_lmpar2( const int n = qr.matrixQR().cols(); assert(n==diag.size()); assert(n==qtb.size()); - assert(n==x.size()); Matrix< Scalar, Dynamic, 1 > wa1, wa2; diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index 39c897241..c8b0b55a1 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -216,7 +216,7 @@ void testLmder() // check covariance covfac = fnorm*fnorm/(m-n); - ei_covar(lm.fjac, lm.ipvt); // TODO : move this as a function of lm + ei_covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm MatrixXd cov_ref(n,n); cov_ref << @@ -605,7 +605,7 @@ void testLmdif() // check covariance covfac = fnorm*fnorm/(m-n); - ei_covar(lm.fjac, lm.ipvt); + ei_covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm MatrixXd cov_ref(n,n); cov_ref << @@ -1010,7 +1010,7 @@ void testNistLanczos1(void) VERIFY( 79 == lm.nfev); VERIFY( 72 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.429961002287e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.430899764097e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1031,7 +1031,7 @@ void testNistLanczos1(void) VERIFY( 9 == lm.nfev); VERIFY( 8 == lm.njev); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.43059335827267E-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428595533845e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02 ); VERIFY_IS_APPROX(x[1], 1.0000000001E+00 ); @@ -1171,8 +1171,8 @@ void testNistMGH10(void) // check return value VERIFY( 2 == info); - VERIFY( 281 == lm.nfev); - VERIFY( 248 == lm.njev); + VERIFY( 284 == lm.nfev); + VERIFY( 249 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01); // check x @@ -1188,7 +1188,7 @@ void testNistMGH10(void) info = lm.minimize(x); // check return value - VERIFY( 2 == info); + VERIFY( 3 == info); VERIFY( 126 == lm.nfev); VERIFY( 116 == lm.njev); // check norm^2 @@ -1270,7 +1270,7 @@ void testNistBoxBOD(void) // check return value VERIFY( 1 == info); - VERIFY( 17 == lm.nfev); + VERIFY( 15 == lm.nfev); VERIFY( 14 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03); @@ -1332,8 +1332,8 @@ void testNistMGH17(void) // check return value VERIFY( 2 == info); - VERIFY( 605 == lm.nfev); - VERIFY( 544 == lm.njev); + VERIFY( 602 == lm.nfev); + VERIFY( 545 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); // check x @@ -1419,15 +1419,15 @@ void testNistMGH09(void) // check return value VERIFY( 1 == info); - VERIFY( 486 == lm.nfev); - VERIFY( 377 == lm.njev); + VERIFY( 490 == lm.nfev); + VERIFY( 376 == lm.njev); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04); // check x VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01 - VERIFY_IS_APPROX(x[1], 0.1912649346); // should be 1.9128232873E-01 - VERIFY_IS_APPROX(x[2], 0.1230532308); // should be 1.2305650693E-01 - VERIFY_IS_APPROX(x[3], 0.1360542773); // should be 1.3606233068E-01 + VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01 + VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01 + VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01 /* * Second try @@ -1845,7 +1845,6 @@ void test_NonLinearOptimization() printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev); printf("fvec.squaredNorm() : %.13g\n", lm.fvec.squaredNorm()); - printf("fvec.squaredNorm() : %.32g\n", lm.fvec.squaredNorm()); std::cout << x << std::endl; std::cout.precision(9); std::cout << x[0] << std::endl; From 71f513e2503d12dbb8e61a80c62648d051138e13 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 13:08:29 +0100 Subject: [PATCH 022/109] forgot to commit this: qform.h is not used anymore --- unsupported/Eigen/NonLinearOptimization | 1 - 1 file changed, 1 deletion(-) diff --git a/unsupported/Eigen/NonLinearOptimization b/unsupported/Eigen/NonLinearOptimization index a239018b0..432d94d93 100644 --- a/unsupported/Eigen/NonLinearOptimization +++ b/unsupported/Eigen/NonLinearOptimization @@ -130,7 +130,6 @@ namespace Eigen { #include "src/NonLinearOptimization/r1mpyq.h" #include "src/NonLinearOptimization/rwupdt.h" #include "src/NonLinearOptimization/fdjac1.h" -#include "src/NonLinearOptimization/qform.h" #include "src/NonLinearOptimization/lmpar.h" #include "src/NonLinearOptimization/dogleg.h" #include "src/NonLinearOptimization/covar.h" From 55f328b26404a34885cb459cbb0106476a9e6184 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 13:20:24 +0100 Subject: [PATCH 023/109] misc cleaning --- .../Eigen/src/NonLinearOptimization/chkder.h | 13 ++- .../Eigen/src/NonLinearOptimization/covar.h | 6 +- .../Eigen/src/NonLinearOptimization/fdjac1.h | 10 +-- .../Eigen/src/NonLinearOptimization/qrsolv.h | 5 -- .../Eigen/src/NonLinearOptimization/r1mpyq.h | 11 ++- .../Eigen/src/NonLinearOptimization/rwupdt.h | 83 +++++++------------ 6 files changed, 48 insertions(+), 80 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/chkder.h b/unsupported/Eigen/src/NonLinearOptimization/chkder.h index d5fca9c62..21fd60a9d 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/chkder.h +++ b/unsupported/Eigen/src/NonLinearOptimization/chkder.h @@ -17,14 +17,13 @@ void ei_chkder( const Scalar epsf = chkder_factor * epsilon(); const Scalar epslog = chkder_log10e * ei_log(eps); Scalar temp; - int i,j; const int m = fvec.size(), n = x.size(); if (mode != 2) { + /* mode = 1. */ xp.resize(n); - /* mode = 1. */ - for (j = 0; j < n; ++j) { + for (int j = 0; j < n; ++j) { temp = eps * ei_abs(x[j]); if (temp == 0.) temp = eps; @@ -32,15 +31,15 @@ void ei_chkder( } } else { - /* mode = 2. */ + /* mode = 2. */ err.setZero(m); - for (j = 0; j < n; ++j) { + for (int j = 0; j < n; ++j) { temp = ei_abs(x[j]); if (temp == 0.) temp = 1.; err += temp * fjac.col(j); } - for (i = 0; i < m; ++i) { + for (int i = 0; i < m; ++i) { temp = 1.; if (fvec[i] != 0. && fvecp[i] != 0. && ei_abs(fvecp[i] - fvec[i]) >= epsf * ei_abs(fvec[i])) temp = eps * ei_abs((fvecp[i] - fvec[i]) / eps - err[i]) / (ei_abs(fvec[i]) + ei_abs(fvecp[i])); @@ -51,5 +50,5 @@ void ei_chkder( err[i] = 0.; } } -} /* chkder_ */ +} diff --git a/unsupported/Eigen/src/NonLinearOptimization/covar.h b/unsupported/Eigen/src/NonLinearOptimization/covar.h index 2e495cd7f..620a2d71a 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/covar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/covar.h @@ -1,5 +1,5 @@ - template +template void ei_covar( Matrix< Scalar, Dynamic, Dynamic > &r, const VectorXi &ipvt, @@ -17,7 +17,6 @@ void ei_covar( assert(ipvt.size()==n); /* form the inverse of r in the full upper triangle of r. */ - l = -1; for (k = 0; k < n; ++k) if (ei_abs(r(k,k)) > tolr) { @@ -33,7 +32,6 @@ void ei_covar( /* form the full upper triangle of the inverse of (r transpose)*r */ /* in the full upper triangle of r. */ - for (k = 0; k <= l; ++k) { for (j = 0; j <= k-1; ++j) { temp = r(j,k); @@ -47,7 +45,6 @@ void ei_covar( /* form the full lower triangle of the covariance matrix */ /* in the strict lower triangle of r and in wa. */ - for (j = 0; j < n; ++j) { jj = ipvt[j]; sing = j > l; @@ -64,7 +61,6 @@ void ei_covar( } /* symmetrize the covariance matrix in r. */ - for (j = 0; j < n; ++j) { for (i = 0; i <= j; ++i) r(i,j) = r(j,i); diff --git a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h index e9c8fa991..77c18fbeb 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h +++ b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h @@ -13,7 +13,7 @@ int ei_fdjac1( int i, j, k; Scalar eps, temp; int msum; - int iflag = 0; + int iflag; /* Function Body */ const Scalar epsmch = epsilon(); @@ -42,7 +42,7 @@ int ei_fdjac1( }else { /* computation of banded approximate jacobian. */ for (k = 0; k < msum; ++k) { - for (j = k; msum< 0 ? j > n: j < n; j += msum) { + for (j = k; (msum<0) ? (j>n): (j n: j < n; j += msum) { + for (j = k; (msum<0) ? (j>n): (j 1.) { cos__ = 1. / v[j]; @@ -40,7 +39,7 @@ void ei_r1mpyq(int m, int n, Scalar *a, int } } /* apply the second set of givens rotations to a. */ - for (j = 1; j <= nm1; ++j) { + for (j = 1; j <= n-1; ++j) { if (ei_abs(w[j]) > 1.) { cos__ = 1. / w[j]; sin__ = ei_sqrt(1. - ei_abs2(cos__)); @@ -56,5 +55,5 @@ void ei_r1mpyq(int m, int n, Scalar *a, int } } return; -} /* r1mpyq_ */ +} diff --git a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h index 6be292f6a..38d614ae0 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h @@ -8,7 +8,6 @@ void ei_rwupdt(int n, Scalar *r__, int ldr, int r_dim1, r_offset; /* Local variables */ - int i, j, jm1; Scalar tan__, temp, rowj, cotan; /* Parameter adjustments */ @@ -21,60 +20,40 @@ void ei_rwupdt(int n, Scalar *r__, int ldr, r__ -= r_offset; /* Function Body */ + for (int j = 1; j <= n; ++j) { + rowj = w[j]; - for (j = 1; j <= n; ++j) { - rowj = w[j]; - jm1 = j - 1; + /* apply the previous transformations to */ + /* r(i,j), i=1,2,...,j-1, and to w(j). */ + if (j-1>=1) + for (int i = 1; i <= j-1; ++i) { + temp = cos__[i] * r__[i + j * r_dim1] + sin__[i] * rowj; + rowj = -sin__[i] * r__[i + j * r_dim1] + cos__[i] * rowj; + r__[i + j * r_dim1] = temp; + } -/* apply the previous transformations to */ -/* r(i,j), i=1,2,...,j-1, and to w(j). */ + /* determine a givens rotation which eliminates w(j). */ + cos__[j] = 1.; + sin__[j] = 0.; + if (rowj != 0.) { + if (ei_abs(r__[j + j * r_dim1]) < ei_abs(rowj)) { + cotan = r__[j + j * r_dim1] / rowj; + sin__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); + cos__[j] = sin__[j] * cotan; + } + else { + tan__ = rowj / r__[j + j * r_dim1]; + cos__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); + sin__[j] = cos__[j] * tan__; + } - if (jm1 < 1) { - goto L20; - } - for (i = 1; i <= jm1; ++i) { - temp = cos__[i] * r__[i + j * r_dim1] + sin__[i] * rowj; - rowj = -sin__[i] * r__[i + j * r_dim1] + cos__[i] * rowj; - r__[i + j * r_dim1] = temp; -/* L10: */ - } -L20: - -/* determine a givens rotation which eliminates w(j). */ - - cos__[j] = 1.; - sin__[j] = 0.; - if (rowj == 0.) { - goto L50; - } - if (ei_abs(r__[j + j * r_dim1]) >= ei_abs(rowj)) - goto L30; - cotan = r__[j + j * r_dim1] / rowj; -/* Computing 2nd power */ - sin__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__[j] = sin__[j] * cotan; - goto L40; -L30: - tan__ = rowj / r__[j + j * r_dim1]; -/* Computing 2nd power */ - cos__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__[j] = cos__[j] * tan__; -L40: - -/* apply the current transformation to r(j,j), b(j), and alpha. */ - - r__[j + j * r_dim1] = cos__[j] * r__[j + j * r_dim1] + sin__[j] * - rowj; - temp = cos__[j] * b[j] + sin__[j] * *alpha; - *alpha = -sin__[j] * b[j] + cos__[j] * *alpha; - b[j] = temp; -L50: -/* L60: */ - ; + /* apply the current transformation to r(j,j), b(j), and alpha. */ + r__[j + j * r_dim1] = cos__[j] * r__[j + j * r_dim1] + sin__[j] * rowj; + temp = cos__[j] * b[j] + sin__[j] * *alpha; + *alpha = -sin__[j] * b[j] + cos__[j] * *alpha; + b[j] = temp; + } } return; - -/* last card of subroutine rwupdt. */ - -} /* rwupdt_ */ +} From c04a93df31c32912c81704535fc10849ac11f076 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Tue, 26 Jan 2010 14:08:52 +0100 Subject: [PATCH 024/109] clean r1mpyq: remove fortran leftovers --- .../HybridNonLinearSolver.h | 8 ++-- .../Eigen/src/NonLinearOptimization/r1mpyq.h | 40 +++++++------------ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index cbf89b1c6..e1d10bdcc 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -360,8 +360,8 @@ HybridNonLinearSolver::solveOneStep( /* compute the qr factorization of the updated jacobian. */ ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); - ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); - ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); + ei_r1mpyq(n, n, fjac.data(), wa2.data(), wa3.data()); + ei_r1mpyq(1, n, qtf.data(), wa2.data(), wa3.data()); jeval = false; } @@ -609,8 +609,8 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* compute the qr factorization of the updated jacobian. */ ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); - ei_r1mpyq(n, n, fjac.data(), fjac.rows(), wa2.data(), wa3.data()); - ei_r1mpyq(1, n, qtf.data(), 1, wa2.data(), wa3.data()); + ei_r1mpyq(n, n, fjac.data(), wa2.data(), wa3.data()); + ei_r1mpyq(1, n, qtf.data(), wa2.data(), wa3.data()); jeval = false; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h index 9134dc0b6..ac1feeffc 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h @@ -1,29 +1,19 @@ +// TODO : move this to GivensQR once there's such a thing in Eigen + template -void ei_r1mpyq(int m, int n, Scalar *a, int - lda, const Scalar *v, const Scalar *w) +void ei_r1mpyq(int m, int n, Scalar *a, const Scalar *v, const Scalar *w) { - /* System generated locals */ - int a_dim1, a_offset; - /* Local variables */ - int i, j, nmj; + int i, j; Scalar cos__=0., sin__=0., temp; - /* Parameter adjustments */ - --w; - --v; - a_dim1 = lda; - a_offset = 1 + a_dim1 * 1; - a -= a_offset; - /* Function Body */ if (n<=1) return; /* apply the first set of givens rotations to a. */ - for (nmj = 1; nmj <= n-1; ++nmj) { - j = n - nmj; + for (j = n-2; j>=0; --j) { if (ei_abs(v[j]) > 1.) { cos__ = 1. / v[j]; sin__ = ei_sqrt(1. - ei_abs2(cos__)); @@ -31,15 +21,14 @@ void ei_r1mpyq(int m, int n, Scalar *a, int sin__ = v[j]; cos__ = ei_sqrt(1. - ei_abs2(sin__)); } - for (i = 1; i <= m; ++i) { - temp = cos__ * a[i + j * a_dim1] - sin__ * a[i + n * a_dim1]; - a[i + n * a_dim1] = sin__ * a[i + j * a_dim1] + cos__ * a[ - i + n * a_dim1]; - a[i + j * a_dim1] = temp; + for (i = 0; i 1.) { cos__ = 1. / w[j]; sin__ = ei_sqrt(1. - ei_abs2(cos__)); @@ -47,11 +36,10 @@ void ei_r1mpyq(int m, int n, Scalar *a, int sin__ = w[j]; cos__ = ei_sqrt(1. - ei_abs2(sin__)); } - for (i = 1; i <= m; ++i) { - temp = cos__ * a[i + j * a_dim1] + sin__ * a[i + n * a_dim1]; - a[i + n * a_dim1] = -sin__ * a[i + j * a_dim1] + cos__ * a[ - i + n * a_dim1]; - a[i + j * a_dim1] = temp; + for (i = 0; i Date: Tue, 26 Jan 2010 17:40:55 +0100 Subject: [PATCH 025/109] use PlanarRotation<> instead of handmade givens rotation in cminpack code + cleaning. This results in some more memory being used, but not much. --- .../HybridNonLinearSolver.h | 16 ++- .../LevenbergMarquardt.h | 3 +- .../Eigen/src/NonLinearOptimization/r1mpyq.h | 43 ++----- .../Eigen/src/NonLinearOptimization/r1updt.h | 121 +++++++----------- .../Eigen/src/NonLinearOptimization/rwupdt.h | 42 ++---- 5 files changed, 78 insertions(+), 147 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index e1d10bdcc..539c58d72 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -218,6 +218,8 @@ HybridNonLinearSolver::solveOneStep( ) { int j; + std::vector > v_givens(n), w_givens(n); + jeval = true; /* calculate the jacobian matrix. */ @@ -359,9 +361,9 @@ HybridNonLinearSolver::solveOneStep( wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); - ei_r1mpyq(n, n, fjac.data(), wa2.data(), wa3.data()); - ei_r1mpyq(1, n, qtf.data(), wa2.data(), wa3.data()); + ei_r1updt(R, wa1.data(), v_givens, w_givens, wa2.data(), wa3.data(), &sing); + ei_r1mpyq(n, n, fjac.data(), v_givens, w_givens); + ei_r1mpyq(1, n, qtf.data(), v_givens, w_givens); jeval = false; } @@ -465,6 +467,8 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( ) { int j; + std::vector > v_givens(n), w_givens(n); + jeval = true; if (parameters.nb_of_subdiagonals<0) parameters.nb_of_subdiagonals= n-1; if (parameters.nb_of_superdiagonals<0) parameters.nb_of_superdiagonals= n-1; @@ -608,9 +612,9 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(n, n, R, wa1.data(), wa2.data(), wa3.data(), &sing); - ei_r1mpyq(n, n, fjac.data(), wa2.data(), wa3.data()); - ei_r1mpyq(1, n, qtf.data(), wa2.data(), wa3.data()); + ei_r1updt(R, wa1.data(), v_givens, w_givens, wa2.data(), wa3.data(), &sing); + ei_r1mpyq(n, n, fjac.data(), v_givens, w_givens); + ei_r1mpyq(1, n, qtf.data(), v_givens, w_givens); jeval = false; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 1a3ca12ae..adbb3c835 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -468,8 +468,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( int rownb = 2; for (i = 0; i < m; ++i) { if (functor.df(x, wa3, rownb) < 0) return UserAsked; - temp = fvec[i]; - ei_rwupdt(n, fjac.data(), fjac.rows(), wa3.data(), qtf.data(), &temp, wa1.data(), wa2.data()); + ei_rwupdt(n, fjac.data(), fjac.rows(), wa3.data(), qtf.data(), fvec[i]); ++rownb; } ++njev; diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h index ac1feeffc..855cb7a1b 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h @@ -2,46 +2,21 @@ // TODO : move this to GivensQR once there's such a thing in Eigen template -void ei_r1mpyq(int m, int n, Scalar *a, const Scalar *v, const Scalar *w) +void ei_r1mpyq(int m, int n, Scalar *a, const std::vector > &v_givens, const std::vector > &w_givens) { - /* Local variables */ - int i, j; - Scalar cos__=0., sin__=0., temp; - - /* Function Body */ - if (n<=1) - return; - /* apply the first set of givens rotations to a. */ - for (j = n-2; j>=0; --j) { - if (ei_abs(v[j]) > 1.) { - cos__ = 1. / v[j]; - sin__ = ei_sqrt(1. - ei_abs2(cos__)); - } else { - sin__ = v[j]; - cos__ = ei_sqrt(1. - ei_abs2(sin__)); - } - for (i = 0; i=0; --j) + for (int i = 0; i 1.) { - cos__ = 1. / w[j]; - sin__ = ei_sqrt(1. - ei_abs2(cos__)); - } else { - sin__ = w[j]; - cos__ = ei_sqrt(1. - ei_abs2(sin__)); - } - for (i = 0; i -void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, Scalar *v, Scalar *w, bool *sing) +void ei_r1updt(Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, + std::vector > &v_givens, + std::vector > &w_givens, + Scalar *v, Scalar *w, bool *sing) { /* Local variables */ - int i, j=1, nm1; - Scalar tan__; - int nmj; - Scalar cos__, sin__, tau, temp, cotan; + const int m = s.rows(); + const int n = s.cols(); + int i, j=1; + Scalar temp; + PlanarRotation givens; // ei_r1updt had a broader usecase, but we dont use it here. And, more // importantly, we can not test it. @@ -17,52 +21,31 @@ void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar --u; --v; - /* Function Body */ - const Scalar giant = std::numeric_limits::max(); - /* move the nontrivial part of the last column of s into w. */ w[n] = s(n-1,n-1); /* rotate the vector v into a multiple of the n-th unit vector */ /* in such a way that a spike is introduced into w. */ - nm1 = n - 1; - if (nm1 >= 1) - for (nmj = 1; nmj <= nm1; ++nmj) { - j = n - nmj; - w[j] = 0.; - if (v[j] != 0.) { - /* determine a givens rotation which eliminates the */ - /* j-th element of v. */ - if (ei_abs(v[n]) < ei_abs(v[j])) { - cotan = v[n] / v[j]; - /* Computing 2nd power */ - sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__ = sin__ * cotan; - tau = 1.; - if (ei_abs(cos__) * giant > 1.) { - tau = 1. / cos__; - } - } else { - tan__ = v[j] / v[n]; - /* Computing 2nd power */ - cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__ = cos__ * tan__; - tau = sin__; - } + for (j=n-1; j>=1; --j) { + w[j] = 0.; + if (v[j] != 0.) { + /* determine a givens rotation which eliminates the */ + /* j-th element of v. */ + givens.makeGivens(-v[n], v[j]); - /* apply the transformation to v and store the information */ - /* necessary to recover the givens rotation. */ - v[n] = sin__ * v[j] + cos__ * v[n]; - v[j] = tau; + /* apply the transformation to v and store the information */ + /* necessary to recover the givens rotation. */ + v[n] = givens.s() * v[j] + givens.c() * v[n]; + v_givens[j-1] = givens; - /* apply the transformation to s and extend the spike in w. */ - for (i = j; i <= m; ++i) { - temp = cos__ * s(j-1,i-1) - sin__ * w[i]; - w[i] = sin__ * s(j-1,i-1) + cos__ * w[i]; - s(j-1,i-1) = temp; - } + /* apply the transformation to s and extend the spike in w. */ + for (i = j; i <= m; ++i) { + temp = givens.c() * s(j-1,i-1) - givens.s() * w[i]; + w[i] = givens.s() * s(j-1,i-1) + givens.c() * w[i]; + s(j-1,i-1) = temp; } } + } /* add the spike from the rank 1 update to w. */ for (i = 1; i <= m; ++i) @@ -70,45 +53,29 @@ void ei_r1updt(int m, int n, Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar /* eliminate the spike. */ *sing = false; - if (nm1 >= 1) - for (j = 1; j <= nm1; ++j) { - if (w[j] != 0.) { - /* determine a givens rotation which eliminates the */ - /* j-th element of the spike. */ - if (ei_abs(s(j-1,j-1)) < ei_abs(w[j])) { - cotan = s(j-1,j-1) / w[j]; - /* Computing 2nd power */ - sin__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__ = sin__ * cotan; - tau = 1.; - if (ei_abs(cos__) * giant > 1.) { - tau = 1. / cos__; - } - } else { - tan__ = w[j] / s(j-1,j-1); - /* Computing 2nd power */ - cos__ = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__ = cos__ * tan__; - tau = sin__; - } + for (j = 1; j <= n-1; ++j) { + if (w[j] != 0.) { + /* determine a givens rotation which eliminates the */ + /* j-th element of the spike. */ + givens.makeGivens(-s(j-1,j-1), w[j]); - /* apply the transformation to s and reduce the spike in w. */ - for (i = j; i <= m; ++i) { - temp = cos__ * s(j-1,i-1) + sin__ * w[i]; - w[i] = -sin__ * s(j-1,i-1) + cos__ * w[i]; - s(j-1,i-1) = temp; - } - - /* store the information necessary to recover the */ - /* givens rotation. */ - w[j] = tau; + /* apply the transformation to s and reduce the spike in w. */ + for (i = j; i <= m; ++i) { + temp = givens.c() * s(j-1,i-1) + givens.s() * w[i]; + w[i] = -givens.s() * s(j-1,i-1) + givens.c() * w[i]; + s(j-1,i-1) = temp; } - /* test for zero diagonal elements in the output s. */ - if (s(j-1,j-1) == 0.) { - *sing = true; - } + /* store the information necessary to recover the */ + /* givens rotation. */ + w_givens[j-1] = givens; } + + /* test for zero diagonal elements in the output s. */ + if (s(j-1,j-1) == 0.) { + *sing = true; + } + } /* move w back into the last column of the output s. */ s(n-1,n-1) = w[n]; diff --git a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h index 38d614ae0..38676e720 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h @@ -1,18 +1,15 @@ -template -void ei_rwupdt(int n, Scalar *r__, int ldr, - const Scalar *w, Scalar *b, Scalar *alpha, Scalar *cos__, - Scalar *sin__) + template +void ei_rwupdt(int n, Scalar *r__, int ldr, const Scalar *w, Scalar *b, Scalar alpha) { + std::vector > givens(n); /* System generated locals */ int r_dim1, r_offset; /* Local variables */ - Scalar tan__, temp, rowj, cotan; + Scalar temp, rowj; /* Parameter adjustments */ - --sin__; - --cos__; --b; --w; r_dim1 = ldr; @@ -23,34 +20,23 @@ void ei_rwupdt(int n, Scalar *r__, int ldr, for (int j = 1; j <= n; ++j) { rowj = w[j]; - /* apply the previous transformations to */ - /* r(i,j), i=1,2,...,j-1, and to w(j). */ + /* apply the previous transformations to */ + /* r(i,j), i=1,2,...,j-1, and to w(j). */ if (j-1>=1) for (int i = 1; i <= j-1; ++i) { - temp = cos__[i] * r__[i + j * r_dim1] + sin__[i] * rowj; - rowj = -sin__[i] * r__[i + j * r_dim1] + cos__[i] * rowj; + temp = givens[i-1].c() * r__[i + j * r_dim1] + givens[i-1].s() * rowj; + rowj = -givens[i-1].s() * r__[i + j * r_dim1] + givens[i-1].c() * rowj; r__[i + j * r_dim1] = temp; } - /* determine a givens rotation which eliminates w(j). */ - cos__[j] = 1.; - sin__[j] = 0.; + /* determine a givens rotation which eliminates w(j). */ if (rowj != 0.) { - if (ei_abs(r__[j + j * r_dim1]) < ei_abs(rowj)) { - cotan = r__[j + j * r_dim1] / rowj; - sin__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(cotan)); - cos__[j] = sin__[j] * cotan; - } - else { - tan__ = rowj / r__[j + j * r_dim1]; - cos__[j] = Scalar(.5) / ei_sqrt(Scalar(0.25) + Scalar(0.25) * ei_abs2(tan__)); - sin__[j] = cos__[j] * tan__; - } + givens[j-1].makeGivens(-r__[j + j * r_dim1], rowj); - /* apply the current transformation to r(j,j), b(j), and alpha. */ - r__[j + j * r_dim1] = cos__[j] * r__[j + j * r_dim1] + sin__[j] * rowj; - temp = cos__[j] * b[j] + sin__[j] * *alpha; - *alpha = -sin__[j] * b[j] + cos__[j] * *alpha; + /* apply the current transformation to r(j,j), b(j), and alpha. */ + r__[j + j * r_dim1] = givens[j-1].c() * r__[j + j * r_dim1] + givens[j-1].s() * rowj; + temp = givens[j-1].c() * b[j] + givens[j-1].s() * alpha; + alpha = -givens[j-1].s() * b[j] + givens[j-1].c() * alpha; b[j] = temp; } } From 4365a48748b3aeb6c15178b8471b1a5a8e0e9802 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 26 Jan 2010 19:42:17 +0100 Subject: [PATCH 026/109] Added an ei_linspaced_op to create linearly spaced vectors. Added setLinSpaced/LinSpaced functionality to DenseBase. Improved vectorized assignment - overcomes MSVC optimization issues. CwiseNullaryOp is now requiring functors to offer 1D and 2D operators. Adapted existing functors to the new CwiseNullaryOp requirements. Added ei_plset to create packages as [a, a+1, ..., a+size]. Added more nullaray unit tests. --- Eigen/src/Array/Random.h | 2 +- Eigen/src/Core/Assign.h | 33 +++++++++-- Eigen/src/Core/CwiseNullaryOp.h | 74 +++++++++++++++++++++--- Eigen/src/Core/DenseBase.h | 15 ++++- Eigen/src/Core/Functors.h | 71 ++++++++++++++++++++++- Eigen/src/Core/GenericPacketMath.h | 4 ++ Eigen/src/Core/Transpose.h | 2 +- Eigen/src/Core/arch/SSE/PacketMath.h | 4 ++ Eigen/src/Core/util/Constants.h | 5 ++ doc/snippets/DenseBase_LinSpaced.cpp | 2 + doc/snippets/DenseBase_LinSpaced_seq.cpp | 2 + doc/snippets/DenseBase_setLinSpaced.cpp | 3 + test/nullary.cpp | 54 +++++++++++++++++ 13 files changed, 252 insertions(+), 19 deletions(-) create mode 100644 doc/snippets/DenseBase_LinSpaced.cpp create mode 100644 doc/snippets/DenseBase_LinSpaced_seq.cpp create mode 100644 doc/snippets/DenseBase_setLinSpaced.cpp diff --git a/Eigen/src/Array/Random.h b/Eigen/src/Array/Random.h index 97ca0fba3..e1f4aa7ca 100644 --- a/Eigen/src/Array/Random.h +++ b/Eigen/src/Array/Random.h @@ -27,7 +27,7 @@ template struct ei_scalar_random_op { EIGEN_EMPTY_STRUCT_CTOR(ei_scalar_random_op) - inline const Scalar operator() (int, int) const { return ei_random(); } + inline const Scalar operator() (int, int = 0) const { return ei_random(); } }; template struct ei_functor_traits > diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index e5c17b3f4..41653098f 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -378,6 +378,31 @@ struct ei_assign_impl +struct ei_unaligned_assign_impl +{ + template + static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, int start, int end) {} +}; + +template <> +struct ei_unaligned_assign_impl +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. +#ifdef _MSC_VER + template + static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, int start, int end) +#else + template + static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, int start, int end) +#endif + { + for (int index = start; index < end; ++index) + dst.copyCoeff(index, src); + } +}; + template struct ei_assign_impl { @@ -389,16 +414,14 @@ struct ei_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); + for(int index = alignedStart; index < alignedEnd; index += packetSize) { dst.template copyPacket::SrcAlignment>(index, src); } - for(int index = alignedEnd; index < size; ++index) - dst.copyCoeff(index, src); + ei_unaligned_assign_impl<>::run(src,dst,alignedEnd,size); } }; diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index c5d5cd97c..f4dd0b695 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -80,23 +80,20 @@ class CwiseNullaryOp : ei_no_assignment_operator, } template - EIGEN_STRONG_INLINE PacketScalar packet(int, int) const + EIGEN_STRONG_INLINE PacketScalar packet(int row, int col) const { - return m_functor.packetOp(); + return m_functor.packetOp(row, col); } EIGEN_STRONG_INLINE const Scalar coeff(int index) const { - if(RowsAtCompileTime == 1) - return m_functor(0, index); - else - return m_functor(index, 0); + return m_functor(index); } template - EIGEN_STRONG_INLINE PacketScalar packet(int) const + EIGEN_STRONG_INLINE PacketScalar packet(int index) const { - return m_functor.packetOp(); + return m_functor.packetOp(index); } protected: @@ -228,6 +225,49 @@ DenseBase::Constant(const Scalar& value) return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, ei_scalar_constant_op(value)); } +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * This particular version of LinSpaced() uses sequential access, i.e. vector access is + * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization + * and yields faster code than the random access version. + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced_seq.cpp + * Output: \verbinclude DenseBase_LinSpaced_seq.out + * + * \sa setLinSpaced(Scalar,Scalar,int), LinSpaced(Scalar,Scalar,int), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +DenseBase::LinSpaced(Sequential_t, Scalar low, Scalar high, int size) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return NullaryExpr(size, ei_linspaced_op(low,high,size)); +} + +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced.cpp + * Output: \verbinclude DenseBase_LinSpaced.out + * + * \sa setLinSpaced(Scalar,Scalar,int), LinSpaced(Sequential_t,Scalar,Scalar,int), CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(Scalar low, Scalar high, int size) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return NullaryExpr(size, ei_linspaced_op(low,high,size)); +} + /** \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ template bool DenseBase::isApproxToConstant @@ -305,6 +345,24 @@ DenseStorageBase::setConstant(int rows, int cols, const return setConstant(value); } +/** + * \brief Sets a linearly space vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * + * \only_for_vectors + * + * Example: \include DenseBase_setLinSpaced.cpp + * Output: \verbinclude DenseBase_setLinSpaced.out + * + * \sa CwiseNullaryOp + */ +template +EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Scalar low, Scalar high, int size) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return derived() = Derived::NullaryExpr(size, ei_linspaced_op(low,high,size)); +} // zero: diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 8ea0f3ddf..e0a3a04af 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -192,11 +192,15 @@ template class DenseBase /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Derived> ConstantReturnType; + /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ + typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; + /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ + typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, ei_traits::ColsAtCompileTime, 1> EigenvaluesReturnType; - /** \internal expression tyepe of a column */ + /** \internal expression type of a column */ typedef Block::RowsAtCompileTime, 1> ColXpr; - /** \internal expression tyepe of a column */ + /** \internal expression type of a column */ typedef Block::ColsAtCompileTime> RowXpr; #endif // not EIGEN_PARSED_BY_DOXYGEN @@ -343,6 +347,11 @@ template class DenseBase static const ConstantReturnType Constant(const Scalar& value); + static const SequentialLinSpacedReturnType + LinSpaced(Sequential_t, Scalar low, Scalar high, int size); + static const RandomAccessLinSpacedReturnType + LinSpaced(Scalar low, Scalar high, int size); + template static const CwiseNullaryOp NullaryExpr(int rows, int cols, const CustomNullaryOp& func); @@ -362,11 +371,11 @@ template class DenseBase void fill(const Scalar& value); Derived& setConstant(const Scalar& value); + Derived& setLinSpaced(Scalar low, Scalar high, int size); Derived& setZero(); Derived& setOnes(); Derived& setRandom(); - template bool isApprox(const DenseBase& other, RealScalar prec = dummy_precision()) const; diff --git a/Eigen/src/Core/Functors.h b/Eigen/src/Core/Functors.h index aa3eba5cc..31d0cff70 100644 --- a/Eigen/src/Core/Functors.h +++ b/Eigen/src/Core/Functors.h @@ -437,7 +437,7 @@ struct ei_scalar_constant_op { EIGEN_STRONG_INLINE ei_scalar_constant_op(const ei_scalar_constant_op& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE ei_scalar_constant_op(const Scalar& other) : m_other(other) { } EIGEN_STRONG_INLINE const Scalar operator() (int, int = 0) const { return m_other; } - EIGEN_STRONG_INLINE const PacketScalar packetOp() const { return ei_pset1(m_other); } + EIGEN_STRONG_INLINE const PacketScalar packetOp(int, int = 0) const { return ei_pset1(m_other); } const Scalar m_other; }; template @@ -452,6 +452,75 @@ template struct ei_functor_traits > { enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; +template struct ei_linspaced_op_impl; + +// linear access for packet ops: +// 1) initialization +// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) +// 2) each step +// base += [size*step, ..., size*step] +template +struct ei_linspaced_op_impl +{ + typedef typename ei_packet_traits::type PacketScalar; + + ei_linspaced_op_impl(Scalar low, Scalar step) : + m_low(low), m_step(step), + m_packetStep(ei_pset1(ei_packet_traits::size*step)), + m_base(ei_padd(ei_pset1(low),ei_pmul(ei_pset1(step),ei_plset(-ei_packet_traits::size)))) {} + + EIGEN_STRONG_INLINE const Scalar operator() (int i) const { return m_low+i*m_step; } + EIGEN_STRONG_INLINE const PacketScalar packetOp(int) const { return m_base = ei_padd(m_base,m_packetStep); } + + const Scalar m_low; + const Scalar m_step; + const PacketScalar m_packetStep; + mutable PacketScalar m_base; +}; + +// random access for packet ops: +// 1) each step +// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) +template +struct ei_linspaced_op_impl +{ + typedef typename ei_packet_traits::type PacketScalar; + + ei_linspaced_op_impl(Scalar low, Scalar step) : + m_low(low), m_step(step), + m_lowPacket(ei_pset1(m_low)), m_stepPacket(ei_pset1(m_step)), m_interPacket(ei_plset(0)) {} + + EIGEN_STRONG_INLINE const Scalar operator() (int i) const { return m_low+i*m_step; } + EIGEN_STRONG_INLINE const PacketScalar packetOp(int i) const + { return ei_padd(m_lowPacket, ei_pmul(m_stepPacket, ei_padd(ei_pset1(i),m_interPacket))); } + + const Scalar m_low; + const Scalar m_step; + const PacketScalar m_lowPacket; + const PacketScalar m_stepPacket; + const PacketScalar m_interPacket; +}; + +// ----- Linspace functor ---------------------------------------------------------------- + +// Forward declaration (we default to random access which does not really give +// us a speed gain when using packet access but it allows to use the functor in +// nested expressions). +template struct ei_linspaced_op; +template struct ei_functor_traits< ei_linspaced_op > +{ enum { Cost = 1, PacketAccess = ei_packet_traits::size>1, IsRepeatable = true }; }; +template struct ei_linspaced_op +{ + typedef typename ei_packet_traits::type PacketScalar; + ei_linspaced_op(Scalar low, Scalar high, int num_steps) : impl(low, (high-low)/(num_steps-1)) {} + EIGEN_STRONG_INLINE const Scalar operator() (int i, int = 0) const { return impl(i); } + EIGEN_STRONG_INLINE const PacketScalar packetOp(int i, int = 0) const { return impl.packetOp(i); } + // This proxy object handles the actual required temporaries, the different + // implementations (random vs. sequential access) as well as the piping + // correct piping to size 2/4 packet operations. + const ei_linspaced_op_impl impl; +}; + // allow to add new functors and specializations of ei_functor_traits from outside Eigen. // this macro is really needed because ei_functor_traits must be specialized after it is declared but before it is used... #ifdef EIGEN_FUNCTORS_PLUGIN diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index ae1720eca..08981f89d 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h @@ -157,6 +157,10 @@ ei_ploadu(const Scalar* from) { return *from; } template inline typename ei_packet_traits::type ei_pset1(const Scalar& a) { return a; } +/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ +template inline typename ei_packet_traits::type +ei_plset(const Scalar& a) { return a; } + /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ template inline void ei_pstore(Scalar* to, const Packet& from) { (*to) = from; } diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 1113792fd..143b39033 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -63,7 +63,7 @@ template class Transpose public: typedef typename TransposeImpl::StorageType>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) + EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) inline Transpose(const MatrixType& matrix) : m_matrix(matrix) {} diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index f65801137..a5a56f759 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -91,6 +91,10 @@ template<> EIGEN_STRONG_INLINE Packet2d ei_pset1(const double& from) { r #endif template<> EIGEN_STRONG_INLINE Packet4i ei_pset1(const int& from) { return _mm_set1_epi32(from); } +template<> EIGEN_STRONG_INLINE Packet4f ei_plset(const float& a) { return _mm_add_ps(ei_pset1(a), _mm_set_ps(3,2,1,0)); } +template<> EIGEN_STRONG_INLINE Packet2d ei_plset(const double& a) { return _mm_add_pd(ei_pset1(a),_mm_set_pd(1,0)); } +template<> EIGEN_STRONG_INLINE Packet4i ei_plset(const int& a) { return _mm_add_epi32(ei_pset1(a),_mm_set_epi32(3,2,1,0)); } + template<> EIGEN_STRONG_INLINE Packet4f ei_padd(const Packet4f& a, const Packet4f& b) { return _mm_add_ps(a,b); } template<> EIGEN_STRONG_INLINE Packet2d ei_padd(const Packet2d& a, const Packet2d& b) { return _mm_add_pd(a,b); } template<> EIGEN_STRONG_INLINE Packet4i ei_padd(const Packet4i& a, const Packet4i& b) { return _mm_add_epi32(a,b); } diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 01c1aeb2f..6ae103e66 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -224,6 +224,11 @@ namespace { EIGEN_UNUSED NoChange_t NoChange; } +struct Sequential_t {}; +namespace { + EIGEN_UNUSED Sequential_t Sequential; +} + struct Default_t {}; namespace { EIGEN_UNUSED Default_t Default; diff --git a/doc/snippets/DenseBase_LinSpaced.cpp b/doc/snippets/DenseBase_LinSpaced.cpp new file mode 100644 index 000000000..540709adc --- /dev/null +++ b/doc/snippets/DenseBase_LinSpaced.cpp @@ -0,0 +1,2 @@ +cout << VectorXi::LinSpaced(7,10,4) << endl; +cout << VectorXd::LinSpaced(0.0,1.0,5) << endl; diff --git a/doc/snippets/DenseBase_LinSpaced_seq.cpp b/doc/snippets/DenseBase_LinSpaced_seq.cpp new file mode 100644 index 000000000..73873c4e9 --- /dev/null +++ b/doc/snippets/DenseBase_LinSpaced_seq.cpp @@ -0,0 +1,2 @@ +cout << VectorXi::LinSpaced(Sequential,7,10,4).transpose() << endl; +cout << VectorXd::LinSpaced(Sequential,0.0,1.0,5).transpose() << endl; diff --git a/doc/snippets/DenseBase_setLinSpaced.cpp b/doc/snippets/DenseBase_setLinSpaced.cpp new file mode 100644 index 000000000..a8ea73407 --- /dev/null +++ b/doc/snippets/DenseBase_setLinSpaced.cpp @@ -0,0 +1,3 @@ +VectorXf v; +v.setLinSpaced(0.5f,1.5f,5).transpose(); +cout << v << endl; diff --git a/test/nullary.cpp b/test/nullary.cpp index a7f6c60a7..240365529 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -46,6 +46,54 @@ bool equalsIdentity(const MatrixType& A) return offDiagOK && diagOK; } +template +void testVectorType(const VectorType& base) +{ + typedef typename ei_traits::Scalar Scalar; + Scalar low = ei_random(-500,500); + Scalar high = ei_random(-500,500); + if (low>high) std::swap(low,high); + const int size = base.size(); + const Scalar step = (high-low)/(size-1); + + // check whether the result yields what we expect it to do + VectorType m(base); + m.setLinSpaced(low,high,size); + + VectorType n(size); + for (int i=0; i::epsilon()*10e3 ); + + // random access version + m = VectorType::LinSpaced(low,high,size); + VERIFY( (m-n).norm() < std::numeric_limits::epsilon()*10e3 ); + + // These guys sometimes fail! This is not good. Any ideas how to fix them!? + //VERIFY( m(m.size()-1) == high ); + //VERIFY( m(0) == low ); + + // sequential access version + m = VectorType::LinSpaced(Sequential,low,high,size); + VERIFY( (m-n).norm() < std::numeric_limits::epsilon()*10e3 ); + + // These guys sometimes fail! This is not good. Any ideas how to fix them!? + //VERIFY( m(m.size()-1) == high ); + //VERIFY( m(0) == low ); + + // check whether everything works with row and col major vectors + Matrix row_vector(size); + Matrix col_vector(size); + row_vector.setLinSpaced(low,high,size); + col_vector.setLinSpaced(low,high,size); + VERIFY( (row_vector-col_vector.transpose()).norm() < 1e-10 ); + + Matrix size_changer(size+50); + size_changer.setLinSpaced(low,high,size); + VERIFY( size_changer.size() == size ); +} + template void testMatrixType(const MatrixType& m) { @@ -63,4 +111,10 @@ void test_nullary() CALL_SUBTEST_1( testMatrixType(Matrix2d()) ); CALL_SUBTEST_2( testMatrixType(MatrixXcf(50,50)) ); CALL_SUBTEST_3( testMatrixType(MatrixXf(5,7)) ); + CALL_SUBTEST_4( testVectorType(VectorXd(51)) ); + CALL_SUBTEST_5( testVectorType(VectorXd(41)) ); + CALL_SUBTEST_6( testVectorType(Vector3d()) ); + CALL_SUBTEST_7( testVectorType(VectorXf(51)) ); + CALL_SUBTEST_8( testVectorType(VectorXf(41)) ); + CALL_SUBTEST_9( testVectorType(Vector3f()) ); } From e97529c2e3cf5006ff9252d34ae6ae5bc010c159 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Wed, 27 Jan 2010 08:14:50 +0100 Subject: [PATCH 027/109] doc : update code, mention examples --- unsupported/Eigen/NonLinearOptimization | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/unsupported/Eigen/NonLinearOptimization b/unsupported/Eigen/NonLinearOptimization index 432d94d93..8d8f4fe43 100644 --- a/unsupported/Eigen/NonLinearOptimization +++ b/unsupported/Eigen/NonLinearOptimization @@ -108,19 +108,23 @@ namespace Eigen { * handle the loop: init + loop until a stop condition is met. Those are provided for * convenience. * - * As an example, the method LevenbergMarquardt.minimizeNumericalDiff() is + * As an example, the method LevenbergMarquardt::minimize() is * implemented as follow : * \code - * LevenbergMarquardt.minimizeNumericalDiff(Matrix< Scalar, Dynamic, 1 > &x, - * const int mode ) + * Status LevenbergMarquardt::minimize(FVectorType &x, const int mode) * { - * Status status = minimizeNumericalDiffInit(x, mode); - * while (status==Running) - * status = minimizeNumericalDiffOneStep(x, mode); + * Status status = minimizeInit(x, mode); + * do { + * status = minimizeOneStep(x, mode); + * } while (status==Running); * return status; * } * \endcode * + * \section examples Examples + * + * The easiest way to understand how to use this module is by looking at the many examples in the file + * unsupported/test/NonLinearOptimization.cpp. */ #ifndef EIGEN_PARSED_BY_DOXYGEN From 7ba9dc07edb356d1a7d81bf4ef62378099a509ca Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Wed, 27 Jan 2010 09:01:13 +0100 Subject: [PATCH 028/109] port ei_rwupdt to c++, and misc cleaning --- .../LevenbergMarquardt.h | 14 +++-- .../Eigen/src/NonLinearOptimization/rwupdt.h | 52 +++++++++---------- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index adbb3c835..cda6ef74b 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -289,7 +289,6 @@ LevenbergMarquardt::minimizeOneStep( if (mode != 2) diag = diag.cwiseMax(wa2); - /* beginning of the inner loop. */ do { /* determine the levenberg-marquardt parameter. */ @@ -374,9 +373,9 @@ LevenbergMarquardt::minimizeOneStep( return XtolTooSmall; if (gnorm <= epsilon()) return GtolTooSmall; - /* end of the inner loop. repeat if iteration unsuccessful. */ + } while (ratio < Scalar(1e-4)); - /* end of the outer loop. */ + return Running; } @@ -468,7 +467,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( int rownb = 2; for (i = 0; i < m; ++i) { if (functor.df(x, wa3, rownb) < 0) return UserAsked; - ei_rwupdt(n, fjac.data(), fjac.rows(), wa3.data(), qtf.data(), fvec[i]); + ei_rwupdt(fjac, wa3, qtf, fvec[i]); ++rownb; } ++njev; @@ -485,7 +484,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( if (sing) { wa2 = fjac.colwise().blueNorm(); // TODO We have no unit test covering this code path, do not modify - // before it is carefully tested + // until it is carefully tested ColPivHouseholderQR qrfac(fjac); fjac = qrfac.matrixQR(); wa1 = fjac.diagonal(); @@ -538,7 +537,6 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( if (mode != 2) diag = diag.cwiseMax(wa2); - /* beginning of the inner loop. */ do { /* determine the levenberg-marquardt parameter. */ @@ -623,9 +621,9 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( return XtolTooSmall; if (gnorm <= epsilon()) return GtolTooSmall; - /* end of the inner loop. repeat if iteration unsuccessful. */ + } while (ratio < Scalar(1e-4)); - /* end of the outer loop. */ + return Running; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h index 38676e720..7703ff8de 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h @@ -1,45 +1,41 @@ - template -void ei_rwupdt(int n, Scalar *r__, int ldr, const Scalar *w, Scalar *b, Scalar alpha) +template +void ei_rwupdt( + Matrix< Scalar, Dynamic, Dynamic > &r, + const Matrix< Scalar, Dynamic, 1> &w, + Matrix< Scalar, Dynamic, 1> &b, + Scalar alpha) { + const int n = r.cols(); + assert(r.rows()>=n); std::vector > givens(n); - /* System generated locals */ - int r_dim1, r_offset; /* Local variables */ Scalar temp, rowj; - /* Parameter adjustments */ - --b; - --w; - r_dim1 = ldr; - r_offset = 1 + r_dim1 * 1; - r__ -= r_offset; - /* Function Body */ - for (int j = 1; j <= n; ++j) { + for (int j = 0; j < n; ++j) { rowj = w[j]; /* apply the previous transformations to */ - /* r(i,j), i=1,2,...,j-1, and to w(j). */ - if (j-1>=1) - for (int i = 1; i <= j-1; ++i) { - temp = givens[i-1].c() * r__[i + j * r_dim1] + givens[i-1].s() * rowj; - rowj = -givens[i-1].s() * r__[i + j * r_dim1] + givens[i-1].c() * rowj; - r__[i + j * r_dim1] = temp; - } + /* r(i,j), i=0,1,...,j-1, and to w(j). */ + for (int i = 0; i < j; ++i) { + temp = givens[i].c() * r(i,j) + givens[i].s() * rowj; + rowj = -givens[i].s() * r(i,j) + givens[i].c() * rowj; + r(i,j) = temp; + } + + if (rowj == 0.) + continue; /* determine a givens rotation which eliminates w(j). */ - if (rowj != 0.) { - givens[j-1].makeGivens(-r__[j + j * r_dim1], rowj); + givens[j].makeGivens(-r(j,j), rowj); - /* apply the current transformation to r(j,j), b(j), and alpha. */ - r__[j + j * r_dim1] = givens[j-1].c() * r__[j + j * r_dim1] + givens[j-1].s() * rowj; - temp = givens[j-1].c() * b[j] + givens[j-1].s() * alpha; - alpha = -givens[j-1].s() * b[j] + givens[j-1].c() * alpha; - b[j] = temp; - } + /* apply the current transformation to r(j,j), b(j), and alpha. */ + r(j,j) = givens[j].c() * r(j,j) + givens[j].s() * rowj; + temp = givens[j].c() * b[j] + givens[j].s() * alpha; + alpha = -givens[j].s() * b[j] + givens[j].c() * alpha; + b[j] = temp; } - return; } From 35bacf7cb864d4cb6d74ec1fa6ed84006b00ddf2 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 27 Jan 2010 07:11:49 -0500 Subject: [PATCH 029/109] *forward port fix in MapBase::coeff(int) and coeffRef(int) *forward port expanded map.cpp unit test *fix unused variable warnings --- Eigen/src/Core/Assign.h | 2 +- Eigen/src/Core/MapBase.h | 4 +-- test/map.cpp | 46 ++++++++++++++++++++---- unsupported/Eigen/src/FFT/ei_fftw_impl.h | 2 +- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 41653098f..0a6c46eca 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -382,7 +382,7 @@ template struct ei_unaligned_assign_impl { template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, int start, int end) {} + static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, int, int) {} }; template <> diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 4d5ec1eeb..81feb0b5a 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -88,7 +88,7 @@ template class MapBase inline const Scalar& coeff(int index) const { ei_assert(Derived::IsVectorAtCompileTime || (ei_traits::Flags & LinearAccessBit)); - if ( ((RowsAtCompileTime == 1) == IsRowMajor) ) + if ( ((RowsAtCompileTime == 1) == IsRowMajor) || !int(Derived::IsVectorAtCompileTime) ) return m_data[index]; else return m_data[index*stride()]; @@ -97,7 +97,7 @@ template class MapBase inline Scalar& coeffRef(int index) { ei_assert(Derived::IsVectorAtCompileTime || (ei_traits::Flags & LinearAccessBit)); - if ( ((RowsAtCompileTime == 1) == IsRowMajor) ) + if ( ((RowsAtCompileTime == 1) == IsRowMajor) || !int(Derived::IsVectorAtCompileTime) ) return const_cast(m_data)[index]; else return const_cast(m_data)[index*stride()]; diff --git a/test/map.cpp b/test/map.cpp index 14c0393db..603b6159b 100644 --- a/test/map.cpp +++ b/test/map.cpp @@ -24,7 +24,7 @@ #include "main.h" -template void map_class(const VectorType& m) +template void map_class_vector(const VectorType& m) { typedef typename VectorType::Scalar Scalar; @@ -51,6 +51,34 @@ template void map_class(const VectorType& m) delete[] array3; } +template void map_class_matrix(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + + int rows = m.rows(), cols = m.cols(), size = rows*cols; + + // test Map.h + Scalar* array1 = ei_aligned_new(size); + for(int i = 0; i < size; i++) array1[i] = Scalar(1); + Scalar* array2 = ei_aligned_new(size); + for(int i = 0; i < size; i++) array2[i] = Scalar(1); + Scalar* array3 = new Scalar[size+1]; + for(int i = 0; i < size+1; i++) array3[i] = Scalar(1); + Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3; + Map(array1, rows, cols) = MatrixType::Ones(rows,cols); + Map(array2, rows, cols) = Map(array1, rows, cols); + Map(array3unaligned, rows, cols) = Map(array1, rows, cols); + MatrixType ma1 = Map(array1, rows, cols); + MatrixType ma2 = Map(array2, rows, cols); + VERIFY_IS_APPROX(ma1, ma2); + MatrixType ma3 = Map(array3unaligned, rows, cols); + VERIFY_IS_APPROX(ma1, ma3); + + ei_aligned_delete(array1, size); + ei_aligned_delete(array2, size); + delete[] array3; +} + template void map_static_methods(const VectorType& m) { typedef typename VectorType::Scalar Scalar; @@ -81,11 +109,17 @@ template void map_static_methods(const VectorType& m) void test_map() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( map_class(Matrix()) ); - CALL_SUBTEST_2( map_class(Vector4d()) ); - CALL_SUBTEST_3( map_class(RowVector4f()) ); - CALL_SUBTEST_4( map_class(VectorXcf(8)) ); - CALL_SUBTEST_5( map_class(VectorXi(12)) ); + CALL_SUBTEST_1( map_class_vector(Matrix()) ); + CALL_SUBTEST_2( map_class_vector(Vector4d()) ); + CALL_SUBTEST_3( map_class_vector(RowVector4f()) ); + CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) ); + CALL_SUBTEST_5( map_class_vector(VectorXi(12)) ); + + CALL_SUBTEST_1( map_class_matrix(Matrix()) ); + CALL_SUBTEST_2( map_class_matrix(Matrix4d()) ); + CALL_SUBTEST_11( map_class_matrix(Matrix()) ); + CALL_SUBTEST_4( map_class_matrix(MatrixXcf(ei_random(1,10),ei_random(1,10))) ); + CALL_SUBTEST_5( map_class_matrix(MatrixXi(ei_random(1,10),ei_random(1,10))) ); CALL_SUBTEST_6( map_static_methods(Matrix()) ); CALL_SUBTEST_7( map_static_methods(Vector3f()) ); diff --git a/unsupported/Eigen/src/FFT/ei_fftw_impl.h b/unsupported/Eigen/src/FFT/ei_fftw_impl.h index a66b7398c..1d6e419eb 100644 --- a/unsupported/Eigen/src/FFT/ei_fftw_impl.h +++ b/unsupported/Eigen/src/FFT/ei_fftw_impl.h @@ -205,7 +205,7 @@ { bool inplace = (dst==src); bool aligned = ( (reinterpret_cast(src)&15) | (reinterpret_cast(dst)&15) ) == 0; - int key = (nfft<<3 ) | (inverse<<2) | (inplace<<1) | aligned; + int key = (nfft<<3 ) | (inverse<<2) | (inplace<<1) | static_cast(aligned); return m_plans[key]; } }; From dcbf104bccec39e955ab84c76bf1d96beaa31aa1 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 27 Jan 2010 07:48:48 -0500 Subject: [PATCH 030/109] add EIGEN_DEFAULT_TO_ROW_MAJOR cmake option for the tests. --- cmake/EigenTesting.cmake | 6 ++++++ test/CMakeLists.txt | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 4d02a470a..8830eef4e 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -148,6 +148,12 @@ macro(ei_testing_print_summary) message("Enabled backends: ${EIGEN_TESTED_BACKENDS}") message("Disabled backends: ${EIGEN_MISSING_BACKENDS}") + if(EIGEN_DEFAULT_TO_ROW_MAJOR) + message("Default order: Row-major") + else() + message("Default order: Column-major") + endif() + if(EIGEN_TEST_SSE2) message("SSE2: ON") else() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6dd0d6916..1177db797 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,11 @@ add_dependencies(check buildtests) option(EIGEN_SPLIT_LARGE_TESTS "Split large tests into smaller executables" ON) +option(EIGEN_DEFAULT_TO_ROW_MAJOR "Use row-major as default matrix storage order" OFF) +if(EIGEN_DEFAULT_TO_ROW_MAJOR) + add_definitions("-DEIGEN_DEFAULT_TO_ROW_MAJOR") +endif() + find_package(GSL) if(GSL_FOUND AND GSL_VERSION_MINOR LESS 9) set(GSL_FOUND "") From 828d058b4b340a467da7f7bea6bb29522a6565f9 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 27 Jan 2010 11:42:04 -0500 Subject: [PATCH 031/109] EIGEN_ENUM_MIN ---> EIGEN_SIZE_MIN --- Eigen/src/Core/BandMatrix.h | 3 ++- Eigen/src/Geometry/Umeyama.h | 6 +++--- Eigen/src/LU/FullPivLU.h | 4 ++-- Eigen/src/LU/PartialPivLU.h | 2 +- Eigen/src/QR/ColPivHouseholderQR.h | 2 +- Eigen/src/QR/FullPivHouseholderQR.h | 2 +- Eigen/src/SVD/SVD.h | 2 +- test/lu.cpp | 10 ++++++---- test/submatrices.cpp | 11 ++++++----- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index 67684eca3..538e6dd76 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -77,7 +77,7 @@ class BandMatrix : public AnyMatrixBase DataType; @@ -136,6 +136,7 @@ class BandMatrix : public AnyMatrixBase& src, const MatrixBase& dst, boo EIGEN_STATIC_ASSERT((ei_is_same_type::Scalar>::ret), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - enum { Dimension = EIGEN_ENUM_MIN(Derived::RowsAtCompileTime, OtherDerived::RowsAtCompileTime) }; + enum { Dimension = EIGEN_SIZE_MIN(Derived::RowsAtCompileTime, OtherDerived::RowsAtCompileTime) }; typedef Matrix VectorType; typedef Matrix MatrixType; diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 148ddcd23..fe14a9080 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -487,7 +487,7 @@ struct ei_kernel_retval > { EIGEN_MAKE_KERNEL_HELPERS(FullPivLU<_MatrixType>) - enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( + enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN( MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime) }; @@ -572,7 +572,7 @@ struct ei_image_retval > { EIGEN_MAKE_IMAGE_HELPERS(FullPivLU<_MatrixType>) - enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( + enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN( MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime) }; diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index f50aa4535..809e4aad6 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -67,7 +67,7 @@ template class PartialPivLU typedef Matrix PermutationVectorType; typedef PermutationMatrix PermutationType; - enum { MaxSmallDimAtCompileTime = EIGEN_ENUM_MIN( + enum { MaxSmallDimAtCompileTime = EIGEN_SIZE_MIN( MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime) }; diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index a119d0c2f..63d069081 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -51,7 +51,7 @@ template class ColPivHouseholderQR RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, - DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) + DiagSizeAtCompileTime = EIGEN_SIZE_MIN(ColsAtCompileTime,RowsAtCompileTime) }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 717ff19f8..8e8dbbbf8 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -51,7 +51,7 @@ template class FullPivHouseholderQR RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, - DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) + DiagSizeAtCompileTime = EIGEN_SIZE_MIN(ColsAtCompileTime,RowsAtCompileTime) }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; diff --git a/Eigen/src/SVD/SVD.h b/Eigen/src/SVD/SVD.h index cd8c11b8d..1d4bbe417 100644 --- a/Eigen/src/SVD/SVD.h +++ b/Eigen/src/SVD/SVD.h @@ -52,7 +52,7 @@ template class SVD ColsAtCompileTime = MatrixType::ColsAtCompileTime, PacketSize = ei_packet_traits::size, AlignmentMask = int(PacketSize)-1, - MinSize = EIGEN_ENUM_MIN(RowsAtCompileTime, ColsAtCompileTime) + MinSize = EIGEN_SIZE_MIN(RowsAtCompileTime, ColsAtCompileTime) }; typedef Matrix ColVector; diff --git a/test/lu.cpp b/test/lu.cpp index c2237febf..45308ff82 100644 --- a/test/lu.cpp +++ b/test/lu.cpp @@ -35,7 +35,7 @@ template void lu_non_invertible() int rows, cols, cols2; if(MatrixType::RowsAtCompileTime==Dynamic) { - rows = ei_random(20,200); + rows = ei_random(2,200); } else { @@ -43,8 +43,8 @@ template void lu_non_invertible() } if(MatrixType::ColsAtCompileTime==Dynamic) { - cols = ei_random(20,200); - cols2 = ei_random(20,200); + cols = ei_random(2,200); + cols2 = ei_random(2,200); } else { @@ -108,7 +108,7 @@ template void lu_invertible() LU.h */ typedef typename NumTraits::Real RealScalar; - int size = ei_random(10,200); + int size = ei_random(1,200); MatrixType m1(size, size), m2(size, size), m3(size, size); m1 = MatrixType::Random(size,size); @@ -185,5 +185,7 @@ void test_lu() CALL_SUBTEST_6( lu_non_invertible() ); CALL_SUBTEST_6( lu_invertible() ); CALL_SUBTEST_6( lu_verify_assert() ); + + CALL_SUBTEST_7(( lu_non_invertible >() )); } } diff --git a/test/submatrices.cpp b/test/submatrices.cpp index 9cd6f3fab..d53fd4b6f 100644 --- a/test/submatrices.cpp +++ b/test/submatrices.cpp @@ -60,6 +60,7 @@ template void submatrices(const MatrixType& m) typedef typename MatrixType::RealScalar RealScalar; typedef Matrix VectorType; typedef Matrix RowVectorType; + typedef Matrix SquareMatrixType; int rows = m.rows(); int cols = m.cols(); @@ -67,11 +68,9 @@ template void submatrices(const MatrixType& m) m2 = MatrixType::Random(rows, cols), m3(rows, cols), mzero = MatrixType::Zero(rows, cols), - ones = MatrixType::Ones(rows, cols), - identity = Matrix - ::Identity(rows, rows), - square = Matrix - ::Random(rows, rows); + ones = MatrixType::Ones(rows, cols); + SquareMatrixType identity = SquareMatrixType::Identity(rows, rows), + square = SquareMatrixType::Random(rows, rows); VectorType v1 = VectorType::Random(rows), v2 = VectorType::Random(rows), v3 = VectorType::Random(rows), @@ -222,6 +221,8 @@ void test_submatrices() CALL_SUBTEST_5( submatrices(MatrixXcd(20, 20)) ); CALL_SUBTEST_6( submatrices(MatrixXf(20, 20)) ); + CALL_SUBTEST_8( submatrices(Matrix(3, 4)) ); + CALL_SUBTEST_6( data_and_stride(MatrixXf(ei_random(5,50), ei_random(5,50))) ); CALL_SUBTEST_7( data_and_stride(Matrix(ei_random(5,50), ei_random(5,50))) ); } From 5b9cc65418be7539db01f87712ed32d3f22517a5 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 27 Jan 2010 20:34:05 +0100 Subject: [PATCH 032/109] Added EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION macro including unit tests and documentation. --- Eigen/StdVector | 39 ++++++++++++++++++++++++++++ doc/D01_StlContainers.dox | 15 +++++++++++ doc/snippets/DenseBase_LinSpaced.cpp | 4 +-- test/CMakeLists.txt | 1 + 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Eigen/StdVector b/Eigen/StdVector index b6dbde8a2..04e356785 100644 --- a/Eigen/StdVector +++ b/Eigen/StdVector @@ -29,6 +29,45 @@ #include "Core" #include +// Define the explicit instantiation (e.g. necessary for the Intel compiler) +#if defined(__INTEL_COMPILER) || defined(__GNUC__) + #define EIGEN_EXPLICIT_STL_VECTOR_INSTANTIATION(...) template class std::vector<__VA_ARGS__, Eigen::aligned_allocator<__VA_ARGS__> >; +#else + #define EIGEN_EXPLICIT_STL_VECTOR_INSTANTIATION(...) +#endif + +/** + * This section contains a convenience MACRO which allows an easy specialization of + * std::vector such that for data types with alignment issues the correct allocator + * is used automatically. + */ +#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) \ +EIGEN_EXPLICIT_STL_VECTOR_INSTANTIATION(__VA_ARGS__) \ +namespace std \ +{ \ + template \ + class vector<__VA_ARGS__, _Ay> \ + : public vector<__VA_ARGS__, Eigen::aligned_allocator<__VA_ARGS__> > \ + { \ + typedef vector<__VA_ARGS__, Eigen::aligned_allocator<__VA_ARGS__> > vector_base; \ + public: \ + typedef __VA_ARGS__ value_type; \ + typedef typename vector_base::allocator_type allocator_type; \ + typedef typename vector_base::size_type size_type; \ + typedef typename vector_base::iterator iterator; \ + explicit vector(const allocator_type& a = allocator_type()) : vector_base(a) {} \ + template \ + vector(InputIterator first, InputIterator last, const allocator_type& a = allocator_type()) : vector_base(first, last, a) {} \ + vector(const vector& c) : vector_base(c) {} \ + explicit vector(size_type num, const value_type& val = value_type()) : vector_base(num, val) {} \ + vector(iterator start, iterator end) : vector_base(start, end) {} \ + vector& operator=(const vector& x) { \ + vector_base::operator=(x); \ + return *this; \ + } \ + }; \ +} + namespace Eigen { // This one is needed to prevent reimplementing the whole std::vector. diff --git a/doc/D01_StlContainers.dox b/doc/D01_StlContainers.dox index db682c996..83e930e50 100644 --- a/doc/D01_StlContainers.dox +++ b/doc/D01_StlContainers.dox @@ -41,6 +41,21 @@ Here is an example: std::vector > \endcode +\subsection vector_spec An alternative - specializing std::vector for Eigen types + +As an alternative to the recommended approach described above, you have the option to specialize std::vector for Eigen types requiring alignment. +The advantage is that you won't need to declare std::vector all over with Eigen::allocator. One drawback on the other hand side is that +the specialization needs to be defined before all code pieces in which e.g. std::vector is used. Otherwise, without knowing the specialization +the compiler will compile that particular instance with the default std::allocator and you program is most likely to crash. + +Here is an example: +\code +#include +\/* ... *\/ +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2d) +std::vector +\endcode + \b Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector, some Eigen::Vector4f objects will be passed by value, which discards any alignment modifiers, so a Eigen::Vector4f can be created at an unaligned location. In order to avoid that, the only solution we saw was to specialize std::vector to make it work on a slight modification of, here, Eigen::Vector4f, that is able to deal properly with this situation. diff --git a/doc/snippets/DenseBase_LinSpaced.cpp b/doc/snippets/DenseBase_LinSpaced.cpp index 540709adc..c8c3e972c 100644 --- a/doc/snippets/DenseBase_LinSpaced.cpp +++ b/doc/snippets/DenseBase_LinSpaced.cpp @@ -1,2 +1,2 @@ -cout << VectorXi::LinSpaced(7,10,4) << endl; -cout << VectorXd::LinSpaced(0.0,1.0,5) << endl; +cout << VectorXi::LinSpaced(7,10,4).transpose() << endl; +cout << VectorXd::LinSpaced(0.0,1.0,5).transpose() << endl; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1177db797..77e7a5fd2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -152,6 +152,7 @@ ei_add_test(geo_parametrizedline) ei_add_test(geo_alignedbox) ei_add_test(regression) ei_add_test(stdvector) +ei_add_test(stdvector_overload) ei_add_test(resize) if(QT4_FOUND) ei_add_test(qtvector " " "${QT_QTCORE_LIBRARY}") From 3bfba8c9a9e2302fc288444eb716c73e009bb9d2 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 27 Jan 2010 20:34:42 +0100 Subject: [PATCH 033/109] Added the missing unit test file. --- test/stdvector_overload.cpp | 175 ++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 test/stdvector_overload.cpp diff --git a/test/stdvector_overload.cpp b/test/stdvector_overload.cpp new file mode 100644 index 000000000..a8a833141 --- /dev/null +++ b/test/stdvector_overload.cpp @@ -0,0 +1,175 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Benoit Jacob +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#include "main.h" + +#include +#include + +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Vector4f) + +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2f) +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4f) +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4d) + +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Transform3f) +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Transform3d) + +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaternionf) +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaterniond) + +template +void check_stdvector_matrix(const MatrixType& m) +{ + int rows = m.rows(); + int cols = m.cols(); + MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols); + std::vector v(10, MatrixType(rows,cols)), w(20, y); + v[5] = x; + w[6] = v[5]; + VERIFY_IS_APPROX(w[6], v[5]); + v = w; + for(int i = 0; i < 20; i++) + { + VERIFY_IS_APPROX(w[i], v[i]); + } + + v.resize(21); + v[20] = x; + VERIFY_IS_APPROX(v[20], x); + v.resize(22,y); + VERIFY_IS_APPROX(v[21], y); + v.push_back(x); + VERIFY_IS_APPROX(v[22], x); + VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType)); + + // do a lot of push_back such that the vector gets internally resized + // (with memory reallocation) + MatrixType* ref = &w[0]; + for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) + v.push_back(w[i%w.size()]); + for(unsigned int i=23; i +void check_stdvector_transform(const TransformType&) +{ + typedef typename TransformType::MatrixType MatrixType; + TransformType x(MatrixType::Random()), y(MatrixType::Random()); + std::vector v(10), w(20, y); + v[5] = x; + w[6] = v[5]; + VERIFY_IS_APPROX(w[6], v[5]); + v = w; + for(int i = 0; i < 20; i++) + { + VERIFY_IS_APPROX(w[i], v[i]); + } + + v.resize(21); + v[20] = x; + VERIFY_IS_APPROX(v[20], x); + v.resize(22,y); + VERIFY_IS_APPROX(v[21], y); + v.push_back(x); + VERIFY_IS_APPROX(v[22], x); + VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType)); + + // do a lot of push_back such that the vector gets internally resized + // (with memory reallocation) + TransformType* ref = &w[0]; + for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) + v.push_back(w[i%w.size()]); + for(unsigned int i=23; i +void check_stdvector_quaternion(const QuaternionType&) +{ + typedef typename QuaternionType::Coefficients Coefficients; + QuaternionType x(Coefficients::Random()), y(Coefficients::Random()); + std::vector v(10), w(20, y); + v[5] = x; + w[6] = v[5]; + VERIFY_IS_APPROX(w[6], v[5]); + v = w; + for(int i = 0; i < 20; i++) + { + VERIFY_IS_APPROX(w[i], v[i]); + } + + v.resize(21); + v[20] = x; + VERIFY_IS_APPROX(v[20], x); + v.resize(22,y); + VERIFY_IS_APPROX(v[21], y); + v.push_back(x); + VERIFY_IS_APPROX(v[22], x); + VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType)); + + // do a lot of push_back such that the vector gets internally resized + // (with memory reallocation) + QuaternionType* ref = &w[0]; + for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) + v.push_back(w[i%w.size()]); + for(unsigned int i=23; i Date: Wed, 27 Jan 2010 20:47:37 +0100 Subject: [PATCH 034/109] Modified license header. --- test/stdvector_overload.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/stdvector_overload.cpp b/test/stdvector_overload.cpp index a8a833141..86f4308ad 100644 --- a/test/stdvector_overload.cpp +++ b/test/stdvector_overload.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2008 Benoit Jacob +// Copyright (C) 2010 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public From 0ce5bc0d14557891ecd39144007e8e11d7887489 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 27 Jan 2010 23:23:59 +0100 Subject: [PATCH 035/109] add support for global math function for array --- Eigen/Core | 2 ++ Eigen/src/Array/GlobalFunctions.h | 55 +++++++++++++++++++++++++++++++ test/array.cpp | 30 +++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 Eigen/src/Array/GlobalFunctions.h diff --git a/Eigen/Core b/Eigen/Core index 2a9ee08e8..12c8ea97f 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -253,6 +253,8 @@ struct Dense {}; } // namespace Eigen +#include "src/Array/GlobalFunctions.h" + #include "src/Core/util/EnableMSVCWarnings.h" #ifdef EIGEN2_SUPPORT diff --git a/Eigen/src/Array/GlobalFunctions.h b/Eigen/src/Array/GlobalFunctions.h new file mode 100644 index 000000000..33f00c2ba --- /dev/null +++ b/Eigen/src/Array/GlobalFunctions.h @@ -0,0 +1,55 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_GLOBAL_FUNCTIONS_H +#define EIGEN_GLOBAL_FUNCTIONS_H + +#define EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(NAME,FUNCTOR) \ + template \ + inline const Eigen::CwiseUnaryOp, Derived> \ + NAME(const Eigen::ArrayBase& x) { \ + return x.derived(); \ + } + +namespace std +{ + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sqrt,ei_scalar_sqrt_op) +} + +namespace Eigen +{ + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sqrt,ei_scalar_sqrt_op) +} + +#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/test/array.cpp b/test/array.cpp index 8a71b4020..e51dbac2a 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -132,6 +132,30 @@ template void comparisons(const MatrixType& m) VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayXi::Constant(rows, cols)); } +template void array_real(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + int rows = m.rows(); + int cols = m.cols(); + + MatrixType m1 = MatrixType::Random(rows, cols), + m2 = MatrixType::Random(rows, cols), + m3(rows, cols); + + VERIFY_IS_APPROX(m1.sin(), std::sin(m1)); + VERIFY_IS_APPROX(m1.sin(), ei_sin(m1)); + VERIFY_IS_APPROX(m1.cos(), ei_cos(m1)); + VERIFY_IS_APPROX(m1.cos(), ei_cos(m1)); + VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1))); + VERIFY_IS_APPROX(m1.abs().sqrt(), ei_sqrt(ei_abs(m1))); + VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1))); + VERIFY_IS_APPROX(m1.abs().log(), ei_log(ei_abs(m1))); + VERIFY_IS_APPROX(m1.exp(), std::exp(m1)); + VERIFY_IS_APPROX(m1.exp(), ei_exp(m1)); +} + void test_array() { for(int i = 0; i < g_repeat; i++) { @@ -149,4 +173,10 @@ void test_array() CALL_SUBTEST_5( comparisons(ArrayXXf(8, 12)) ); CALL_SUBTEST_6( comparisons(ArrayXXi(8, 12)) ); } + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( array_real(Array()) ); + CALL_SUBTEST_2( array_real(Array22f()) ); + CALL_SUBTEST_3( array_real(Array44d()) ); + CALL_SUBTEST_5( array_real(ArrayXXf(8, 12)) ); + } } From bd732986bc0a60f5e138beb221e99c870e9e6ecd Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Wed, 27 Jan 2010 23:43:15 +0100 Subject: [PATCH 036/109] fix compilation --- unsupported/Eigen/NonLinearOptimization | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/NonLinearOptimization b/unsupported/Eigen/NonLinearOptimization index 8d8f4fe43..149b658f8 100644 --- a/unsupported/Eigen/NonLinearOptimization +++ b/unsupported/Eigen/NonLinearOptimization @@ -25,6 +25,8 @@ #ifndef EIGEN_NONLINEAROPTIMIZATION_MODULE #define EIGEN_NONLINEAROPTIMIZATION_MODULE +#include + #include #include #include @@ -54,7 +56,7 @@ namespace Eigen { * fortran. Those implementations have been carefully tuned, tested, and used * for several decades. * - * The original fortran code was automatically translated (using f2c) in C and + * The original fortran code was automatically translated using f2c (http://en.wikipedia.org/wiki/F2c) in C, * then c++, and then cleaned by several different authors. * The last one of those cleanings being our starting point : * http://devernay.free.fr/hacks/cminpack.html From fcd074c92823576d3c17544a4d82a8c57776f266 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Wed, 27 Jan 2010 23:43:32 +0100 Subject: [PATCH 037/109] silent warning of icc --- Eigen/src/Core/util/XprHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 6b5387c99..b2496a771 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -142,7 +142,7 @@ template struct ei_plain_matrix_type_dense * in order to avoid a useless copy */ -template::StorageType> class ei_eval; +template::StorageType> struct ei_eval; template struct ei_eval { From 40eac2d8a09149846ae92cc39ead3a50791443b1 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 28 Jan 2010 04:19:39 +0100 Subject: [PATCH 038/109] misc cleaning / eigenization --- .../HybridNonLinearSolver.h | 12 +++---- .../LevenbergMarquardt.h | 12 +++---- .../Eigen/src/NonLinearOptimization/chkder.h | 8 ++--- .../Eigen/src/NonLinearOptimization/covar.h | 33 +++++++------------ .../Eigen/src/NonLinearOptimization/dogleg.h | 7 ++-- .../Eigen/src/NonLinearOptimization/fdjac1.h | 12 +++---- .../Eigen/src/NonLinearOptimization/lmpar.h | 10 ++++-- .../Eigen/src/NonLinearOptimization/qrsolv.h | 11 +++---- 8 files changed, 44 insertions(+), 61 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 539c58d72..51cea50be 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -238,8 +238,7 @@ HybridNonLinearSolver::solveOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); - xnorm = wa3.stableNorm(); + xnorm = diag.cwiseProduct(x).stableNorm(); delta = parameters.factor * xnorm; if (delta == 0.) delta = parameters.factor; @@ -269,8 +268,7 @@ HybridNonLinearSolver::solveOneStep( /* store the direction p and x + p. calculate the norm of p. */ wa1 = -wa1; wa2 = x + wa1; - wa3 = diag.cwiseProduct(wa1); - pnorm = wa3.stableNorm(); + pnorm = diag.cwiseProduct(wa1).stableNorm(); /* on the first iteration, adjust the initial step bound. */ if (iter == 1) @@ -489,8 +487,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); - xnorm = wa3.stableNorm(); + xnorm = diag.cwiseProduct(x).stableNorm(); delta = parameters.factor * xnorm; if (delta == 0.) delta = parameters.factor; @@ -520,8 +517,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* store the direction p and x + p. calculate the norm of p. */ wa1 = -wa1; wa2 = x + wa1; - wa3 = diag.cwiseProduct(wa1); - pnorm = wa3.stableNorm(); + pnorm = diag.cwiseProduct(wa1).stableNorm(); /* on the first iteration, adjust the initial step bound. */ if (iter == 1) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index cda6ef74b..076110651 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -261,8 +261,7 @@ LevenbergMarquardt::minimizeOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); - xnorm = wa3.stableNorm(); + xnorm = diag.cwiseProduct(x).stableNorm(); delta = parameters.factor * xnorm; if (delta == 0.) delta = parameters.factor; @@ -297,8 +296,7 @@ LevenbergMarquardt::minimizeOneStep( /* store the direction p and x + p. calculate the norm of p. */ wa1 = -wa1; wa2 = x + wa1; - wa3 = diag.cwiseProduct(wa1); - pnorm = wa3.stableNorm(); + pnorm = diag.cwiseProduct(wa1).stableNorm(); /* on the first iteration, adjust the initial step bound. */ if (iter == 1) @@ -515,8 +513,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* on the first iteration, calculate the norm of the scaled x */ /* and initialize the step bound delta. */ - wa3 = diag.cwiseProduct(x); - xnorm = wa3.stableNorm(); + xnorm = diag.cwiseProduct(x).stableNorm(); delta = parameters.factor * xnorm; if (delta == 0.) delta = parameters.factor; @@ -545,8 +542,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* store the direction p and x + p. calculate the norm of p. */ wa1 = -wa1; wa2 = x + wa1; - wa3 = diag.cwiseProduct(wa1); - pnorm = wa3.stableNorm(); + pnorm = diag.cwiseProduct(wa1).stableNorm(); /* on the first iteration, adjust the initial step bound. */ if (iter == 1) diff --git a/unsupported/Eigen/src/NonLinearOptimization/chkder.h b/unsupported/Eigen/src/NonLinearOptimization/chkder.h index 21fd60a9d..be8115230 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/chkder.h +++ b/unsupported/Eigen/src/NonLinearOptimization/chkder.h @@ -4,11 +4,11 @@ template void ei_chkder( - Matrix< Scalar, Dynamic, 1 > &x, - Matrix< Scalar, Dynamic, 1 > &fvec, - Matrix< Scalar, Dynamic, Dynamic > &fjac, + const Matrix< Scalar, Dynamic, 1 > &x, + const Matrix< Scalar, Dynamic, 1 > &fvec, + const Matrix< Scalar, Dynamic, Dynamic > &fjac, Matrix< Scalar, Dynamic, 1 > &xp, - Matrix< Scalar, Dynamic, 1 > &fvecp, + const Matrix< Scalar, Dynamic, 1 > &fvecp, int mode, Matrix< Scalar, Dynamic, 1 > &err ) diff --git a/unsupported/Eigen/src/NonLinearOptimization/covar.h b/unsupported/Eigen/src/NonLinearOptimization/covar.h index 620a2d71a..15c72d6ed 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/covar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/covar.h @@ -16,7 +16,7 @@ void ei_covar( Matrix< Scalar, Dynamic, 1 > wa(n); assert(ipvt.size()==n); - /* form the inverse of r in the full upper triangle of r. */ + /* form the inverse of r in the full upper triangle of r. */ l = -1; for (k = 0; k < n; ++k) if (ei_abs(r(k,k)) > tolr) { @@ -24,27 +24,21 @@ void ei_covar( for (j = 0; j <= k-1; ++j) { temp = r(k,k) * r(j,k); r(j,k) = 0.; - for (i = 0; i <= j; ++i) - r(i,k) -= temp * r(i,j); + r.col(k).head(j+1) -= r.col(j).head(j+1) * temp; } l = k; } - /* form the full upper triangle of the inverse of (r transpose)*r */ - /* in the full upper triangle of r. */ + /* form the full upper triangle of the inverse of (r transpose)*r */ + /* in the full upper triangle of r. */ for (k = 0; k <= l; ++k) { - for (j = 0; j <= k-1; ++j) { - temp = r(j,k); - for (i = 0; i <= j; ++i) - r(i,j) += temp * r(i,k); - } - temp = r(k,k); - for (i = 0; i <= k; ++i) - r(i,k) = temp * r(i,k); + for (j = 0; j <= k-1; ++j) + r.col(j).head(j+1) += r.col(k).head(j+1) * r(j,k); + r.col(k).head(k+1) *= r(k,k); } - /* form the full lower triangle of the covariance matrix */ - /* in the strict lower triangle of r and in wa. */ + /* form the full lower triangle of the covariance matrix */ + /* in the strict lower triangle of r and in wa. */ for (j = 0; j < n; ++j) { jj = ipvt[j]; sing = j > l; @@ -60,11 +54,8 @@ void ei_covar( wa[jj] = r(j,j); } - /* symmetrize the covariance matrix in r. */ - for (j = 0; j < n; ++j) { - for (i = 0; i <= j; ++i) - r(i,j) = r(j,i); - r(j,j) = wa[j]; - } + /* symmetrize the covariance matrix in r. */ + r.corner(TopLeft,n,n).template triangularView() = r.corner(TopLeft,n,n).transpose(); + r.diagonal() = wa; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index 18b0963b2..b3c4fbb96 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -36,8 +36,7 @@ void ei_dogleg( } /* test whether the gauss-newton direction is acceptable. */ - wa2 = diag.cwiseProduct(x); - qnorm = wa2.stableNorm(); + qnorm = diag.cwiseProduct(x).stableNorm(); if (qnorm <= delta) return; @@ -48,9 +47,7 @@ void ei_dogleg( wa1.fill(0.); for (j = 0; j < n; ++j) { - temp = qtb[j]; - for (i = j; i < n; ++i) - wa1[i] += qrfac(j,i) * temp; + wa1.tail(n-j) += qrfac.row(j).tail(n-j) * qtb[j]; wa1[j] /= diag[j]; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h index 77c18fbeb..9564a784b 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h +++ b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h @@ -10,10 +10,11 @@ int ei_fdjac1( { /* Local variables */ Scalar h; - int i, j, k; + int j, k; Scalar eps, temp; int msum; int iflag; + int start, length; /* Function Body */ const Scalar epsmch = epsilon(); @@ -55,11 +56,10 @@ int ei_fdjac1( x[j] = wa2[j]; h = eps * ei_abs(wa2[j]); if (h == 0.) h = eps; - for (i = 0; i < n; ++i) { - fjac(i,j) = 0.; - if (i >= j - mu && i <= j + ml) - fjac(i,j) = (wa1[i] - fvec[i]) / h; - } + fjac.col(j).setZero(); + start = std::max(0,j-mu); + length = std::min(n-1, j+ml) - start + 1; + fjac.col(j).segment(start, length) = ( wa1.segment(start, length)-fvec.segment(start, length))/h; } } } diff --git a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h index cd4698d76..d763bd4e7 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/lmpar.h @@ -164,7 +164,7 @@ void ei_lmpar2( { /* Local variables */ - int i, j; + int j; Scalar fp; Scalar parc, parl; int iter; @@ -183,9 +183,11 @@ void ei_lmpar2( /* compute and store in x the gauss-newton direction. if the */ /* jacobian is rank-deficient, obtain a least squares solution. */ + // const int rank = qr.nonzeroPivots(); // exactly double(0.) const int rank = qr.rank(); // use a threshold - wa1 = qtb; wa1.segment(rank,n-rank).setZero(); + wa1 = qtb; + wa1.tail(n-rank).setZero(); qr.matrixQR().corner(TopLeft, rank, rank).template triangularView().solveInPlace(wa1.head(rank)); x = qr.colsPermutation()*wa1; @@ -255,10 +257,12 @@ void ei_lmpar2( /* compute the newton correction. */ wa1 = qr.colsPermutation().inverse() * diag.cwiseProduct(wa2/dxnorm); + // we could almost use this here, but the diagonal is outside qr, in sdiag[] + // qr.matrixQR().corner(TopLeft, n, n).transpose().template triangularView().solveInPlace(wa1); for (j = 0; j < n; ++j) { wa1[j] /= sdiag[j]; temp = wa1[j]; - for (i = j+1; i < n; ++i) + for (int i = j+1; i < n; ++i) wa1[i] -= s(i,j) * temp; } temp = wa1.blueNorm(); diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h index 18e313c27..f89a5f9a8 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h @@ -1,4 +1,5 @@ +// TODO : once qrsolv2 is removed, use ColPivHouseholderQR or PermutationMatrix instead of ipvt template void ei_qrsolv( Matrix< Scalar, Dynamic, Dynamic > &s, @@ -15,6 +16,7 @@ void ei_qrsolv( Scalar temp; int n = s.cols(); Matrix< Scalar, Dynamic, 1 > wa(n); + PlanarRotation givens; /* Function Body */ // the following will only change the lower triangular part of s, including @@ -25,9 +27,7 @@ void ei_qrsolv( x = s.diagonal(); wa = qtb; - for (j = 0; j < n; ++j) - for (i = j+1; i < n; ++i) - s(i,j) = s(j,i); + s.corner(TopLeft,n,n).template triangularView() = s.corner(TopLeft,n,n).transpose(); /* eliminate the diagonal matrix d using a givens rotation. */ for (j = 0; j < n; ++j) { @@ -37,7 +37,7 @@ void ei_qrsolv( l = ipvt[j]; if (diag[l] == 0.) break; - sdiag.segment(j,n-j).setZero(); + sdiag.tail(n-j).setZero(); sdiag[j] = diag[l]; /* the transformations to eliminate the row of d */ @@ -47,7 +47,6 @@ void ei_qrsolv( for (k = j; k < n; ++k) { /* determine a givens rotation which eliminates the */ /* appropriate element in the current row of d. */ - PlanarRotation givens; givens.makeGivens(-s(k,k), sdiag[k]); /* compute the modified diagonal element of r and */ @@ -70,8 +69,8 @@ void ei_qrsolv( /* singular, then obtain a least squares solution. */ int nsing; for (nsing=0; nsing().solveInPlace(wa.head(nsing)); // restore From 27cf1b3a97ee13c5bede72e6cd44975750908f21 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 28 Jan 2010 04:28:52 +0100 Subject: [PATCH 039/109] eigenization of ei_r1updt() --- .../HybridNonLinearSolver.h | 4 +- .../Eigen/src/NonLinearOptimization/r1updt.h | 91 ++++++++++--------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 51cea50be..258297072 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -359,7 +359,7 @@ HybridNonLinearSolver::solveOneStep( wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(R, wa1.data(), v_givens, w_givens, wa2.data(), wa3.data(), &sing); + ei_r1updt(R, wa1, v_givens, w_givens, wa2, wa3, &sing); ei_r1mpyq(n, n, fjac.data(), v_givens, w_givens); ei_r1mpyq(1, n, qtf.data(), v_givens, w_givens); @@ -608,7 +608,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( wa2 = (wa2-wa3)/pnorm; /* compute the qr factorization of the updated jacobian. */ - ei_r1updt(R, wa1.data(), v_givens, w_givens, wa2.data(), wa3.data(), &sing); + ei_r1updt(R, wa1, v_givens, w_givens, wa2, wa3, &sing); ei_r1mpyq(n, n, fjac.data(), v_givens, w_givens); ei_r1mpyq(1, n, qtf.data(), v_givens, w_givens); diff --git a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h index 0c530f3aa..3d8978837 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/r1updt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/r1updt.h @@ -1,9 +1,13 @@ template -void ei_r1updt(Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, +void ei_r1updt( + Matrix< Scalar, Dynamic, Dynamic > &s, + const Matrix< Scalar, Dynamic, 1> &u, std::vector > &v_givens, std::vector > &w_givens, - Scalar *v, Scalar *w, bool *sing) + Matrix< Scalar, Dynamic, 1> &v, + Matrix< Scalar, Dynamic, 1> &w, + bool *sing) { /* Local variables */ const int m = s.rows(); @@ -15,71 +19,68 @@ void ei_r1updt(Matrix< Scalar, Dynamic, Dynamic > &s, const Scalar *u, // ei_r1updt had a broader usecase, but we dont use it here. And, more // importantly, we can not test it. assert(m==n); + assert(u.size()==m); + assert(v.size()==n); + assert(w.size()==n); - /* Parameter adjustments */ - --w; - --u; - --v; + /* move the nontrivial part of the last column of s into w. */ + w[n-1] = s(n-1,n-1); - /* move the nontrivial part of the last column of s into w. */ - w[n] = s(n-1,n-1); - - /* rotate the vector v into a multiple of the n-th unit vector */ - /* in such a way that a spike is introduced into w. */ - for (j=n-1; j>=1; --j) { + /* rotate the vector v into a multiple of the n-th unit vector */ + /* in such a way that a spike is introduced into w. */ + for (j=n-2; j>=0; --j) { w[j] = 0.; if (v[j] != 0.) { - /* determine a givens rotation which eliminates the */ - /* j-th element of v. */ - givens.makeGivens(-v[n], v[j]); + /* determine a givens rotation which eliminates the */ + /* j-th element of v. */ + givens.makeGivens(-v[n-1], v[j]); - /* apply the transformation to v and store the information */ - /* necessary to recover the givens rotation. */ - v[n] = givens.s() * v[j] + givens.c() * v[n]; - v_givens[j-1] = givens; + /* apply the transformation to v and store the information */ + /* necessary to recover the givens rotation. */ + v[n-1] = givens.s() * v[j] + givens.c() * v[n-1]; + v_givens[j] = givens; - /* apply the transformation to s and extend the spike in w. */ - for (i = j; i <= m; ++i) { - temp = givens.c() * s(j-1,i-1) - givens.s() * w[i]; - w[i] = givens.s() * s(j-1,i-1) + givens.c() * w[i]; - s(j-1,i-1) = temp; + /* apply the transformation to s and extend the spike in w. */ + for (i = j; i < m; ++i) { + temp = givens.c() * s(j,i) - givens.s() * w[i]; + w[i] = givens.s() * s(j,i) + givens.c() * w[i]; + s(j,i) = temp; } } } - /* add the spike from the rank 1 update to w. */ - for (i = 1; i <= m; ++i) - w[i] += v[n] * u[i]; + /* add the spike from the rank 1 update to w. */ + w += v[n-1] * u; - /* eliminate the spike. */ + /* eliminate the spike. */ *sing = false; - for (j = 1; j <= n-1; ++j) { + for (j = 0; j < n-1; ++j) { if (w[j] != 0.) { - /* determine a givens rotation which eliminates the */ - /* j-th element of the spike. */ - givens.makeGivens(-s(j-1,j-1), w[j]); + /* determine a givens rotation which eliminates the */ + /* j-th element of the spike. */ + givens.makeGivens(-s(j,j), w[j]); - /* apply the transformation to s and reduce the spike in w. */ - for (i = j; i <= m; ++i) { - temp = givens.c() * s(j-1,i-1) + givens.s() * w[i]; - w[i] = -givens.s() * s(j-1,i-1) + givens.c() * w[i]; - s(j-1,i-1) = temp; + /* apply the transformation to s and reduce the spike in w. */ + for (i = j; i < m; ++i) { + temp = givens.c() * s(j,i) + givens.s() * w[i]; + w[i] = -givens.s() * s(j,i) + givens.c() * w[i]; + s(j,i) = temp; } - /* store the information necessary to recover the */ - /* givens rotation. */ - w_givens[j-1] = givens; + /* store the information necessary to recover the */ + /* givens rotation. */ + w_givens[j] = givens; } - /* test for zero diagonal elements in the output s. */ - if (s(j-1,j-1) == 0.) { + /* test for zero diagonal elements in the output s. */ + if (s(j,j) == 0.) { *sing = true; } } - /* move w back into the last column of the output s. */ - s(n-1,n-1) = w[n]; + /* move w back into the last column of the output s. */ + s(n-1,n-1) = w[n-1]; - if (s(j-1,j-1) == 0.) { + if (s(j,j) == 0.) { *sing = true; } return; From 98a584ceb8dcaf32091c742c294c4c335b46aa1d Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 28 Jan 2010 10:29:26 +0100 Subject: [PATCH 040/109] Put the Status outside of the class, it really does not depend on the FunctorType or Scalar template parameters. --- .../HybridNonLinearSolver.h | 116 +++++++------- .../LevenbergMarquardt.h | 145 +++++++++--------- 2 files changed, 134 insertions(+), 127 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 258297072..5c832b73d 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -28,6 +28,19 @@ #ifndef EIGEN_HYBRIDNONLINEARSOLVER_H #define EIGEN_HYBRIDNONLINEARSOLVER_H +namespace HybridNonLinearSolverSpace { + enum Status { + Running = -1, + ImproperInputParameters = 0, + RelativeErrorTooSmall = 1, + TooManyFunctionEvaluation = 2, + TolTooSmall = 3, + NotMakingProgressJacobian = 4, + NotMakingProgressIterations = 5, + UserAksed = 6 + }; +} + /** * \ingroup NonLinearOptimization_Module * \brief Finds a zero of a system of n @@ -46,17 +59,6 @@ public: HybridNonLinearSolver(FunctorType &_functor) : functor(_functor) { nfev=njev=iter = 0; fnorm= 0.; } - enum Status { - Running = -1, - ImproperInputParameters = 0, - RelativeErrorTooSmall = 1, - TooManyFunctionEvaluation = 2, - TolTooSmall = 3, - NotMakingProgressJacobian = 4, - NotMakingProgressIterations = 5, - UserAksed = 6 - }; - struct Parameters { Parameters() : factor(Scalar(100.)) @@ -77,38 +79,38 @@ public: /* TODO: if eigen provides a triangular storage, use it here */ typedef Matrix< Scalar, Dynamic, Dynamic > UpperTriangularType; - Status hybrj1( + HybridNonLinearSolverSpace::Status hybrj1( FVectorType &x, const Scalar tol = ei_sqrt(epsilon()) ); - Status solveInit( + HybridNonLinearSolverSpace::Status solveInit( FVectorType &x, const int mode=1 ); - Status solveOneStep( + HybridNonLinearSolverSpace::Status solveOneStep( FVectorType &x, const int mode=1 ); - Status solve( + HybridNonLinearSolverSpace::Status solve( FVectorType &x, const int mode=1 ); - Status hybrd1( + HybridNonLinearSolverSpace::Status hybrd1( FVectorType &x, const Scalar tol = ei_sqrt(epsilon()) ); - Status solveNumericalDiffInit( + HybridNonLinearSolverSpace::Status solveNumericalDiffInit( FVectorType &x, const int mode=1 ); - Status solveNumericalDiffOneStep( + HybridNonLinearSolverSpace::Status solveNumericalDiffOneStep( FVectorType &x, const int mode=1 ); - Status solveNumericalDiff( + HybridNonLinearSolverSpace::Status solveNumericalDiff( FVectorType &x, const int mode=1 ); @@ -142,7 +144,7 @@ private: template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::hybrj1( FVectorType &x, const Scalar tol @@ -152,7 +154,7 @@ HybridNonLinearSolver::hybrj1( /* check the input parameters for errors. */ if (n <= 0 || tol < 0.) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; resetParameters(); parameters.maxfev = 100*(n+1); @@ -165,7 +167,7 @@ HybridNonLinearSolver::hybrj1( } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solveInit( FVectorType &x, const int mode @@ -187,17 +189,17 @@ HybridNonLinearSolver::solveInit( /* check the input parameters for errors. */ if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0. ) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; if (mode == 2) for (int j = 0; j < n; ++j) if (diag[j] <= 0.) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; /* evaluate the function at the starting point */ /* and calculate its norm. */ nfev = 1; if ( functor(x, fvec) < 0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; fnorm = fvec.stableNorm(); /* initialize iteration counter and monitors. */ @@ -207,11 +209,11 @@ HybridNonLinearSolver::solveInit( nslow1 = 0; nslow2 = 0; - return Running; + return HybridNonLinearSolverSpace::Running; } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solveOneStep( FVectorType &x, const int mode @@ -224,7 +226,7 @@ HybridNonLinearSolver::solveOneStep( /* calculate the jacobian matrix. */ if ( functor.df(x, fjac) < 0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; ++njev; wa2 = fjac.colwise().blueNorm(); @@ -276,7 +278,7 @@ HybridNonLinearSolver::solveOneStep( /* evaluate the function at x + p and calculate its norm. */ if ( functor(wa2, wa4) < 0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; ++nfev; fnorm1 = wa4.stableNorm(); @@ -334,17 +336,17 @@ HybridNonLinearSolver::solveOneStep( /* test for convergence. */ if (delta <= parameters.xtol * xnorm || fnorm == 0.) - return RelativeErrorTooSmall; + return HybridNonLinearSolverSpace::RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) - return TooManyFunctionEvaluation; + return HybridNonLinearSolverSpace::TooManyFunctionEvaluation; if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) - return TolTooSmall; + return HybridNonLinearSolverSpace::TolTooSmall; if (nslow2 == 5) - return NotMakingProgressJacobian; + return HybridNonLinearSolverSpace::NotMakingProgressJacobian; if (nslow1 == 10) - return NotMakingProgressIterations; + return HybridNonLinearSolverSpace::NotMakingProgressIterations; /* criterion for recalculating jacobian. */ if (ncfail == 2) @@ -365,18 +367,18 @@ HybridNonLinearSolver::solveOneStep( jeval = false; } - return Running; + return HybridNonLinearSolverSpace::Running; } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solve( FVectorType &x, const int mode ) { - Status status = solveInit(x, mode); - while (status==Running) + HybridNonLinearSolverSpace::Status status = solveInit(x, mode); + while (status==HybridNonLinearSolverSpace::Running) status = solveOneStep(x, mode); return status; } @@ -384,7 +386,7 @@ HybridNonLinearSolver::solve( template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::hybrd1( FVectorType &x, const Scalar tol @@ -394,7 +396,7 @@ HybridNonLinearSolver::hybrd1( /* check the input parameters for errors. */ if (n <= 0 || tol < 0.) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; resetParameters(); parameters.maxfev = 200*(n+1); @@ -408,7 +410,7 @@ HybridNonLinearSolver::hybrd1( } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solveNumericalDiffInit( FVectorType &x, const int mode @@ -434,17 +436,17 @@ HybridNonLinearSolver::solveNumericalDiffInit( /* check the input parameters for errors. */ if (n <= 0 || parameters.xtol < 0. || parameters.maxfev <= 0 || parameters.nb_of_subdiagonals< 0 || parameters.nb_of_superdiagonals< 0 || parameters.factor <= 0. ) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; if (mode == 2) for (int j = 0; j < n; ++j) if (diag[j] <= 0.) - return ImproperInputParameters; + return HybridNonLinearSolverSpace::ImproperInputParameters; /* evaluate the function at the starting point */ /* and calculate its norm. */ nfev = 1; if ( functor(x, fvec) < 0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; fnorm = fvec.stableNorm(); /* initialize iteration counter and monitors. */ @@ -454,11 +456,11 @@ HybridNonLinearSolver::solveNumericalDiffInit( nslow1 = 0; nslow2 = 0; - return Running; + return HybridNonLinearSolverSpace::Running; } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solveNumericalDiffOneStep( FVectorType &x, const int mode @@ -473,7 +475,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* calculate the jacobian matrix. */ if (ei_fdjac1(functor, x, fvec, fjac, parameters.nb_of_subdiagonals, parameters.nb_of_superdiagonals, parameters.epsfcn) <0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; nfev += std::min(parameters.nb_of_subdiagonals+parameters.nb_of_superdiagonals+ 1, n); wa2 = fjac.colwise().blueNorm(); @@ -525,7 +527,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* evaluate the function at x + p and calculate its norm. */ if ( functor(wa2, wa4) < 0) - return UserAksed; + return HybridNonLinearSolverSpace::UserAksed; ++nfev; fnorm1 = wa4.stableNorm(); @@ -583,17 +585,17 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* test for convergence. */ if (delta <= parameters.xtol * xnorm || fnorm == 0.) - return RelativeErrorTooSmall; + return HybridNonLinearSolverSpace::RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) - return TooManyFunctionEvaluation; + return HybridNonLinearSolverSpace::TooManyFunctionEvaluation; if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) - return TolTooSmall; + return HybridNonLinearSolverSpace::TolTooSmall; if (nslow2 == 5) - return NotMakingProgressJacobian; + return HybridNonLinearSolverSpace::NotMakingProgressJacobian; if (nslow1 == 10) - return NotMakingProgressIterations; + return HybridNonLinearSolverSpace::NotMakingProgressIterations; /* criterion for recalculating jacobian. */ if (ncfail == 2) @@ -614,18 +616,18 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( jeval = false; } - return Running; + return HybridNonLinearSolverSpace::Running; } template -typename HybridNonLinearSolver::Status +HybridNonLinearSolverSpace::Status HybridNonLinearSolver::solveNumericalDiff( FVectorType &x, const int mode ) { - Status status = solveNumericalDiffInit(x, mode); - while (status==Running) + HybridNonLinearSolverSpace::Status status = solveNumericalDiffInit(x, mode); + while (status==HybridNonLinearSolverSpace::Running) status = solveNumericalDiffOneStep(x, mode); return status; } diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 076110651..7457c688e 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -28,21 +28,8 @@ #ifndef EIGEN_LEVENBERGMARQUARDT__H #define EIGEN_LEVENBERGMARQUARDT__H -/** - * \ingroup NonLinearOptimization_Module - * \brief Performs non linear optimization over a non-linear function, - * using a variant of the Levenberg Marquardt algorithm. - * - * Check wikipedia for more information. - * http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm - */ -template -class LevenbergMarquardt -{ -public: - LevenbergMarquardt(FunctorType &_functor) - : functor(_functor) { nfev = njev = iter = 0; fnorm=gnorm = 0.; } +namespace LevenbergMarquardtSpace { enum Status { NotStarted = -2, Running = -1, @@ -57,6 +44,24 @@ public: GtolTooSmall = 8, UserAsked = 9 }; +} + + + +/** + * \ingroup NonLinearOptimization_Module + * \brief Performs non linear optimization over a non-linear function, + * using a variant of the Levenberg Marquardt algorithm. + * + * Check wikipedia for more information. + * http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm + */ +template +class LevenbergMarquardt +{ +public: + LevenbergMarquardt(FunctorType &_functor) + : functor(_functor) { nfev = njev = iter = 0; fnorm=gnorm = 0.; } struct Parameters { Parameters() @@ -77,45 +82,45 @@ public: typedef Matrix< Scalar, Dynamic, 1 > FVectorType; typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType; - Status lmder1( + LevenbergMarquardtSpace::Status lmder1( FVectorType &x, const Scalar tol = ei_sqrt(epsilon()) ); - Status minimize( + LevenbergMarquardtSpace::Status minimize( FVectorType &x, const int mode=1 ); - Status minimizeInit( + LevenbergMarquardtSpace::Status minimizeInit( FVectorType &x, const int mode=1 ); - Status minimizeOneStep( + LevenbergMarquardtSpace::Status minimizeOneStep( FVectorType &x, const int mode=1 ); - static Status lmdif1( + static LevenbergMarquardtSpace::Status lmdif1( FunctorType &functor, FVectorType &x, int *nfev, const Scalar tol = ei_sqrt(epsilon()) ); - Status lmstr1( + LevenbergMarquardtSpace::Status lmstr1( FVectorType &x, const Scalar tol = ei_sqrt(epsilon()) ); - Status minimizeOptimumStorage( + LevenbergMarquardtSpace::Status minimizeOptimumStorage( FVectorType &x, const int mode=1 ); - Status minimizeOptimumStorageInit( + LevenbergMarquardtSpace::Status minimizeOptimumStorageInit( FVectorType &x, const int mode=1 ); - Status minimizeOptimumStorageOneStep( + LevenbergMarquardtSpace::Status minimizeOptimumStorageOneStep( FVectorType &x, const int mode=1 ); @@ -146,7 +151,7 @@ private: }; template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::lmder1( FVectorType &x, const Scalar tol @@ -157,7 +162,7 @@ LevenbergMarquardt::lmder1( /* check the input parameters for errors. */ if (n <= 0 || m < n || tol < 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; resetParameters(); parameters.ftol = tol; @@ -169,21 +174,21 @@ LevenbergMarquardt::lmder1( template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimize( FVectorType &x, const int mode ) { - Status status = minimizeInit(x, mode); + LevenbergMarquardtSpace::Status status = minimizeInit(x, mode); do { status = minimizeOneStep(x, mode); - } while (status==Running); + } while (status==LevenbergMarquardtSpace::Running); return status; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimizeInit( FVectorType &x, const int mode @@ -207,29 +212,29 @@ LevenbergMarquardt::minimizeInit( /* check the input parameters for errors. */ if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; if (mode == 2) for (int j = 0; j < n; ++j) if (diag[j] <= 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; /* evaluate the function at the starting point */ /* and calculate its norm. */ nfev = 1; if ( functor(x, fvec) < 0) - return UserAsked; + return LevenbergMarquardtSpace::UserAsked; fnorm = fvec.stableNorm(); /* initialize levenberg-marquardt parameter and iteration counter. */ par = 0.; iter = 1; - return NotStarted; + return LevenbergMarquardtSpace::NotStarted; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimizeOneStep( FVectorType &x, const int mode @@ -240,7 +245,7 @@ LevenbergMarquardt::minimizeOneStep( /* calculate the jacobian matrix. */ int df_ret = functor.df(x, fjac); if (df_ret<0) - return UserAsked; + return LevenbergMarquardtSpace::UserAsked; if (df_ret>0) // numerical diff, we evaluated the function df_ret times nfev += df_ret; @@ -282,7 +287,7 @@ LevenbergMarquardt::minimizeOneStep( /* test for convergence of the gradient norm. */ if (gnorm <= parameters.gtol) - return CosinusTooSmall; + return LevenbergMarquardtSpace::CosinusTooSmall; /* rescale if necessary. */ if (mode != 2) @@ -304,7 +309,7 @@ LevenbergMarquardt::minimizeOneStep( /* evaluate the function at x + p and calculate its norm. */ if ( functor(wa2, wa4) < 0) - return UserAsked; + return LevenbergMarquardtSpace::UserAsked; ++nfev; fnorm1 = wa4.stableNorm(); @@ -356,29 +361,29 @@ LevenbergMarquardt::minimizeOneStep( /* tests for convergence. */ if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) - return RelativeErrorAndReductionTooSmall; + return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall; if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) - return RelativeReductionTooSmall; + return LevenbergMarquardtSpace::RelativeReductionTooSmall; if (delta <= parameters.xtol * xnorm) - return RelativeErrorTooSmall; + return LevenbergMarquardtSpace::RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) - return TooManyFunctionEvaluation; + return LevenbergMarquardtSpace::TooManyFunctionEvaluation; if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) - return FtolTooSmall; + return LevenbergMarquardtSpace::FtolTooSmall; if (delta <= epsilon() * xnorm) - return XtolTooSmall; + return LevenbergMarquardtSpace::XtolTooSmall; if (gnorm <= epsilon()) - return GtolTooSmall; + return LevenbergMarquardtSpace::GtolTooSmall; } while (ratio < Scalar(1e-4)); - return Running; + return LevenbergMarquardtSpace::Running; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::lmstr1( FVectorType &x, const Scalar tol @@ -389,7 +394,7 @@ LevenbergMarquardt::lmstr1( /* check the input parameters for errors. */ if (n <= 0 || m < n || tol < 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; resetParameters(); parameters.ftol = tol; @@ -400,7 +405,7 @@ LevenbergMarquardt::lmstr1( } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimizeOptimumStorageInit( FVectorType &x, const int mode @@ -424,30 +429,30 @@ LevenbergMarquardt::minimizeOptimumStorageInit( /* check the input parameters for errors. */ if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; if (mode == 2) for (int j = 0; j < n; ++j) if (diag[j] <= 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; /* evaluate the function at the starting point */ /* and calculate its norm. */ nfev = 1; if ( functor(x, fvec) < 0) - return UserAsked; + return LevenbergMarquardtSpace::UserAsked; fnorm = fvec.stableNorm(); /* initialize levenberg-marquardt parameter and iteration counter. */ par = 0.; iter = 1; - return NotStarted; + return LevenbergMarquardtSpace::NotStarted; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimizeOptimumStorageOneStep( FVectorType &x, const int mode @@ -464,7 +469,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( fjac.fill(0.); int rownb = 2; for (i = 0; i < m; ++i) { - if (functor.df(x, wa3, rownb) < 0) return UserAsked; + if (functor.df(x, wa3, rownb) < 0) return LevenbergMarquardtSpace::UserAsked; ei_rwupdt(fjac, wa3, qtf, fvec[i]); ++rownb; } @@ -528,7 +533,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* test for convergence of the gradient norm. */ if (gnorm <= parameters.gtol) - return CosinusTooSmall; + return LevenbergMarquardtSpace::CosinusTooSmall; /* rescale if necessary. */ if (mode != 2) @@ -550,7 +555,7 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* evaluate the function at x + p and calculate its norm. */ if ( functor(wa2, wa4) < 0) - return UserAsked; + return LevenbergMarquardtSpace::UserAsked; ++nfev; fnorm1 = wa4.stableNorm(); @@ -602,43 +607,43 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* tests for convergence. */ if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) - return RelativeErrorAndReductionTooSmall; + return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall; if (ei_abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) - return RelativeReductionTooSmall; + return LevenbergMarquardtSpace::RelativeReductionTooSmall; if (delta <= parameters.xtol * xnorm) - return RelativeErrorTooSmall; + return LevenbergMarquardtSpace::RelativeErrorTooSmall; /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) - return TooManyFunctionEvaluation; + return LevenbergMarquardtSpace::TooManyFunctionEvaluation; if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) - return FtolTooSmall; + return LevenbergMarquardtSpace::FtolTooSmall; if (delta <= epsilon() * xnorm) - return XtolTooSmall; + return LevenbergMarquardtSpace::XtolTooSmall; if (gnorm <= epsilon()) - return GtolTooSmall; + return LevenbergMarquardtSpace::GtolTooSmall; } while (ratio < Scalar(1e-4)); - return Running; + return LevenbergMarquardtSpace::Running; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::minimizeOptimumStorage( FVectorType &x, const int mode ) { - Status status = minimizeOptimumStorageInit(x, mode); + LevenbergMarquardtSpace::Status status = minimizeOptimumStorageInit(x, mode); do { status = minimizeOptimumStorageOneStep(x, mode); - } while (status==Running); + } while (status==LevenbergMarquardtSpace::Running); return status; } template -typename LevenbergMarquardt::Status +LevenbergMarquardtSpace::Status LevenbergMarquardt::lmdif1( FunctorType &functor, FVectorType &x, @@ -651,7 +656,7 @@ LevenbergMarquardt::lmdif1( /* check the input parameters for errors. */ if (n <= 0 || m < n || tol < 0.) - return ImproperInputParameters; + return LevenbergMarquardtSpace::ImproperInputParameters; NumericalDiff numDiff(functor); // embedded LevenbergMarquardt @@ -660,7 +665,7 @@ LevenbergMarquardt::lmdif1( lm.parameters.xtol = tol; lm.parameters.maxfev = 200*(n+1); - Status info = Status(lm.minimize(x)); + LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x)); if (nfev) * nfev = lm.nfev; return info; From 33abe75afab26216a299977a3133f05441d997eb Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 28 Jan 2010 10:32:44 +0100 Subject: [PATCH 041/109] Fixed Quaternion operator*= added regression test. --- Eigen/src/Geometry/Quaternion.h | 3 ++- test/geo_quaternion.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index b8b41ebcf..285a93c15 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -377,7 +377,8 @@ template template EIGEN_STRONG_INLINE Derived& QuaternionBase::operator*= (const QuaternionBase& other) { - return (derived() = derived() * other.derived()); + derived() = derived() * other.derived(); + return derived(); } /** Rotation of a vector by a quaternion. diff --git a/test/geo_quaternion.cpp b/test/geo_quaternion.cpp index 052c01fbf..311ffd2ec 100644 --- a/test/geo_quaternion.cpp +++ b/test/geo_quaternion.cpp @@ -59,6 +59,9 @@ template void quaternion(void) q1.coeffs().setRandom(); VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs()); + // concatenation + q1 *= q2; + q1 = AngleAxisx(a, v0.normalized()); q2 = AngleAxisx(a, v1.normalized()); From 13b078efc956f4adb19029d826b6fd3c383f499b Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 28 Jan 2010 08:46:01 -0500 Subject: [PATCH 042/109] remove reference to dead option --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7d4089c0..210c90725 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,9 +61,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra") endif() - if(NOT EIGEN_TEST_LIB) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") - endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF) if(EIGEN_TEST_SSE2) From 375b5faa8a433a5707d59a645e5573c89eed9dfc Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 28 Jan 2010 17:06:20 +0000 Subject: [PATCH 043/109] Fix copy-paste error in first_aligned test. --- test/first_aligned.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp index 3cf1a7eef..f00ed57a5 100644 --- a/test/first_aligned.cpp +++ b/test/first_aligned.cpp @@ -50,9 +50,9 @@ void test_first_aligned() test_first_aligned_helper(array_float+5, 50); EIGEN_ALIGN16 double array_double[100]; - test_first_aligned_helper(array_float, 50); - test_first_aligned_helper(array_float+1, 50); - test_first_aligned_helper(array_float+2, 50); + test_first_aligned_helper(array_double, 50); + test_first_aligned_helper(array_double+1, 50); + test_first_aligned_helper(array_double+2, 50); double *array_double_plus_4_bytes = (double*)(size_t(array_double)+4); test_none_aligned_helper(array_double_plus_4_bytes, 50); From 2b2fcc9460b0d541172e951a9059be4d982d44d0 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Fri, 29 Jan 2010 08:59:25 +0100 Subject: [PATCH 044/109] erm.... using nxn is the actual purpose of this variant, fix this. --- .../Eigen/src/NonLinearOptimization/LevenbergMarquardt.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 7457c688e..49b63bed8 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -417,7 +417,12 @@ LevenbergMarquardt::minimizeOptimumStorageInit( wa1.resize(n); wa2.resize(n); wa3.resize(n); wa4.resize(m); fvec.resize(m); - fjac.resize(m, n); + // Only R is stored in fjac. Q is only used to compute 'qtf', which is + // Q.transpose()*rhs. qtf will be updated using givens rotation, + // instead of storing them in Q. + // The purpose it to only use a nxn matrix, instead of mxn here, so + // that we can handle cases where m>>n : + fjac.resize(n, n); if (mode != 2) diag.resize(n); assert( (mode!=2 || diag.size()==n) || "When using mode==2, the caller must provide a valid 'diag'"); From ae06365bbd4b8cb80e5991c32967d6df891d0361 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 29 Jan 2010 09:53:19 +0100 Subject: [PATCH 045/109] Disable variadic macro warning when compiling at full warning level. I was not able to get a macro version running and thus I opted for a cmake patch. --- cmake/EigenTesting.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 8830eef4e..c445f842b 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -233,7 +233,12 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") endif(EIGEN_TEST_C++0x) if(EIGEN_TEST_MAX_WARNING_LEVEL) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion") + CHECK_CXX_COMPILER_FLAG("-Wno-variadic-macros" FLAG_VARIADIC) + if(FLAG_VARIADIC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wno-variadic-macros") + else(FLAG_VARIADIC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion") + endif(FLAG_VARIADIC) endif(EIGEN_TEST_MAX_WARNING_LEVEL) if(CMAKE_SYSTEM_NAME MATCHES Linux) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") From 42b88983ff846624ff335e2a60f7435acb7cb9cf Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 29 Jan 2010 11:48:16 +0100 Subject: [PATCH 046/109] Fixed mean reduction leading to unresolved symbol. --- Eigen/src/Core/MatrixBase.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 3f1f2a6b9..62aed3b7f 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -284,7 +284,6 @@ template class MatrixBase template inline const typename ei_meta_if,Derived&>::ret forceAlignedAccessIf() const; template inline typename ei_meta_if,Derived&>::ret forceAlignedAccessIf(); - Scalar mean() const; Scalar trace() const; /////////// Array module /////////// From 6dee5440e4971781077769913586e9748b1d6dbf Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 29 Jan 2010 12:12:02 +0100 Subject: [PATCH 047/109] Adapted mean to work with complex numbers. Added regression test. --- Eigen/src/Core/Redux.h | 2 +- test/redux.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 1643f13b2..09538a3bd 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -356,7 +356,7 @@ template EIGEN_STRONG_INLINE typename ei_traits::Scalar DenseBase::mean() const { - return this->redux(Eigen::ei_scalar_sum_op()) / this->size(); + return this->redux(Eigen::ei_scalar_sum_op()) / Scalar(this->size()); } /** \returns the product of all coefficients of *this diff --git a/test/redux.cpp b/test/redux.cpp index 3293fd54e..f95e8b29c 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -44,7 +44,11 @@ template void matrixRedux(const MatrixType& m) minc = std::min(ei_real(minc), ei_real(m1(i,j))); maxc = std::max(ei_real(maxc), ei_real(m1(i,j))); } + const Scalar mean = s/Scalar(rows*cols); + const Scalar other_mean = m1.mean(); + VERIFY_IS_APPROX(m1.sum(), s); + VERIFY_IS_APPROX(m1.mean(), mean); VERIFY_IS_APPROX(m1.prod(), p); VERIFY_IS_APPROX(m1.real().minCoeff(), ei_real(minc)); VERIFY_IS_APPROX(m1.real().maxCoeff(), ei_real(maxc)); @@ -113,15 +117,24 @@ void test_redux() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( matrixRedux(Matrix()) ); + CALL_SUBTEST_1( matrixRedux(Array()) ); CALL_SUBTEST_2( matrixRedux(Matrix2f()) ); + CALL_SUBTEST_2( matrixRedux(Array2f()) ); CALL_SUBTEST_3( matrixRedux(Matrix4d()) ); + CALL_SUBTEST_3( matrixRedux(Array4d()) ); CALL_SUBTEST_4( matrixRedux(MatrixXcf(3, 3)) ); + CALL_SUBTEST_4( matrixRedux(ArrayXXcf(3, 3)) ); CALL_SUBTEST_5( matrixRedux(MatrixXd(8, 12)) ); + CALL_SUBTEST_5( matrixRedux(ArrayXXd(8, 12)) ); CALL_SUBTEST_6( matrixRedux(MatrixXi(8, 12)) ); + CALL_SUBTEST_6( matrixRedux(ArrayXXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_7( vectorRedux(Vector4f()) ); + CALL_SUBTEST_7( vectorRedux(Array4f()) ); CALL_SUBTEST_5( vectorRedux(VectorXd(10)) ); + CALL_SUBTEST_5( vectorRedux(ArrayXd(10)) ); CALL_SUBTEST_8( vectorRedux(VectorXf(33)) ); + CALL_SUBTEST_8( vectorRedux(ArrayXf(33)) ); } } From b6521b799f6d14761ff8e0000a1911d560a79a0e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Jan 2010 21:28:23 +0100 Subject: [PATCH 048/109] add specialization of ei_ref_selector for Array (fix a big perf issue \!) --- Eigen/src/Core/util/XprHelper.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index b2496a771..136cc876b 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -228,6 +228,13 @@ struct ei_ref_selector< Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCo typedef MatrixType const& type; }; +template +struct ei_ref_selector< Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > +{ + typedef Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> ArrayType; + typedef ArrayType const& type; +}; + /** \internal Determines how a given expression should be nested into another one. * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be * nested into the bigger product expression. The choice is between nesting the expression b+c as-is, or From 43f0c0cbb31dff81402ffda22cf9dd3856d499e6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 30 Jan 2010 09:02:18 +0100 Subject: [PATCH 049/109] fix triangular view assignment --- Eigen/src/Core/SolveTriangular.h | 2 +- Eigen/src/Core/TriangularMatrix.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h index 73cf77387..cac1e2554 100644 --- a/Eigen/src/Core/SolveTriangular.h +++ b/Eigen/src/Core/SolveTriangular.h @@ -254,7 +254,7 @@ void TriangularView::solveInPlace(const MatrixBase::type, - Side, Mode>::run(_expression(), otherCopy); + Side, Mode>::run(nestedExpression(), otherCopy); if (copy) other = otherCopy; diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index e51be366b..8bea0aa68 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -204,8 +204,8 @@ template class TriangularView return m_matrix.const_cast_derived().coeffRef(row, col); } - /** \internal */ - const MatrixType& _expression() const { return m_matrix; } + const MatrixType& nestedExpression() const { return m_matrix; } + MatrixType& nestedExpression() { return const_cast(m_matrix); } /** Assigns a triangular matrix to a triangular part of a dense matrix */ template @@ -215,7 +215,7 @@ template class TriangularView TriangularView& operator=(const MatrixBase& other); TriangularView& operator=(const TriangularView& other) - { return *this = other._expression(); } + { return *this = other.nestedExpression(); } template void lazyAssign(const TriangularBase& other); @@ -510,15 +510,15 @@ template inline TriangularView& TriangularView::operator=(const TriangularBase& other) { - ei_assert(Mode == OtherDerived::Mode); + ei_assert(Mode == int(OtherDerived::Mode)); if(ei_traits::Flags & EvalBeforeAssigningBit) { typename OtherDerived::DenseMatrixType other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived()); + other_evaluated.template triangularView().lazyAssign(other.derived().nestedExpression()); lazyAssign(other_evaluated); } else - lazyAssign(other.derived()); + lazyAssign(other.derived().nestedExpression()); return *this; } @@ -534,7 +534,7 @@ void TriangularView::lazyAssign(const TriangularBase::run(m_matrix.const_cast_derived(), other.derived()._expression()); + >::run(m_matrix.const_cast_derived(), other.derived().nestedExpression()); } /*************************************************************************** @@ -571,7 +571,7 @@ void TriangularBase::evalToLazy(MatrixBase &other) const ::ExpressionType, Derived::Mode, unroll ? int(DenseDerived::SizeAtCompileTime) : Dynamic, true // clear the opposite triangular part - >::run(other.derived(), derived()._expression()); + >::run(other.derived(), derived().nestedExpression()); } /*************************************************************************** From 15c0a78c6ed2b2442d374d5c7d7ed81fa03c381f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Sat, 30 Jan 2010 17:24:18 +0100 Subject: [PATCH 050/109] One warning less... --- test/redux.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/redux.cpp b/test/redux.cpp index f95e8b29c..511df1d22 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -45,7 +45,6 @@ template void matrixRedux(const MatrixType& m) maxc = std::max(ei_real(maxc), ei_real(m1(i,j))); } const Scalar mean = s/Scalar(rows*cols); - const Scalar other_mean = m1.mean(); VERIFY_IS_APPROX(m1.sum(), s); VERIFY_IS_APPROX(m1.mean(), mean); From dd817361f5eef9a72d920a29ada56f69bd0b410c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 31 Jan 2010 12:28:16 +0100 Subject: [PATCH 051/109] use unrolled product path for small outer product --- Eigen/src/Core/Product.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 400ff06f3..c6bd21961 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -92,6 +92,7 @@ template<> struct ei_product_type_selector<1, 1, 1> template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; +template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = GemvProduct }; }; From 08f154b93ad7f1bb3e67aa069412eaad0df4d0e5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Feb 2010 11:44:44 +0100 Subject: [PATCH 052/109] remove some trailing nestbyvalue --- Eigen/src/Core/DiagonalMatrix.h | 4 ++-- Eigen/src/Core/MatrixBase.h | 5 ++--- Eigen/src/Core/NestByValue.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index bd23b2e09..08c046611 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -68,10 +68,10 @@ class DiagonalBase : public AnyMatrixBase const DiagonalProduct operator*(const MatrixBase &matrix) const; - inline const DiagonalWrapper, DiagonalVectorType> > > + inline const DiagonalWrapper, DiagonalVectorType> > inverse() const { - return diagonal().cwiseInverse().nestByValue(); + return diagonal().cwiseInverse(); } }; diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 62aed3b7f..e599a9e03 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -119,8 +119,8 @@ template class MatrixBase /** \brief The plain matrix type corresponding to this expression. * - * This is not necessarily exactly the return type of eval(). In the case of plain matrices, - * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed * that the return type of eval() is either PlainMatrixType or const PlainMatrixType&. */ typedef Matrix::Scalar, @@ -278,7 +278,6 @@ template class MatrixBase NoAlias noalias(); - inline const NestByValue nestByValue() const; inline const ForceAlignedAccess forceAlignedAccess() const; inline ForceAlignedAccess forceAlignedAccess(); template inline const typename ei_meta_if,Derived&>::ret forceAlignedAccessIf() const; diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h index d70ab1ecb..9f6d1c0c0 100644 --- a/Eigen/src/Core/NestByValue.h +++ b/Eigen/src/Core/NestByValue.h @@ -109,7 +109,7 @@ template class NestByValue */ template inline const NestByValue -MatrixBase::nestByValue() const +DenseBase::nestByValue() const { return NestByValue(derived()); } From 7c41fb66f864b7584eac12247fb3945e2ce99f26 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Feb 2010 11:45:08 +0100 Subject: [PATCH 053/109] fix compilation on 32bits systems --- Eigen/src/LU/arch/Inverse_SSE.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/LU/arch/Inverse_SSE.h b/Eigen/src/LU/arch/Inverse_SSE.h index 2ad371a7b..9da39bf20 100644 --- a/Eigen/src/LU/arch/Inverse_SSE.h +++ b/Eigen/src/LU/arch/Inverse_SSE.h @@ -158,8 +158,8 @@ struct ei_compute_inverse_size4 Date: Tue, 2 Feb 2010 09:27:41 +0100 Subject: [PATCH 054/109] Fixes #89. Added regression test. --- Eigen/src/Geometry/AngleAxis.h | 10 ++++++++++ test/geo_transformations.cpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/Eigen/src/Geometry/AngleAxis.h b/Eigen/src/Geometry/AngleAxis.h index da698bbfe..284c60a74 100644 --- a/Eigen/src/Geometry/AngleAxis.h +++ b/Eigen/src/Geometry/AngleAxis.h @@ -189,6 +189,16 @@ AngleAxis& AngleAxis::operator=(const MatrixBase& mat) return *this = QuaternionType(mat); } +/** +* \brief Sets \c *this from a 3x3 rotation matrix. +**/ +template +template +AngleAxis& AngleAxis::fromRotationMatrix(const MatrixBase& mat) +{ + return *this = QuaternionType(mat); +} + /** Constructs and \returns an equivalent 3x3 rotation matrix. */ template diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index fc542e71b..895fe0f08 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -85,6 +85,10 @@ template void transformations(void) VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1); + aa.fromRotationMatrix(aa.toRotationMatrix()); + VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); + VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1); + // AngleAxis VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(), Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix()); From 8861dce7eeac5bf16f28a0d0e3c73cc57abbcf65 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 3 Feb 2010 09:07:17 +0100 Subject: [PATCH 055/109] Fixed 32bit builds. --- Eigen/src/Core/CwiseNullaryOp.h | 10 +++++----- Eigen/src/Core/DenseBase.h | 6 +++--- Eigen/src/plugins/MatrixCwiseUnaryOps.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index f4dd0b695..5800335d7 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -238,11 +238,11 @@ DenseBase::Constant(const Scalar& value) * Example: \include DenseBase_LinSpaced_seq.cpp * Output: \verbinclude DenseBase_LinSpaced_seq.out * - * \sa setLinSpaced(Scalar,Scalar,int), LinSpaced(Scalar,Scalar,int), CwiseNullaryOp + * \sa setLinSpaced(const Scalar&,const Scalar&,int), LinSpaced(Scalar,Scalar,int), CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType -DenseBase::LinSpaced(Sequential_t, Scalar low, Scalar high, int size) +DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high, int size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return NullaryExpr(size, ei_linspaced_op(low,high,size)); @@ -258,11 +258,11 @@ DenseBase::LinSpaced(Sequential_t, Scalar low, Scalar high, int size) * Example: \include DenseBase_LinSpaced.cpp * Output: \verbinclude DenseBase_LinSpaced.out * - * \sa setLinSpaced(Scalar,Scalar,int), LinSpaced(Sequential_t,Scalar,Scalar,int), CwiseNullaryOp + * \sa setLinSpaced(const Scalar&,const Scalar&,int), LinSpaced(Sequential_t,const Scalar&,const Scalar&,int), CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType -DenseBase::LinSpaced(Scalar low, Scalar high, int size) +DenseBase::LinSpaced(const Scalar& low, const Scalar& high, int size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return NullaryExpr(size, ei_linspaced_op(low,high,size)); @@ -358,7 +358,7 @@ DenseStorageBase::setConstant(int rows, int cols, const * \sa CwiseNullaryOp */ template -EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Scalar low, Scalar high, int size) +EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high, int size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return derived() = Derived::NullaryExpr(size, ei_linspaced_op(low,high,size)); diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index e0a3a04af..a2165b52f 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -348,9 +348,9 @@ template class DenseBase Constant(const Scalar& value); static const SequentialLinSpacedReturnType - LinSpaced(Sequential_t, Scalar low, Scalar high, int size); + LinSpaced(Sequential_t, const Scalar& low, const Scalar& high, int size); static const RandomAccessLinSpacedReturnType - LinSpaced(Scalar low, Scalar high, int size); + LinSpaced(const Scalar& low, const Scalar& high, int size); template static const CwiseNullaryOp @@ -371,7 +371,7 @@ template class DenseBase void fill(const Scalar& value); Derived& setConstant(const Scalar& value); - Derived& setLinSpaced(Scalar low, Scalar high, int size); + Derived& setLinSpaced(const Scalar& low, const Scalar& high, int size); Derived& setZero(); Derived& setOnes(); Derived& setRandom(); diff --git a/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/Eigen/src/plugins/MatrixCwiseUnaryOps.h index d75e229fb..8927711ed 100644 --- a/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -75,7 +75,7 @@ cwiseInverse() const { return derived(); } * \sa cwiseEqual(const MatrixBase &) const */ inline const CwiseUnaryOp >,Derived> -cwiseEqual(Scalar s) const +cwiseEqual(const Scalar& s) const { return CwiseUnaryOp >,Derived> (derived(), std::bind1st(std::equal_to(), s)); From 05837be8fb373d69840c5a1b0a0be14a1c52639b Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 3 Feb 2010 09:46:27 +0100 Subject: [PATCH 056/109] Fixed a warning. Transform::Identity() is now returning a Transform. --- Eigen/src/Geometry/Quaternion.h | 2 +- Eigen/src/Geometry/Transform.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 285a93c15..98b91e2de 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -573,7 +573,7 @@ QuaternionBase::angularDistance(const QuaternionBase& oth double d = ei_abs(this->dot(other)); if (d>=1.0) return Scalar(0); - return Scalar(2) * std::acos(d); + return static_cast(2 * std::acos(d)); } /** \returns the spherical linear interpolation between the two quaternions diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index b945ea43f..309c1e1fd 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -345,9 +345,14 @@ public: /** \sa MatrixBase::setIdentity() */ void setIdentity() { m_matrix.setIdentity(); } - static const typename MatrixType::IdentityReturnType Identity() + + /** + * \brief Returns an identity transformation. + * \todo In the future this function should be returning a Transform expression. + */ + static const Transform Identity() { - return MatrixType::Identity(); + return Transform(MatrixType::Identity()); } template From 1a77334d5435f8edd6d7d756222207a8e3f268a6 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 3 Feb 2010 19:20:25 +0100 Subject: [PATCH 057/109] Silenced type conversion warnings. --- test/nullary.cpp | 4 ++-- test/redux.cpp | 3 ++- unsupported/Eigen/FFT | 12 +++++++++--- .../Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h | 10 +++++----- unsupported/test/FFT.cpp | 4 ++-- unsupported/test/matrix_function.cpp | 5 +++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/test/nullary.cpp b/test/nullary.cpp index 240365529..3adfc33fe 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -50,8 +50,8 @@ template void testVectorType(const VectorType& base) { typedef typename ei_traits::Scalar Scalar; - Scalar low = ei_random(-500,500); - Scalar high = ei_random(-500,500); + Scalar low = ei_random(-500,500); + Scalar high = ei_random(-500,500); if (low>high) std::swap(low,high); const int size = base.size(); const Scalar step = (high-low)/(size-1); diff --git a/test/redux.cpp b/test/redux.cpp index 511df1d22..2dc4dcc45 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -27,6 +27,7 @@ template void matrixRedux(const MatrixType& m) { typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; int rows = m.rows(); int cols = m.cols(); @@ -44,7 +45,7 @@ template void matrixRedux(const MatrixType& m) minc = std::min(ei_real(minc), ei_real(m1(i,j))); maxc = std::max(ei_real(maxc), ei_real(m1(i,j))); } - const Scalar mean = s/Scalar(rows*cols); + const Scalar mean = s/Scalar(RealScalar(rows*cols)); VERIFY_IS_APPROX(m1.sum(), s); VERIFY_IS_APPROX(m1.mean(), mean); diff --git a/unsupported/Eigen/FFT b/unsupported/Eigen/FFT index 8702120de..0cc10bafb 100644 --- a/unsupported/Eigen/FFT +++ b/unsupported/Eigen/FFT @@ -187,7 +187,7 @@ class FFT { m_impl.inv( dst,src,nfft ); if ( HasFlag( Unscaled ) == false) - scale(dst,1./nfft,nfft); + scale(dst,_Scalar(1./nfft),nfft); } inline @@ -237,8 +237,14 @@ class FFT private: template - inline - void scale(_It x,_Val s,int nx) + inline void scale(_It x,_Val s,int nx) + { + for (int k=0;k + inline void scale(std::complex<_Val>* x,_Val s,int nx) { for (int k=0;k::compute(const MatrixType& A) { // TODO: Use that A is upper triangular m_Arows = A.rows(); - m_avgEival = A.trace() / Scalar(m_Arows); + m_avgEival = A.trace() / Scalar(RealScalar(m_Arows)); m_Ashifted = A - m_avgEival * MatrixType::Identity(m_Arows, m_Arows); computeMu(); MatrixType F = m_f(m_avgEival, 0) * MatrixType::Identity(m_Arows, m_Arows); @@ -94,7 +94,7 @@ MatrixType MatrixFunctionAtomic::compute(const MatrixType& A) for (int s = 1; s < 1.1 * m_Arows + 10; s++) { // upper limit is fairly arbitrary Fincr = m_f(m_avgEival, s) * P; F += Fincr; - P = (1/(s + 1.0)) * P * m_Ashifted; + P = Scalar(RealScalar(1.0/(s + 1))) * P * m_Ashifted; if (taylorConverged(s, F, Fincr, P)) { return F; } @@ -127,9 +127,9 @@ bool MatrixFunctionAtomic::taylorConverged(int s, const MatrixType& for (int r = 0; r < n; r++) { RealScalar mx = 0; for (int i = 0; i < n; i++) - mx = std::max(mx, std::abs(m_f(m_Ashifted(i, i) + m_avgEival, s+r))); - if (r != 0) - rfactorial *= r; + mx = std::max(mx, std::abs(m_f(m_Ashifted(i, i) + m_avgEival, s+r))); + if (r != 0) + rfactorial *= RealScalar(r); delta = std::max(delta, mx / rfactorial); } const RealScalar P_norm = P.cwiseAbs().rowwise().sum().maxCoeff(); diff --git a/unsupported/test/FFT.cpp b/unsupported/test/FFT.cpp index 056be2ef3..9c2682724 100644 --- a/unsupported/test/FFT.cpp +++ b/unsupported/test/FFT.cpp @@ -46,10 +46,10 @@ complex promote(long double x) { return complex( x); long double difpower=0; cerr <<"idx\ttruth\t\tvalue\t|dif|=\n"; long double pi = acos((long double)-1); - for (int k0=0;k0(fftbuf.size());++k0) { complex acc = 0; long double phinc = -2.*k0* pi / timebuf.size(); - for (int k1=0;k1(timebuf.size());++k1) { acc += promote( timebuf[k1] ) * exp( complex(0,k1*phinc) ); } totalpower += norm(acc); diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index 3e25c6a6f..446fa7ec3 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -33,14 +33,15 @@ template MatrixType createRandomMatrix(const int size) { typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; MatrixType result; if (ei_random(0,1) == 0) { result = MatrixType::Random(size, size); } else { MatrixType diag = MatrixType::Zero(size, size); for (int i = 0; i < size; ++i) { - diag(i, i) = static_cast(ei_random(0,2)) - + ei_random() * static_cast(0.01); + diag(i, i) = Scalar(RealScalar(ei_random(0,2))) + + ei_random() * Scalar(RealScalar(0.01)); } MatrixType A = MatrixType::Random(size, size); result = A.inverse() * diag * A; From d0b4ef81f01147532fca38c4cff2be354288a00d Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 4 Feb 2010 14:26:03 +0100 Subject: [PATCH 058/109] Prevent temporaries for reductions. --- Eigen/src/Core/Redux.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 09538a3bd..99fec2528 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -313,10 +313,9 @@ template inline typename ei_result_of::Scalar)>::type DenseBase::redux(const Func& func) const { - typename Derived::Nested nested(derived()); typedef typename ei_cleantype::type ThisNested; return ei_redux_impl - ::run(nested, func); + ::run(derived(), func); } /** \returns the minimum of all coefficients of *this From b44240180fdefc07fb576cc107c99aa60989eba9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 4 Feb 2010 17:17:57 +0100 Subject: [PATCH 059/109] optiization: make hybrid small/large outer products use the unrolled path --- Eigen/src/Core/Product.h | 2 ++ Eigen/src/Core/ProductBase.h | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index c6bd21961..7cfdee6cf 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -93,6 +93,8 @@ template<> struct ei_product_type_selector template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; +template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; +template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = GemvProduct }; }; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 44dd587d9..4e5490d6a 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -47,13 +47,6 @@ struct ei_traits > //: ei_traits -struct ei_nested, N, EvalType> -{ - typedef EvalType type; -}; - #define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ typedef ProductBase Base; \ EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ From 73eb0e633c506e86f20fa231269b5cd81ebd083c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 4 Feb 2010 18:28:09 +0100 Subject: [PATCH 060/109] * resurected Flagged from Eigen2Support * reimplement .diagonal() for ProductBase to make (A*B).diagonal() more efficient! --- Eigen/Core | 1 + Eigen/Eigen2Support | 1 - Eigen/src/{Eigen2Support => Core}/Flagged.h | 58 +-------------- Eigen/src/Core/Product.h | 2 - Eigen/src/Core/ProductBase.h | 28 ++++++- Eigen/src/Eigen2Support/Lazy.h | 82 +++++++++++++++++++++ 6 files changed, 111 insertions(+), 61 deletions(-) rename Eigen/src/{Eigen2Support => Core}/Flagged.h (70%) diff --git a/Eigen/Core b/Eigen/Core index 12c8ea97f..b6e383210 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -199,6 +199,7 @@ struct Dense {}; #include "src/Core/IO.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" +#include "src/Core/Flagged.h" #include "src/Core/ProductBase.h" #include "src/Core/Product.h" #include "src/Core/TriangularMatrix.h" diff --git a/Eigen/Eigen2Support b/Eigen/Eigen2Support index 9e3bff68f..bd6306aff 100644 --- a/Eigen/Eigen2Support +++ b/Eigen/Eigen2Support @@ -42,7 +42,6 @@ namespace Eigen { * */ -#include "src/Eigen2Support/Flagged.h" #include "src/Eigen2Support/Lazy.h" #include "src/Eigen2Support/Cwise.h" #include "src/Eigen2Support/CwiseOperators.h" diff --git a/Eigen/src/Eigen2Support/Flagged.h b/Eigen/src/Core/Flagged.h similarity index 70% rename from Eigen/src/Eigen2Support/Flagged.h rename to Eigen/src/Core/Flagged.h index 470db1d7b..af00a68be 100644 --- a/Eigen/src/Eigen2Support/Flagged.h +++ b/Eigen/src/Core/Flagged.h @@ -25,9 +25,7 @@ #ifndef EIGEN_FLAGGED_H #define EIGEN_FLAGGED_H -/** \deprecated it is only used by lazy() which is deprecated - * - * \class Flagged +/** \class Flagged * * \brief Expression with modified flags * @@ -120,58 +118,4 @@ template clas ExpressionTypeNested m_matrix; }; -/** \deprecated it is only used by lazy() which is deprecated - * - * \returns an expression of *this with added flags - * - * Example: \include MatrixBase_marked.cpp - * Output: \verbinclude MatrixBase_marked.out - * - * \sa class Flagged, extract(), part() - */ -template -template -inline const Flagged -MatrixBase::marked() const -{ - return derived(); -} - -/** \deprecated use MatrixBase::noalias() - * - * \returns an expression of *this with the EvalBeforeAssigningBit flag removed. - * - * Example: \include MatrixBase_lazy.cpp - * Output: \verbinclude MatrixBase_lazy.out - * - * \sa class Flagged, marked() - */ -template -inline const Flagged -MatrixBase::lazy() const -{ - return derived(); -} - - -/** \internal - * Overloaded to perform an efficient C += (A*B).lazy() */ -template -template -Derived& MatrixBase::operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other) -{ - other._expression().derived().addTo(derived()); return derived(); -} - -/** \internal - * Overloaded to perform an efficient C -= (A*B).lazy() */ -template -template -Derived& MatrixBase::operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other) -{ - other._expression().derived().subTo(derived()); return derived(); -} - #endif // EIGEN_FLAGGED_H diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 7cfdee6cf..d7f17dd28 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -54,8 +54,6 @@ enum { Small = Dynamic/2 }; -enum { OuterProduct, InnerProduct, UnrolledProduct, GemvProduct, GemmProduct }; - template struct ei_product_type { typedef typename ei_cleantype::type _Lhs; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 4e5490d6a..ef986baaa 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -25,6 +25,8 @@ #ifndef EIGEN_PRODUCTBASE_H #define EIGEN_PRODUCTBASE_H +enum { OuterProduct, InnerProduct, UnrolledProduct, GemvProduct, GemmProduct }; + /** \class ProductBase * */ @@ -69,7 +71,7 @@ class ProductBase : public MatrixBase public: typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - + protected: typedef typename Lhs::Nested LhsNested; typedef typename ei_cleantype::type _LhsNested; typedef ei_blas_traits<_LhsNested> LhsBlasTraits; @@ -82,6 +84,10 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; + typedef typename ProductReturnType::Type CoeffBaseProductType; + typedef Flagged LazyCoeffBaseProductType; + public: + typedef typename Base::PlainMatrixType PlainMatrixType; ProductBase(const Lhs& lhs, const Rhs& rhs) @@ -113,6 +119,26 @@ class ProductBase : public MatrixBase const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } + const Diagonal diagonal() const + { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + + Diagonal diagonal() + { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + + template + const Diagonal diagonal() const + { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + + template + Diagonal diagonal() + { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + + const Diagonal diagonal(int index) const + { return Diagonal(LazyCoeffBaseProductType(CoeffBaseProductType(m_lhs, m_rhs))).diagonal(index); } + + Diagonal diagonal(int index) + { return Diagonal(LazyCoeffBaseProductType(CoeffBaseProductType(m_lhs, m_rhs))).diagonal(index); } + protected: const LhsNested m_lhs; diff --git a/Eigen/src/Eigen2Support/Lazy.h b/Eigen/src/Eigen2Support/Lazy.h index e69de29bb..c4288ede2 100644 --- a/Eigen/src/Eigen2Support/Lazy.h +++ b/Eigen/src/Eigen2Support/Lazy.h @@ -0,0 +1,82 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Benoit Jacob +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_LAZY_H +#define EIGEN_LAZY_H + +/** \deprecated it is only used by lazy() which is deprecated + * + * \returns an expression of *this with added flags + * + * Example: \include MatrixBase_marked.cpp + * Output: \verbinclude MatrixBase_marked.out + * + * \sa class Flagged, extract(), part() + */ +template +template +inline const Flagged +MatrixBase::marked() const +{ + return derived(); +} + +/** \deprecated use MatrixBase::noalias() + * + * \returns an expression of *this with the EvalBeforeAssigningBit flag removed. + * + * Example: \include MatrixBase_lazy.cpp + * Output: \verbinclude MatrixBase_lazy.out + * + * \sa class Flagged, marked() + */ +template +inline const Flagged +MatrixBase::lazy() const +{ + return derived(); +} + + +/** \internal + * Overloaded to perform an efficient C += (A*B).lazy() */ +template +template +Derived& MatrixBase::operator+=(const Flagged, 0, + EvalBeforeAssigningBit>& other) +{ + other._expression().derived().addTo(derived()); return derived(); +} + +/** \internal + * Overloaded to perform an efficient C -= (A*B).lazy() */ +template +template +Derived& MatrixBase::operator-=(const Flagged, 0, + EvalBeforeAssigningBit>& other) +{ + other._expression().derived().subTo(derived()); return derived(); +} + +#endif // EIGEN_LAZY_H From 52167be4c8a2ea72213ebbd9ce828eeb3dcff5f3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 4 Feb 2010 18:51:29 +0100 Subject: [PATCH 061/109] make sure the correct diagoanl() function is called in trace() --- Eigen/src/Core/Redux.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 99fec2528..42287dab9 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -49,7 +49,7 @@ private: MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) && (ei_functor_traits::PacketAccess), MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), - MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize + MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize }; public: @@ -58,7 +58,7 @@ public: : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(DefaultTraversal) }; - + private: enum { Cost = Derived::SizeAtCompileTime * Derived::CoeffReadCost @@ -123,7 +123,7 @@ struct ei_redux_novec_unroller }; /*** vectorization ***/ - + template struct ei_redux_vec_unroller { @@ -223,7 +223,7 @@ struct ei_redux_impl for(int index = alignedStart + packetSize; index < alignedEnd; index += packetSize) packet_res = func.packetOp(packet_res, mat.template packet(index)); res = func.predux(packet_res); - + for(int index = 0; index < alignedStart; ++index) res = func(res,mat.coeff(index)); @@ -265,7 +265,7 @@ struct ei_redux_impl for(int i=0; i (isRowMajor?j:i, isRowMajor?i:j)); - + res = func.predux(packet_res); for(int j=0; j EIGEN_STRONG_INLINE typename ei_traits::Scalar MatrixBase::trace() const { - return diagonal().sum(); + return derived().diagonal().sum(); } #endif // EIGEN_REDUX_H From 6f3f8578979b8af3d29abc8bfc17e7995bf54143 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 5 Feb 2010 23:44:24 +0100 Subject: [PATCH 062/109] make noalias works for coefficient based products --- Eigen/src/Core/DenseBase.h | 3 +++ Eigen/src/Core/Flagged.h | 14 ++++++++++++++ Eigen/src/Core/NoAlias.h | 8 ++++++++ Eigen/src/Core/ProductBase.h | 2 -- Eigen/src/Core/util/Constants.h | 2 ++ Eigen/src/Core/util/ForwardDeclarations.h | 1 + 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index a2165b52f..9ef9108e4 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -233,6 +233,9 @@ template class DenseBase CommaInitializer operator<< (const Scalar& s); + template + const Flagged flagged() const; + template CommaInitializer operator<< (const DenseBase& other); diff --git a/Eigen/src/Core/Flagged.h b/Eigen/src/Core/Flagged.h index af00a68be..7f42a1e73 100644 --- a/Eigen/src/Core/Flagged.h +++ b/Eigen/src/Core/Flagged.h @@ -118,4 +118,18 @@ template clas ExpressionTypeNested m_matrix; }; +/** \returns an expression of *this with added and removed flags + * + * This is mostly for internal use. + * + * \sa class Flagged + */ +template +template +inline const Flagged +DenseBase::flagged() const +{ + return derived(); +} + #endif // EIGEN_FLAGGED_H diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index bfea5c91d..e09fd0091 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -69,6 +69,14 @@ class NoAlias template EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) { other.derived().subTo(m_expression); return m_expression; } + + template + EIGEN_STRONG_INLINE ExpressionType& operator+=(const GeneralProduct& other) + { return m_expression.derived() += other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } + + template + EIGEN_STRONG_INLINE ExpressionType& operator-=(const GeneralProduct& other) + { return m_expression.derived() -= other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } #endif protected: diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index ef986baaa..5c51ea27c 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -25,8 +25,6 @@ #ifndef EIGEN_PRODUCTBASE_H #define EIGEN_PRODUCTBASE_H -enum { OuterProduct, InnerProduct, UnrolledProduct, GemvProduct, GemmProduct }; - /** \class ProductBase * */ diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 6ae103e66..c747d970b 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -267,4 +267,6 @@ namespace Architecture enum DenseStorageMatrix {}; enum DenseStorageArray {}; +enum { OuterProduct, InnerProduct, UnrolledProduct, GemvProduct, GemmProduct }; + #endif // EIGEN_CONSTANTS_H diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index b6bba04e6..ac7824dc1 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -51,6 +51,7 @@ template class CwiseUnaryView; template class CwiseBinaryOp; template class SelfCwiseBinaryOp; template class ProductBase; +template class GeneralProduct; template class DiagonalBase; template class DiagonalWrapper; From 871698d3aa3e125561226a08bee9aa2db5dec6aa Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Sat, 6 Feb 2010 17:43:32 +0100 Subject: [PATCH 063/109] Introduced NestParentByRefBit and NestByRefBit - this should fix temporaries related to nested products. Fixed a few typos and a few warnings. --- Eigen/src/Array/Replicate.h | 2 +- Eigen/src/Array/Reverse.h | 4 +- Eigen/src/Array/Select.h | 3 +- Eigen/src/Array/VectorwiseOp.h | 3 +- Eigen/src/Cholesky/LDLT.h | 2 +- Eigen/src/Core/Block.h | 4 +- Eigen/src/Core/Coeffs.h | 2 +- Eigen/src/Core/CwiseBinaryOp.h | 1 + Eigen/src/Core/CwiseNullaryOp.h | 3 +- Eigen/src/Core/CwiseUnaryOp.h | 3 +- Eigen/src/Core/CwiseUnaryView.h | 3 +- Eigen/src/Core/Diagonal.h | 3 +- Eigen/src/Core/DiagonalProduct.h | 3 +- Eigen/src/Core/Minor.h | 3 +- Eigen/src/Core/ProductBase.h | 5 ++- Eigen/src/Core/Redux.h | 2 +- Eigen/src/Core/SelfAdjointView.h | 5 ++- Eigen/src/Core/SelfCwiseBinaryOp.h | 2 +- Eigen/src/Core/StableNorm.h | 4 +- Eigen/src/Core/Transpose.h | 3 +- Eigen/src/Core/TriangularMatrix.h | 3 +- Eigen/src/Core/products/GeneralUnrolled.h | 4 +- Eigen/src/Core/util/Constants.h | 7 ++- Eigen/src/Core/util/XprHelper.h | 53 +++++++++++++---------- Eigen/src/Geometry/Homogeneous.h | 3 +- Eigen/src/LU/FullPivLU.h | 2 +- Eigen/src/Sparse/DynamicSparseMatrix.h | 9 +--- Eigen/src/Sparse/SparseMatrix.h | 9 +--- Eigen/src/Sparse/SparseVector.h | 9 +--- 29 files changed, 84 insertions(+), 75 deletions(-) diff --git a/Eigen/src/Array/Replicate.h b/Eigen/src/Array/Replicate.h index 0b1b58f1b..7e7595e15 100644 --- a/Eigen/src/Array/Replicate.h +++ b/Eigen/src/Array/Replicate.h @@ -55,7 +55,7 @@ struct ei_traits > : ColFactor * MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _MatrixTypeNested::Flags & HereditaryBits, + Flags = (_MatrixTypeNested::Flags & HereditaryBits) | EIGEN_PROPAGATE_NESTING_BIT(MatrixType::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Array/Reverse.h b/Eigen/src/Array/Reverse.h index c908e8d9c..24fcf644b 100644 --- a/Eigen/src/Array/Reverse.h +++ b/Eigen/src/Array/Reverse.h @@ -59,7 +59,9 @@ struct ei_traits > LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) ? LinearAccessBit : 0, - Flags = (int(_MatrixTypeNested::Flags) & (HereditaryBits | PacketAccessBit | LinearAccess)), + Flags = (int(_MatrixTypeNested::Flags) + & (HereditaryBits | PacketAccessBit | LinearAccess)) + | EIGEN_PROPAGATE_NESTING_BIT(MatrixType::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; diff --git a/Eigen/src/Array/Select.h b/Eigen/src/Array/Select.h index 38c1a716f..bcb233c80 100644 --- a/Eigen/src/Array/Select.h +++ b/Eigen/src/Array/Select.h @@ -55,7 +55,8 @@ struct ei_traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, + Flags = ((unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits) + | EIGEN_PROPAGATE_NESTING_BIT(ConditionMatrixType::Flags|ThenMatrixType::Flags|ElseMatrixType::Flags), CoeffReadCost = ei_traits::type>::CoeffReadCost + EIGEN_ENUM_MAX(ei_traits::type>::CoeffReadCost, ei_traits::type>::CoeffReadCost) diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index 697a07d32..bf5750b13 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -60,7 +60,8 @@ struct ei_traits > ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits, + Flags = ((unsigned int)_MatrixTypeNested::Flags & HereditaryBits) + | EIGEN_PROPAGATE_NESTING_BIT(_MatrixTypeNested::Flags), TraversalSize = Direction==Vertical ? RowsAtCompileTime : ColsAtCompileTime }; #if EIGEN_GNUC_AT_LEAST(3,4) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 8b13d8e2e..54bd2d58a 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -206,7 +206,7 @@ LDLT& LDLT::compute(const MatrixType& a) // in "Analysis of the Cholesky Decomposition of a Semi-definite Matrix" by // Nicholas J. Higham. Also see "Accuracy and Stability of Numerical // Algorithms" page 217, also by Higham. - cutoff = ei_abs(epsilon() * size * biggest_in_corner); + cutoff = ei_abs(epsilon() * RealScalar(size) * biggest_in_corner); m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; } diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 3b4234c22..244f33ca1 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -76,7 +76,9 @@ struct ei_traits > MaskPacketAccessBit = (InnerMaxSize == Dynamic || (InnerSize >= ei_packet_traits::size)) ? PacketAccessBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, - Flags = (ei_traits::Flags & (HereditaryBits | MaskPacketAccessBit | DirectAccessBit)) | FlagsLinearAccessBit + Flags = (ei_traits::Flags & (HereditaryBits | MaskPacketAccessBit | DirectAccessBit)) + | FlagsLinearAccessBit + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags) }; }; diff --git a/Eigen/src/Core/Coeffs.h b/Eigen/src/Core/Coeffs.h index ebfd0c80e..77f0ea544 100644 --- a/Eigen/src/Core/Coeffs.h +++ b/Eigen/src/Core/Coeffs.h @@ -343,7 +343,7 @@ template EIGEN_STRONG_INLINE void DenseBase::copyCoeff(int index, const DenseBase& other) { ei_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); + derived().coeffRef(index) = Scalar(other.derived().coeff(index)); } /** \internal Copies the packet at position (row,col) of other into *this. diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 9ed005dce..a39f206cf 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -72,6 +72,7 @@ struct ei_traits > : ei_traits ( AlignedBit | (StorageOrdersAgree ? LinearAccessBit : 0) | (ei_functor_traits::PacketAccess && StorageOrdersAgree ? PacketAccessBit : 0) + | EIGEN_PROPAGATE_NESTING_BIT(Lhs::Flags|Rhs::Flags) ) ) ), diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index 5800335d7..e4880e5d0 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -48,7 +48,8 @@ struct ei_traits > : ei_traits & ( HereditaryBits | (ei_functor_has_linear_access::ret ? LinearAccessBit : 0) | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (ei_functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + | (ei_functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index b51bd51af..b519e3b1d 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -51,7 +51,8 @@ struct ei_traits > enum { Flags = (_MatrixTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit - | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0))), + | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0))) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost + ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 2198ed226..deef14597 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -47,7 +47,8 @@ struct ei_traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename ei_cleantype::type _MatrixTypeNested; enum { - Flags = (ei_traits<_MatrixTypeNested>::Flags & (HereditaryBits | LinearAccessBit | AlignedBit)), + Flags = (ei_traits<_MatrixTypeNested>::Flags & (HereditaryBits | LinearAccessBit | AlignedBit)) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), // if I am not wrong, I need to test this on MatrixType and not on the nested type CoeffReadCost = ei_traits<_MatrixTypeNested>::CoeffReadCost + ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 3720952cd..4f8bc01c3 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -58,7 +58,8 @@ struct ei_traits > : Index == Dynamic ? EIGEN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) : (EIGEN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) - AbsIndex), MaxColsAtCompileTime = 1, - Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit), + Flags = ((unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit)) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index 868b4419a..7871e7704 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -37,7 +37,8 @@ struct ei_traits > MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, Flags = (HereditaryBits & (unsigned int)(MatrixType::Flags)) - | (PacketAccessBit & (unsigned int)(MatrixType::Flags) & (unsigned int)(DiagonalType::DiagonalVectorType::Flags)), + | (PacketAccessBit & (unsigned int)(MatrixType::Flags) & (unsigned int)(DiagonalType::DiagonalVectorType::Flags)) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost }; }; diff --git a/Eigen/src/Core/Minor.h b/Eigen/src/Core/Minor.h index e7e164a16..aa7739370 100644 --- a/Eigen/src/Core/Minor.h +++ b/Eigen/src/Core/Minor.h @@ -53,7 +53,8 @@ struct ei_traits > int(MatrixType::MaxRowsAtCompileTime) - 1 : Dynamic, MaxColsAtCompileTime = (MatrixType::MaxColsAtCompileTime != Dynamic) ? int(MatrixType::MaxColsAtCompileTime) - 1 : Dynamic, - Flags = _MatrixTypeNested::Flags & HereditaryBits, + Flags = (_MatrixTypeNested::Flags & HereditaryBits) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost // minor is used typically on tiny matrices, // where loops are unrolled and the 'if' evaluates at compile time }; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 5c51ea27c..94f01f55e 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -42,7 +42,10 @@ struct ei_traits > //: ei_traits::ColsAtCompileTime, MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = ei_traits::MaxColsAtCompileTime, - Flags = EvalBeforeNestingBit | EvalBeforeAssigningBit, + Flags = EvalBeforeNestingBit + | EvalBeforeAssigningBit + | NestParentByRefBit + | EIGEN_PROPAGATE_NESTING_BIT(Lhs::Flags|Rhs::Flags), CoeffReadCost = 0 // FIXME why is it needed ? }; }; diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 42287dab9..d5b0c60c2 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -355,7 +355,7 @@ template EIGEN_STRONG_INLINE typename ei_traits::Scalar DenseBase::mean() const { - return this->redux(Eigen::ei_scalar_sum_op()) / Scalar(this->size()); + return Scalar(this->redux(Eigen::ei_scalar_sum_op())) / Scalar(this->size()); } /** \returns the product of all coefficients of *this diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 6d01ee495..9f1893c4a 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -47,8 +47,9 @@ struct ei_traits > : ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 7ae2e82a4..c403a4f55 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -90,7 +90,7 @@ template class SelfCwiseBinaryOp OtherDerived& _other = other.const_cast_derived(); ei_internal_assert(index >= 0 && index < m_matrix.size()); Scalar& tmp = m_matrix.coeffRef(index); - tmp = m_functor(tmp, _other.coeff(index)); + tmp = m_functor(tmp, Scalar(_other.coeff(index))); } template diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index b4d6aa353..70371d8ba 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -118,10 +118,10 @@ MatrixBase::blueNorm() const iexp = - ((iemax+it)/2); s2m = RealScalar(std::pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for upper range - overfl = rbig*s2m; // overfow boundary for abig + overfl = rbig*s2m; // overflow boundary for abig eps = RealScalar(std::pow(double(ibeta), 1-it)); relerr = ei_sqrt(eps); // tolerance for neglecting asml - abig = 1.0/eps - 1.0; + abig = RealScalar(1.0/eps - 1.0); if (RealScalar(nbig)>abig) nmax = int(abig); // largest safe n else nmax = nbig; } diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 143b39033..18e4a1739 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -50,7 +50,8 @@ struct ei_traits > : ei_traits ColsAtCompileTime = MatrixType::RowsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - Flags = (int(_MatrixTypeNested::Flags) ^ RowMajorBit), + Flags = (int(_MatrixTypeNested::Flags & ~NestByRefBit) ^ RowMajorBit) + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 8bea0aa68..e6690b6fa 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -130,7 +130,8 @@ struct ei_traits > : ei_traits typedef MatrixType ExpressionType; enum { Mode = _Mode, - Flags = (_MatrixTypeNested::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, + Flags = (_MatrixTypeNested::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/products/GeneralUnrolled.h b/Eigen/src/Core/products/GeneralUnrolled.h index 32aa3afe6..a8fec1fac 100644 --- a/Eigen/src/Core/products/GeneralUnrolled.h +++ b/Eigen/src/Core/products/GeneralUnrolled.h @@ -81,8 +81,10 @@ struct ei_traits > Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) | EvalBeforeAssigningBit | EvalBeforeNestingBit + | NestParentByRefBit | (CanVectorizeLhs || CanVectorizeRhs ? PacketAccessBit : 0) - | (LhsFlags & RhsFlags & AlignedBit), + | (LhsFlags & RhsFlags & AlignedBit) + | EIGEN_PROPAGATE_NESTING_BIT(LhsFlags|RhsFlags), CoeffReadCost = InnerSize == Dynamic ? Dynamic : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index c747d970b..1b34b401d 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -35,7 +35,7 @@ * - It should be smaller than the sqrt of INT_MAX. Indeed, we often multiply a number of rows with a number * of columns in order to compute a number of coefficients. Even if we guard that with an "if" checking whether * the values are Dynamic, we still get a compiler warning "integer overflow". So the only way to get around - * it would be a meta-selector. Doing this everywhere would reduce code readability and lenghten compilation times. + * it would be a meta-selector. Doing this everywhere would reduce code readability and lengthen compilation times. * 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. * @@ -76,7 +76,7 @@ const unsigned int EvalBeforeNestingBit = 0x2; /** \ingroup flags * - * means the expression should be evaluated before any assignement */ + * means the expression should be evaluated before any assignment */ const unsigned int EvalBeforeAssigningBit = 0x4; /** \ingroup flags @@ -97,6 +97,9 @@ const unsigned int EvalBeforeAssigningBit = 0x4; */ const unsigned int PacketAccessBit = 0x8; +const unsigned int NestParentByRefBit = 0x80; +const unsigned int NestByRefBit = 0x100; + #ifdef EIGEN_VECTORIZE /** \ingroup flags * diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 136cc876b..77b3968b1 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -97,7 +97,7 @@ class ei_compute_matrix_flags }; public: - enum { ret = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit | aligned_bit }; + enum { ret = LinearAccessBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit }; }; template struct ei_size_at_compile_time @@ -201,6 +201,28 @@ template struct ei_plain_matrix_type_row_major // we should be able to get rid of this one too template struct ei_must_nest_by_value { enum { ret = false }; }; +template +struct ei_is_reference +{ +#ifndef NDEBUG + static void check() { std::cout << typeid(T).name() << std::endl; } +#else + static void check() {} +#endif + enum { ret = false }; +}; + +template +struct ei_is_reference +{ +#ifndef NDEBUG + static void check() { std::cout << typeid(T).name() << "&" << std::endl; } +#else + static void check() {} +#endif + enum { ret = true }; +}; + /** * The reference selector for template expressions. The idea is that we don't * need to use references for expressions since they are light weight proxy @@ -209,31 +231,14 @@ template struct ei_must_nest_by_value { enum { ret = false }; }; template struct ei_ref_selector { - typedef T type; + typedef typename ei_meta_if< + bool(ei_traits::Flags & NestByRefBit), + T const&, + T + >::ret type; }; -/** -* Matrices on the other hand side should only be copied, when it is sure -* we gain by copying (see arithmetic cost check and eval before nesting flag). -* Note: This is an optimization measure that comprises potential (though little) -* to create erroneous code. Any user, utilizing ei_nested outside of -* Eigen needs to take care that no references to temporaries are -* stored or that this potential danger is at least communicated -* to the user. -**/ -template -struct ei_ref_selector< Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > -{ - typedef Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> MatrixType; - typedef MatrixType const& type; -}; - -template -struct ei_ref_selector< Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > -{ - typedef Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> ArrayType; - typedef ArrayType const& type; -}; +#define EIGEN_PROPAGATE_NESTING_BIT(ReferenceFlags) ((ReferenceFlags) & NestParentByRefBit)<<1 /** \internal Determines how a given expression should be nested into another one. * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 76ca66c57..8c95a4d4d 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -55,7 +55,8 @@ struct ei_traits > ColsAtCompileTime = Direction==Horizontal ? ColsPlusOne : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _MatrixTypeNested::Flags & HereditaryBits, + Flags = _MatrixTypeNested::Flags & HereditaryBits + | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index fe14a9080..657cbbf1c 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -476,7 +476,7 @@ typename ei_traits::Scalar FullPivLU::determinant() cons { ei_assert(m_isInitialized && "LU is not initialized."); ei_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); - return Scalar(m_det_pq) * m_lu.diagonal().prod(); + return Scalar(m_det_pq) * Scalar(m_lu.diagonal().prod()); } /********* Implementation of kernel() **************************************************/ diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index 4373e1cda..96385df50 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -52,19 +52,12 @@ struct ei_traits > ColsAtCompileTime = Dynamic, MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic, - Flags = _Flags, + Flags = _Flags | NestByRefBit, CoeffReadCost = NumTraits::ReadCost, SupportedAccessPatterns = OuterRandomAccessPattern }; }; -template -struct ei_ref_selector< DynamicSparseMatrix<_Scalar, _Options> > -{ - typedef DynamicSparseMatrix<_Scalar, _Options> MatrixType; - typedef MatrixType const& type; -}; - template class DynamicSparseMatrix : public SparseMatrixBase > diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index d884e7df8..bba0404c3 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -51,19 +51,12 @@ struct ei_traits > ColsAtCompileTime = Dynamic, MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic, - Flags = _Options, + Flags = _Options | NestByRefBit, CoeffReadCost = NumTraits::ReadCost, SupportedAccessPatterns = InnerRandomAccessPattern }; }; -template -struct ei_ref_selector > -{ - typedef SparseMatrix<_Scalar, _Options> MatrixType; - typedef MatrixType const& type; -}; - template class SparseMatrix : public SparseMatrixBase > diff --git a/Eigen/src/Sparse/SparseVector.h b/Eigen/src/Sparse/SparseVector.h index 5ac3f6be7..13b4f75a6 100644 --- a/Eigen/src/Sparse/SparseVector.h +++ b/Eigen/src/Sparse/SparseVector.h @@ -46,19 +46,12 @@ struct ei_traits > ColsAtCompileTime = IsColVector ? 1 : Dynamic, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _Options, + Flags = _Options | NestByRefBit, CoeffReadCost = NumTraits::ReadCost, SupportedAccessPatterns = InnerRandomAccessPattern }; }; -template -struct ei_ref_selector< SparseVector<_Scalar, _Options> > -{ - typedef SparseVector<_Scalar, _Options> MatrixType; - typedef MatrixType const& type; -}; - template class SparseVector : public SparseMatrixBase > From 8b016e717fdcbf4f9be34997bb857f52ca34a5b8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 8 Feb 2010 16:51:41 +0100 Subject: [PATCH 064/109] get rid of NestParentByRefBit --- Eigen/src/Array/Replicate.h | 2 +- Eigen/src/Array/Reverse.h | 4 +--- Eigen/src/Array/Select.h | 9 ++++----- Eigen/src/Array/VectorwiseOp.h | 3 +-- Eigen/src/Core/Block.h | 4 +--- Eigen/src/Core/Coeffs.h | 2 +- Eigen/src/Core/CwiseBinaryOp.h | 1 - Eigen/src/Core/CwiseNullaryOp.h | 3 +-- Eigen/src/Core/CwiseUnaryOp.h | 5 ++--- Eigen/src/Core/CwiseUnaryView.h | 3 +-- Eigen/src/Core/Diagonal.h | 3 +-- Eigen/src/Core/DiagonalProduct.h | 3 +-- Eigen/src/Core/Minor.h | 3 +-- Eigen/src/Core/ProductBase.h | 5 +---- Eigen/src/Core/SelfAdjointView.h | 5 ++--- Eigen/src/Core/SelfCwiseBinaryOp.h | 2 +- Eigen/src/Core/Transpose.h | 5 ++--- Eigen/src/Core/TriangularMatrix.h | 3 +-- Eigen/src/Core/products/GeneralUnrolled.h | 4 +--- Eigen/src/Core/util/Constants.h | 1 - Eigen/src/Core/util/XprHelper.h | 24 ----------------------- Eigen/src/Geometry/Homogeneous.h | 3 +-- 22 files changed, 25 insertions(+), 72 deletions(-) diff --git a/Eigen/src/Array/Replicate.h b/Eigen/src/Array/Replicate.h index 7e7595e15..cd23e0d6f 100644 --- a/Eigen/src/Array/Replicate.h +++ b/Eigen/src/Array/Replicate.h @@ -55,7 +55,7 @@ struct ei_traits > : ColFactor * MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = (_MatrixTypeNested::Flags & HereditaryBits) | EIGEN_PROPAGATE_NESTING_BIT(MatrixType::Flags), + Flags = (_MatrixTypeNested::Flags & HereditaryBits), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Array/Reverse.h b/Eigen/src/Array/Reverse.h index 24fcf644b..a405fbb4b 100644 --- a/Eigen/src/Array/Reverse.h +++ b/Eigen/src/Array/Reverse.h @@ -59,9 +59,7 @@ struct ei_traits > LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) ? LinearAccessBit : 0, - Flags = (int(_MatrixTypeNested::Flags) - & (HereditaryBits | PacketAccessBit | LinearAccess)) - | EIGEN_PROPAGATE_NESTING_BIT(MatrixType::Flags), + Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | PacketAccessBit | LinearAccess), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; diff --git a/Eigen/src/Array/Select.h b/Eigen/src/Array/Select.h index bcb233c80..43735bd76 100644 --- a/Eigen/src/Array/Select.h +++ b/Eigen/src/Array/Select.h @@ -55,11 +55,10 @@ struct ei_traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = ((unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits) - | EIGEN_PROPAGATE_NESTING_BIT(ConditionMatrixType::Flags|ThenMatrixType::Flags|ElseMatrixType::Flags), - CoeffReadCost = ei_traits::type>::CoeffReadCost - + EIGEN_ENUM_MAX(ei_traits::type>::CoeffReadCost, - ei_traits::type>::CoeffReadCost) + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, + CoeffReadCost = ei_traits::type>::CoeffReadCost + + EIGEN_ENUM_MAX(ei_traits::type>::CoeffReadCost, + ei_traits::type>::CoeffReadCost) }; }; diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index bf5750b13..697a07d32 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -60,8 +60,7 @@ struct ei_traits > ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime, - Flags = ((unsigned int)_MatrixTypeNested::Flags & HereditaryBits) - | EIGEN_PROPAGATE_NESTING_BIT(_MatrixTypeNested::Flags), + Flags = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits, TraversalSize = Direction==Vertical ? RowsAtCompileTime : ColsAtCompileTime }; #if EIGEN_GNUC_AT_LEAST(3,4) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 244f33ca1..3b4234c22 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -76,9 +76,7 @@ struct ei_traits > MaskPacketAccessBit = (InnerMaxSize == Dynamic || (InnerSize >= ei_packet_traits::size)) ? PacketAccessBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, - Flags = (ei_traits::Flags & (HereditaryBits | MaskPacketAccessBit | DirectAccessBit)) - | FlagsLinearAccessBit - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags) + Flags = (ei_traits::Flags & (HereditaryBits | MaskPacketAccessBit | DirectAccessBit)) | FlagsLinearAccessBit }; }; diff --git a/Eigen/src/Core/Coeffs.h b/Eigen/src/Core/Coeffs.h index 77f0ea544..ebfd0c80e 100644 --- a/Eigen/src/Core/Coeffs.h +++ b/Eigen/src/Core/Coeffs.h @@ -343,7 +343,7 @@ template EIGEN_STRONG_INLINE void DenseBase::copyCoeff(int index, const DenseBase& other) { ei_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = Scalar(other.derived().coeff(index)); + derived().coeffRef(index) = other.derived().coeff(index); } /** \internal Copies the packet at position (row,col) of other into *this. diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index a39f206cf..9ed005dce 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -72,7 +72,6 @@ struct ei_traits > : ei_traits ( AlignedBit | (StorageOrdersAgree ? LinearAccessBit : 0) | (ei_functor_traits::PacketAccess && StorageOrdersAgree ? PacketAccessBit : 0) - | EIGEN_PROPAGATE_NESTING_BIT(Lhs::Flags|Rhs::Flags) ) ) ), diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index e4880e5d0..5800335d7 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -48,8 +48,7 @@ struct ei_traits > : ei_traits & ( HereditaryBits | (ei_functor_has_linear_access::ret ? LinearAccessBit : 0) | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (ei_functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + | (ei_functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), CoeffReadCost = ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index b519e3b1d..9a6bc4bd5 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -49,10 +49,9 @@ struct ei_traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename ei_unref::type _MatrixTypeNested; enum { - Flags = (_MatrixTypeNested::Flags & ( + Flags = _MatrixTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit - | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0))) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + | (ei_functor_traits::PacketAccess ? PacketAccessBit : 0)), CoeffReadCost = _MatrixTypeNested::CoeffReadCost + ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index deef14597..2198ed226 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -47,8 +47,7 @@ struct ei_traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename ei_cleantype::type _MatrixTypeNested; enum { - Flags = (ei_traits<_MatrixTypeNested>::Flags & (HereditaryBits | LinearAccessBit | AlignedBit)) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), // if I am not wrong, I need to test this on MatrixType and not on the nested type + Flags = (ei_traits<_MatrixTypeNested>::Flags & (HereditaryBits | LinearAccessBit | AlignedBit)), CoeffReadCost = ei_traits<_MatrixTypeNested>::CoeffReadCost + ei_functor_traits::Cost }; }; diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 4f8bc01c3..3720952cd 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -58,8 +58,7 @@ struct ei_traits > : Index == Dynamic ? EIGEN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) : (EIGEN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) - AbsIndex), MaxColsAtCompileTime = 1, - Flags = ((unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit)) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit), CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index 7871e7704..868b4419a 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -37,8 +37,7 @@ struct ei_traits > MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, Flags = (HereditaryBits & (unsigned int)(MatrixType::Flags)) - | (PacketAccessBit & (unsigned int)(MatrixType::Flags) & (unsigned int)(DiagonalType::DiagonalVectorType::Flags)) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + | (PacketAccessBit & (unsigned int)(MatrixType::Flags) & (unsigned int)(DiagonalType::DiagonalVectorType::Flags)), CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost }; }; diff --git a/Eigen/src/Core/Minor.h b/Eigen/src/Core/Minor.h index aa7739370..e7e164a16 100644 --- a/Eigen/src/Core/Minor.h +++ b/Eigen/src/Core/Minor.h @@ -53,8 +53,7 @@ struct ei_traits > int(MatrixType::MaxRowsAtCompileTime) - 1 : Dynamic, MaxColsAtCompileTime = (MatrixType::MaxColsAtCompileTime != Dynamic) ? int(MatrixType::MaxColsAtCompileTime) - 1 : Dynamic, - Flags = (_MatrixTypeNested::Flags & HereditaryBits) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + Flags = _MatrixTypeNested::Flags & HereditaryBits, CoeffReadCost = _MatrixTypeNested::CoeffReadCost // minor is used typically on tiny matrices, // where loops are unrolled and the 'if' evaluates at compile time }; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 94f01f55e..5c51ea27c 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -42,10 +42,7 @@ struct ei_traits > //: ei_traits::ColsAtCompileTime, MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = ei_traits::MaxColsAtCompileTime, - Flags = EvalBeforeNestingBit - | EvalBeforeAssigningBit - | NestParentByRefBit - | EIGEN_PROPAGATE_NESTING_BIT(Lhs::Flags|Rhs::Flags), + Flags = EvalBeforeNestingBit | EvalBeforeAssigningBit, CoeffReadCost = 0 // FIXME why is it needed ? }; }; diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 9f1893c4a..6d01ee495 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -47,9 +47,8 @@ struct ei_traits > : ei_traits::Flags), + Flags = _MatrixTypeNested::Flags & (HereditaryBits) + & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)), // FIXME these flags should be preserved CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index c403a4f55..7ae2e82a4 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -90,7 +90,7 @@ template class SelfCwiseBinaryOp OtherDerived& _other = other.const_cast_derived(); ei_internal_assert(index >= 0 && index < m_matrix.size()); Scalar& tmp = m_matrix.coeffRef(index); - tmp = m_functor(tmp, Scalar(_other.coeff(index))); + tmp = m_functor(tmp, _other.coeff(index)); } template diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 18e4a1739..bd06d8464 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -50,8 +50,7 @@ struct ei_traits > : ei_traits ColsAtCompileTime = MatrixType::RowsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - Flags = (int(_MatrixTypeNested::Flags & ~NestByRefBit) ^ RowMajorBit) - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + Flags = int(_MatrixTypeNested::Flags & ~NestByRefBit) ^ RowMajorBit, CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; @@ -64,7 +63,7 @@ template class Transpose public: typedef typename TransposeImpl::StorageType>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) + EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) inline Transpose(const MatrixType& matrix) : m_matrix(matrix) {} diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index e6690b6fa..8bea0aa68 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -130,8 +130,7 @@ struct ei_traits > : ei_traits typedef MatrixType ExpressionType; enum { Mode = _Mode, - Flags = (_MatrixTypeNested::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + Flags = (_MatrixTypeNested::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; diff --git a/Eigen/src/Core/products/GeneralUnrolled.h b/Eigen/src/Core/products/GeneralUnrolled.h index a8fec1fac..32aa3afe6 100644 --- a/Eigen/src/Core/products/GeneralUnrolled.h +++ b/Eigen/src/Core/products/GeneralUnrolled.h @@ -81,10 +81,8 @@ struct ei_traits > Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) | EvalBeforeAssigningBit | EvalBeforeNestingBit - | NestParentByRefBit | (CanVectorizeLhs || CanVectorizeRhs ? PacketAccessBit : 0) - | (LhsFlags & RhsFlags & AlignedBit) - | EIGEN_PROPAGATE_NESTING_BIT(LhsFlags|RhsFlags), + | (LhsFlags & RhsFlags & AlignedBit), CoeffReadCost = InnerSize == Dynamic ? Dynamic : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 1b34b401d..a4e8b3f78 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -97,7 +97,6 @@ const unsigned int EvalBeforeAssigningBit = 0x4; */ const unsigned int PacketAccessBit = 0x8; -const unsigned int NestParentByRefBit = 0x80; const unsigned int NestByRefBit = 0x100; #ifdef EIGEN_VECTORIZE diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 77b3968b1..a86e7be89 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -201,28 +201,6 @@ template struct ei_plain_matrix_type_row_major // we should be able to get rid of this one too template struct ei_must_nest_by_value { enum { ret = false }; }; -template -struct ei_is_reference -{ -#ifndef NDEBUG - static void check() { std::cout << typeid(T).name() << std::endl; } -#else - static void check() {} -#endif - enum { ret = false }; -}; - -template -struct ei_is_reference -{ -#ifndef NDEBUG - static void check() { std::cout << typeid(T).name() << "&" << std::endl; } -#else - static void check() {} -#endif - enum { ret = true }; -}; - /** * The reference selector for template expressions. The idea is that we don't * need to use references for expressions since they are light weight proxy @@ -238,8 +216,6 @@ struct ei_ref_selector >::ret type; }; -#define EIGEN_PROPAGATE_NESTING_BIT(ReferenceFlags) ((ReferenceFlags) & NestParentByRefBit)<<1 - /** \internal Determines how a given expression should be nested into another one. * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be * nested into the bigger product expression. The choice is between nesting the expression b+c as-is, or diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 8c95a4d4d..76ca66c57 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -55,8 +55,7 @@ struct ei_traits > ColsAtCompileTime = Direction==Horizontal ? ColsPlusOne : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, - Flags = _MatrixTypeNested::Flags & HereditaryBits - | EIGEN_PROPAGATE_NESTING_BIT(ei_traits::Flags), + Flags = _MatrixTypeNested::Flags & HereditaryBits, CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; From c076fec7340c35120f807d7a5fd7111064a30737 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 09:58:34 +0100 Subject: [PATCH 065/109] fix the multiple temporary issue for nested products --- Eigen/src/Core/DenseStorageBase.h | 2 +- Eigen/src/Core/ProductBase.h | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index f3d6e8944..313ac037c 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -490,7 +490,7 @@ class DenseStorageBase : public _Base return ei_assign_selector::run(this->derived(), other.derived()); } - static EIGEN_STRONG_INLINE void _check_template_params() + EIGEN_STRONG_INLINE void _check_template_params() { #ifdef EIGEN_DEBUG_MATRIX_CTOR EIGEN_DEBUG_MATRIX_CTOR; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 5c51ea27c..fa3207f65 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -42,7 +42,8 @@ struct ei_traits > //: ei_traits::ColsAtCompileTime, MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = ei_traits::MaxColsAtCompileTime, - Flags = EvalBeforeNestingBit | EvalBeforeAssigningBit, + Flags = EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, // Note that EvalBeforeNestingBit and NestByRefBit + // are not used in practice because ei_nested is overloaded for products CoeffReadCost = 0 // FIXME why is it needed ? }; }; @@ -137,11 +138,21 @@ class ProductBase : public MatrixBase Diagonal diagonal(int index) { return Diagonal(LazyCoeffBaseProductType(CoeffBaseProductType(m_lhs, m_rhs))).diagonal(index); } + // Implicit convertion to the nested type (trigger the evaluation of the product) + operator const PlainMatrixType& () const + { + m_result.resize(m_lhs.rows(), m_rhs.cols()); + this->evalTo(m_result); + return m_result; + } + protected: const LhsNested m_lhs; const RhsNested m_rhs; + mutable PlainMatrixType m_result; + private: // discard coeff methods @@ -151,6 +162,14 @@ class ProductBase : public MatrixBase void coeffRef(int); }; +// here we need to overload the nested rule for products +// such that the nested type is a const reference to a plain matrix +template +struct ei_nested, N, PlainMatrixType> +{ + typedef PlainMatrixType const& type; +}; + template class ScaledProduct; From 0398e21198caaf7206851a9081033cddb0797d47 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 10:02:26 +0100 Subject: [PATCH 066/109] s/UnrolledProduct/CoeffBasedProduct --- Eigen/src/Core/NoAlias.h | 4 ++-- Eigen/src/Core/Product.h | 16 ++++++++-------- Eigen/src/Core/ProductBase.h | 2 +- .../{GeneralUnrolled.h => GeneralCoeffBased.h} | 6 +++--- Eigen/src/Core/util/Constants.h | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) rename Eigen/src/Core/products/{GeneralUnrolled.h => GeneralCoeffBased.h} (98%) diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index e09fd0091..7e2e501b3 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -71,11 +71,11 @@ class NoAlias { other.derived().subTo(m_expression); return m_expression; } template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const GeneralProduct& other) + EIGEN_STRONG_INLINE ExpressionType& operator+=(const GeneralProduct& other) { return m_expression.derived() += other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const GeneralProduct& other) + EIGEN_STRONG_INLINE ExpressionType& operator-=(const GeneralProduct& other) { return m_expression.derived() -= other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } #endif diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index d7f17dd28..5e531c467 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -87,12 +87,12 @@ public: template struct ei_product_type_selector { enum { ret = OuterProduct }; }; template struct ei_product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; template<> struct ei_product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; -template<> struct ei_product_type_selector { enum { ret = UnrolledProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = GemvProduct }; }; @@ -134,11 +134,11 @@ struct ProductReturnType }; template -struct ProductReturnType +struct ProductReturnType { typedef typename ei_nested::type >::type LhsNested; typedef typename ei_nested::type >::type RhsNested; - typedef GeneralProduct Type; + typedef GeneralProduct Type; }; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index fa3207f65..6eb02f386 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -83,7 +83,7 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; - typedef typename ProductReturnType::Type CoeffBaseProductType; + typedef typename ProductReturnType::Type CoeffBaseProductType; typedef Flagged LazyCoeffBaseProductType; public: diff --git a/Eigen/src/Core/products/GeneralUnrolled.h b/Eigen/src/Core/products/GeneralCoeffBased.h similarity index 98% rename from Eigen/src/Core/products/GeneralUnrolled.h rename to Eigen/src/Core/products/GeneralCoeffBased.h index 32aa3afe6..0cca2d417 100644 --- a/Eigen/src/Core/products/GeneralUnrolled.h +++ b/Eigen/src/Core/products/GeneralCoeffBased.h @@ -43,7 +43,7 @@ template -struct ei_traits > +struct ei_traits > { typedef DenseStorageMatrix DenseStorageType; typedef typename ei_cleantype::type _LhsNested; @@ -98,9 +98,9 @@ struct ei_traits > }; }; -template class GeneralProduct +template class GeneralProduct : ei_no_assignment_operator, - public MatrixBase > + public MatrixBase > { public: diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index a4e8b3f78..dc7b3eea9 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -269,6 +269,6 @@ namespace Architecture enum DenseStorageMatrix {}; enum DenseStorageArray {}; -enum { OuterProduct, InnerProduct, UnrolledProduct, GemvProduct, GemmProduct }; +enum { OuterProduct, InnerProduct, CoeffBasedProduct, GemvProduct, GemmProduct }; #endif // EIGEN_CONSTANTS_H From 5686eca7b1017738a19a32ce0627249e56cfd3eb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 11:05:39 +0100 Subject: [PATCH 067/109] * fix multiple temporary copies for coeff based products * introduce a lazy product version of the coefficient based implementation => flagged is not used anymore => small outer product are now lazy by default (aliasing is really unlikely for outer products) --- Eigen/Core | 2 +- Eigen/src/Core/NoAlias.h | 12 ++-- Eigen/src/Core/Product.h | 24 +++++--- Eigen/src/Core/ProductBase.h | 18 +++--- ...eneralCoeffBased.h => CoeffBasedProduct.h} | 60 ++++++++++++------- Eigen/src/Core/util/Constants.h | 2 +- Eigen/src/Core/util/ForwardDeclarations.h | 5 +- Eigen/src/Core/util/StaticAssert.h | 1 + 8 files changed, 75 insertions(+), 49 deletions(-) rename Eigen/src/Core/products/{GeneralCoeffBased.h => CoeffBasedProduct.h} (88%) diff --git a/Eigen/Core b/Eigen/Core index b6e383210..b9241a730 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -205,7 +205,7 @@ struct Dense {}; #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/SolveTriangular.h" -#include "src/Core/products/GeneralUnrolled.h" +#include "src/Core/products/CoeffBasedProduct.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 7e2e501b3..9d6cab7f9 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -70,13 +70,13 @@ class NoAlias EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) { other.derived().subTo(m_expression); return m_expression; } - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const GeneralProduct& other) - { return m_expression.derived() += other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } + template + EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) + { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const GeneralProduct& other) - { return m_expression.derived() -= other.template flagged<0,EvalBeforeAssigningBit|EvalBeforeNestingBit>(); } + template + EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) + { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } #endif protected: diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 5e531c467..e643b2ea7 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -87,12 +87,12 @@ public: template struct ei_product_type_selector { enum { ret = OuterProduct }; }; template struct ei_product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; template<> struct ei_product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; -template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; -template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProduct }; }; -template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; -template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; -template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; -template<> struct ei_product_type_selector { enum { ret = CoeffBasedProduct }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct ei_product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct ei_product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct ei_product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct ei_product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = GemvProduct }; }; @@ -134,11 +134,19 @@ struct ProductReturnType }; template -struct ProductReturnType +struct ProductReturnType { typedef typename ei_nested::type >::type LhsNested; typedef typename ei_nested::type >::type RhsNested; - typedef GeneralProduct Type; + typedef CoeffBasedProduct Type; +}; + +template +struct ProductReturnType +{ + typedef typename ei_nested::type >::type LhsNested; + typedef typename ei_nested::type >::type RhsNested; + typedef CoeffBasedProduct Type; }; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 6eb02f386..9fdb74f1c 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -83,8 +83,7 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; - typedef typename ProductReturnType::Type CoeffBaseProductType; - typedef Flagged LazyCoeffBaseProductType; + typedef typename ProductReturnType::Type LazyCoeffBaseProductType; public: typedef typename Base::PlainMatrixType PlainMatrixType; @@ -112,31 +111,28 @@ class ProductBase : public MatrixBase template inline void scaleAndAddTo(Dest& dst,Scalar alpha) const { derived().scaleAndAddTo(dst,alpha); } - EIGEN_DEPRECATED const Flagged lazy() const - { return *this; } - const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } const Diagonal diagonal() const - { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs); } Diagonal diagonal() - { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs); } template const Diagonal diagonal() const - { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs); } template Diagonal diagonal() - { return Diagonal(CoeffBaseProductType(m_lhs, m_rhs)); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs); } const Diagonal diagonal(int index) const - { return Diagonal(LazyCoeffBaseProductType(CoeffBaseProductType(m_lhs, m_rhs))).diagonal(index); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } Diagonal diagonal(int index) - { return Diagonal(LazyCoeffBaseProductType(CoeffBaseProductType(m_lhs, m_rhs))).diagonal(index); } + { return LazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } // Implicit convertion to the nested type (trigger the evaluation of the product) operator const PlainMatrixType& () const diff --git a/Eigen/src/Core/products/GeneralCoeffBased.h b/Eigen/src/Core/products/CoeffBasedProduct.h similarity index 88% rename from Eigen/src/Core/products/GeneralCoeffBased.h rename to Eigen/src/Core/products/CoeffBasedProduct.h index 0cca2d417..d947bfc58 100644 --- a/Eigen/src/Core/products/GeneralCoeffBased.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -23,11 +23,14 @@ // License and a copy of the GNU General Public License along with // Eigen. If not, see . -#ifndef EIGEN_GENERAL_UNROLLED_PRODUCT_H -#define EIGEN_GENERAL_UNROLLED_PRODUCT_H +#ifndef EIGEN_COEFFBASED_PRODUCT_H +#define EIGEN_COEFFBASED_PRODUCT_H /********************************************************************************* -* Specialization of GeneralProduct<> for products with small fixed sizes +* Coefficient based product implementation. +* It is designed for the following use cases: +* - small fixed sizes +* - lazy products *********************************************************************************/ /* Since the all the dimensions of the product are small, here we can rely @@ -42,8 +45,8 @@ struct ei_product_coeff_impl; template struct ei_product_packet_impl; -template -struct ei_traits > +template +struct ei_traits > { typedef DenseStorageMatrix DenseStorageType; typedef typename ei_cleantype::type _LhsNested; @@ -79,14 +82,13 @@ struct ei_traits > RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit - | EvalBeforeNestingBit + | NestingFlags | (CanVectorizeLhs || CanVectorizeRhs ? PacketAccessBit : 0) | (LhsFlags & RhsFlags & AlignedBit), - CoeffReadCost = InnerSize == Dynamic ? Dynamic - : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) - + (InnerSize - 1) * NumTraits::AddCost, + CoeffReadCost = 1000,//InnerSize == Dynamic ? Dynamic +// : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) +// + (InnerSize - 1) * NumTraits::AddCost, /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner @@ -98,25 +100,27 @@ struct ei_traits > }; }; -template class GeneralProduct +template +class CoeffBasedProduct : ei_no_assignment_operator, - public MatrixBase > + public MatrixBase > { public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(GeneralProduct) + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct) + typedef typename Base::PlainMatrixType PlainMatrixType; private: - typedef typename ei_traits::_LhsNested _LhsNested; - typedef typename ei_traits::_RhsNested _RhsNested; + typedef typename ei_traits::_LhsNested _LhsNested; + typedef typename ei_traits::_RhsNested _RhsNested; enum { PacketSize = ei_packet_traits::size, - InnerSize = ei_traits::InnerSize, + InnerSize = ei_traits::InnerSize, Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = ei_traits::CanVectorizeInner + CanVectorizeInner = ei_traits::CanVectorizeInner }; typedef ei_product_coeff_impl class GeneralProduct - inline GeneralProduct(const Lhs& lhs, const Rhs& rhs) + inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { // we don't allow taking products of matrices of different real types, as that wouldn't be vectorizable. @@ -171,11 +175,27 @@ template class GeneralProduct +struct ei_nested, N, PlainMatrixType> +{ + typedef PlainMatrixType const& type; +}; /*************************************************************************** * Normal product .coeff() implementation (with meta-unrolling) @@ -386,4 +406,4 @@ struct ei_product_packet_impl class CwiseNullaryOp; template class CwiseUnaryOp; template class CwiseUnaryView; template class CwiseBinaryOp; -template class SelfCwiseBinaryOp; +template class SelfCwiseBinaryOp; template class ProductBase; -template class GeneralProduct; +template class GeneralProduct; +template class CoeffBasedProduct; template class DiagonalBase; template class DiagonalWrapper; diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 56a57b706..619e7664d 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -61,6 +61,7 @@ THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE, THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE, YOU_MADE_A_PROGRAMMING_MISTAKE, + EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE, YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR, YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR, UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC, From d104d2cd29149876c4ec1d2a69960c3ef09872be Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 11:13:22 +0100 Subject: [PATCH 068/109] add accessors to coeff based product --- Eigen/src/Core/products/CoeffBasedProduct.h | 3 +++ test/product_notemporary.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index d947bfc58..a772b9ec8 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -182,6 +182,9 @@ class CoeffBasedProduct return m_result; } + const _LhsNested& lhs() const { return m_lhs; } + const _RhsNested& rhs() const { return m_rhs; } + protected: const LhsNested m_lhs; const RhsNested m_rhs; diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index b8bc3acc3..cddf7eb39 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -25,7 +25,7 @@ static int nb_temporaries; #define EIGEN_DEBUG_MATRIX_CTOR { \ - if(SizeAtCompileTime==Dynamic) \ + if(SizeAtCompileTime==Dynamic && this->data()!=0) \ nb_temporaries++; \ } From 1cb59e478137a1399214a1a5caddf1871556a53a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 11:27:30 +0100 Subject: [PATCH 069/109] fix nesting lazy prod by ref --- Eigen/src/Core/NoAlias.h | 4 ++-- Eigen/src/Core/Product.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 9d6cab7f9..30ddbeb3c 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -72,11 +72,11 @@ class NoAlias template EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } + { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } template EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } + { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } #endif protected: diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index e643b2ea7..07aeae165 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -146,7 +146,7 @@ struct ProductReturnType { typedef typename ei_nested::type >::type LhsNested; typedef typename ei_nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; + typedef CoeffBasedProduct Type; }; From 8185a3c6cf21ea5f60fdd73fb0da63cb7f0d2427 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 13:16:29 +0100 Subject: [PATCH 070/109] fix one useless temp & copy --- Eigen/src/Core/Assign.h | 4 ++-- Eigen/src/Core/products/CoeffBasedProduct.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 0a6c46eca..9440cebf1 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -389,7 +389,7 @@ template <> struct ei_unaligned_assign_impl { // MSVC must not inline this functions. If it does, it fails to optimize the - // packet access path. + // packet access path. #ifdef _MSC_VER template static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, int start, int end) @@ -415,7 +415,7 @@ struct ei_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); - + for(int index = alignedStart; index < alignedEnd; index += packetSize) { dst.template copyPacket::SrcAlignment>(index, src); diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index a772b9ec8..c9d333072 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -86,9 +86,9 @@ struct ei_traits > | (CanVectorizeLhs || CanVectorizeRhs ? PacketAccessBit : 0) | (LhsFlags & RhsFlags & AlignedBit), - CoeffReadCost = 1000,//InnerSize == Dynamic ? Dynamic -// : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) -// + (InnerSize - 1) * NumTraits::AddCost, + CoeffReadCost = InnerSize == Dynamic ? Dynamic + : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + + (InnerSize - 1) * NumTraits::AddCost, /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner @@ -178,7 +178,7 @@ class CoeffBasedProduct // Implicit convertion to the nested type (trigger the evaluation of the product) operator const PlainMatrixType& () const { - m_result = *this; + m_result.lazyAssign(*this); return m_result; } From 928ae382b4e8486a3c0145b289731e4db5fd8db0 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 9 Feb 2010 14:07:37 +0100 Subject: [PATCH 071/109] Added debug only unit test for nesting ops - just run ./check nesting. --- test/CMakeLists.txt | 1 + test/nesting_ops.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 test/nesting_ops.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 77e7a5fd2..b0da2a1d8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -168,6 +168,7 @@ ei_add_test(conservative_resize) ei_add_test(permutationmatrices) ei_add_test(eigen2support) ei_add_test(nullary) +ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}") ei_add_test(prec_inverse_4x4) diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp new file mode 100644 index 000000000..4f6856108 --- /dev/null +++ b/test/nesting_ops.cpp @@ -0,0 +1,53 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#include "main.h" + +template void run_nesting_ops(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + +#ifdef NDEBUG + const bool is_debug = false; +#else + const bool is_debug = true; +#endif + + // Make really sure that we are in debug mode! We don't want any type of + // inlining for these tests to pass. + VERIFY(is_debug); + + // The only intention of these tests is to ensure that this code does + // not trigger any asserts or segmentation faults... more to come. + VERIFY( (m.transpose() * m).diagonal().sum() == (m.transpose() * m).diagonal().sum() ); + VERIFY( (m.transpose() * m).diagonal().array().abs().sum() == (m.transpose() * m).diagonal().array().abs().sum() ); +} + +void test_nesting_ops() +{ + CALL_SUBTEST_1(run_nesting_ops(MatrixXf::Random(25,25))); + CALL_SUBTEST_2(run_nesting_ops(MatrixXd::Random(25,25))); + CALL_SUBTEST_3(run_nesting_ops(Matrix4f::Random())); + CALL_SUBTEST_4(run_nesting_ops(Matrix4d::Random())); +} From dd283b3f82acc3ef0e4e4336b3d7d44588840b2f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 9 Feb 2010 14:12:41 +0100 Subject: [PATCH 072/109] Fixed paste© error. --- test/nesting_ops.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 4f6856108..2ad8f209f 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2010 Hauke Heibel // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public From 0a680a9857033dd0c3c86ca06e1357881124959f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 9 Feb 2010 14:24:17 +0100 Subject: [PATCH 073/109] Added a non-diagonal product nesting test. --- test/nesting_ops.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 2ad8f209f..565bc3644 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -42,6 +42,8 @@ template void run_nesting_ops(const MatrixType& m) // not trigger any asserts or segmentation faults... more to come. VERIFY( (m.transpose() * m).diagonal().sum() == (m.transpose() * m).diagonal().sum() ); VERIFY( (m.transpose() * m).diagonal().array().abs().sum() == (m.transpose() * m).diagonal().array().abs().sum() ); + + VERIFY( (m.transpose() * m).array().abs().sum() == (m.transpose() * m).array().abs().sum() ); } void test_nesting_ops() From 9ce1212d7cf1574d989a5e6269f0a614b4ce17ed Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 14:28:22 +0100 Subject: [PATCH 074/109] For the record, here is a solution for (a*b).diagonal, at the cost of extra copies if a and/or b as to be evaluated. So in the next commit I'll remove it. A nice solution would be to evaluate the lhs/rhs into member of the initial product, but that would be overkill. --- Eigen/src/Core/ProductBase.h | 30 ++++++++++++--------- Eigen/src/Core/products/CoeffBasedProduct.h | 4 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 9fdb74f1c..4c95684f0 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -83,7 +83,11 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; - typedef typename ProductReturnType::Type LazyCoeffBaseProductType; + // here we don't use ProductReturnType::Type because we must nest it by value. + typedef typename ei_nested<_LhsNested, _RhsNested::ColsAtCompileTime, typename ei_plain_matrix_type<_LhsNested>::type >::type LazyLhsNested; + typedef typename ei_nested<_RhsNested, _LhsNested::RowsAtCompileTime, typename ei_plain_matrix_type<_RhsNested>::type >::type LazyRhsNested; + typedef CoeffBasedProduct NestedByValueLazyCoeffBaseProductType; + public: typedef typename Base::PlainMatrixType PlainMatrixType; @@ -114,25 +118,25 @@ class ProductBase : public MatrixBase const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } - const Diagonal diagonal() const - { return LazyCoeffBaseProductType(m_lhs, m_rhs); } + const Diagonal diagonal() const + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - Diagonal diagonal() - { return LazyCoeffBaseProductType(m_lhs, m_rhs); } + Diagonal diagonal() + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } template - const Diagonal diagonal() const - { return LazyCoeffBaseProductType(m_lhs, m_rhs); } + const Diagonal diagonal() const + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } template - Diagonal diagonal() - { return LazyCoeffBaseProductType(m_lhs, m_rhs); } + Diagonal diagonal() + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - const Diagonal diagonal(int index) const - { return LazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } + const Diagonal diagonal(int index) const + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - Diagonal diagonal(int index) - { return LazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } + Diagonal diagonal(int index) + { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } // Implicit convertion to the nested type (trigger the evaluation of the product) operator const PlainMatrixType& () const diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index c9d333072..af0d2e2a2 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -129,6 +129,10 @@ class CoeffBasedProduct public: + inline CoeffBasedProduct(const CoeffBasedProduct& other) + : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) + {} + template inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) From 840977529fd0e674e46a7cb6c5a5519c403b05bc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 14:34:31 +0100 Subject: [PATCH 075/109] * as promised, remove the "optimization" for Product::diagonal() * add MatrixBase::lazyProduct --- Eigen/src/Core/MatrixBase.h | 4 ++++ Eigen/src/Core/Product.h | 25 +++++++++++++++++++++ Eigen/src/Core/ProductBase.h | 25 --------------------- Eigen/src/Core/products/CoeffBasedProduct.h | 4 ---- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index e599a9e03..65b3bfb7c 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -188,6 +188,10 @@ template class MatrixBase const typename ProductReturnType::Type operator*(const MatrixBase &other) const; + template + const typename ProductReturnType::Type + lazyProduct(const MatrixBase &other) const; + template Derived& operator*=(const AnyMatrixBase& other); diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 07aeae165..304dbc3ee 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -445,4 +445,29 @@ MatrixBase::operator*(const MatrixBase &other) const return typename ProductReturnType::Type(derived(), other.derived()); } + +template +template +const typename ProductReturnType::Type +MatrixBase::lazyProduct(const MatrixBase &other) const +{ + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) + + return typename ProductReturnType::Type(derived(), other.derived()); +} + #endif // EIGEN_PRODUCT_H diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 4c95684f0..bbd77f059 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -83,11 +83,6 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; - // here we don't use ProductReturnType::Type because we must nest it by value. - typedef typename ei_nested<_LhsNested, _RhsNested::ColsAtCompileTime, typename ei_plain_matrix_type<_LhsNested>::type >::type LazyLhsNested; - typedef typename ei_nested<_RhsNested, _LhsNested::RowsAtCompileTime, typename ei_plain_matrix_type<_RhsNested>::type >::type LazyRhsNested; - typedef CoeffBasedProduct NestedByValueLazyCoeffBaseProductType; - public: typedef typename Base::PlainMatrixType PlainMatrixType; @@ -118,26 +113,6 @@ class ProductBase : public MatrixBase const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } - const Diagonal diagonal() const - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - - Diagonal diagonal() - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - const Diagonal diagonal() const - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - Diagonal diagonal() - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs); } - - const Diagonal diagonal(int index) const - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - Diagonal diagonal(int index) - { return NestedByValueLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - // Implicit convertion to the nested type (trigger the evaluation of the product) operator const PlainMatrixType& () const { diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index af0d2e2a2..c9d333072 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -129,10 +129,6 @@ class CoeffBasedProduct public: - inline CoeffBasedProduct(const CoeffBasedProduct& other) - : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) - {} - template inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) From 285bc336d5eef7b522648f2fe8fb5a6df64a9645 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 14:45:17 +0100 Subject: [PATCH 076/109] document lazyProduct --- Eigen/src/Core/Product.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 304dbc3ee..5903476b5 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -420,7 +420,7 @@ template<> struct ei_gemv_selector * * \note If instead of the matrix product you want the coefficient-wise product, see Cwise::operator*(). * - * \sa lazy(), operator*=(const MatrixBase&), Cwise::operator*() + * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*() */ template template @@ -445,7 +445,22 @@ MatrixBase::operator*(const MatrixBase &other) const return typename ProductReturnType::Type(derived(), other.derived()); } - +/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. + * + * The coefficients of the product will be computed as requested that is particularly useful when you + * only want to compute a small fraction of the result's coefficients. + * Here is an example: + * \code + * MatrixXf a(10,10), b(10,10); + * (a*b).diagonal().sum(); // here a*b is entirely computed into a 10x10 temporary matrix + * a.lazyProduct(b).diagonal().sum(); // here a*b is evaluated in a lazy manner, + * // so only the diagonal coefficients will be computed + * \endcode + * + * \warning This version of the matrix product can be much much slower if all coefficients have to be computed anyways. + * + * \sa operator*(const MatrixBase&) + */ template template const typename ProductReturnType::Type From 905050b2392681ffb9b0f98b9fd6e738a562ae76 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 15:55:36 +0100 Subject: [PATCH 077/109] extend sparse product benchmark with ublas --- bench/BenchSparseUtil.h | 14 ++++ bench/sparse_product.cpp | 147 ++++++++++++++++++++++----------------- 2 files changed, 98 insertions(+), 63 deletions(-) diff --git a/bench/BenchSparseUtil.h b/bench/BenchSparseUtil.h index 39db69345..a5ab10711 100644 --- a/bench/BenchSparseUtil.h +++ b/bench/BenchSparseUtil.h @@ -123,4 +123,18 @@ void eiToCSparse(const EigenSparseMatrix& src, cs* &dst) #include #include +// using namespace boost; +// using namespace boost::numeric; +// using namespace boost::numeric::ublas; + +typedef boost::numeric::ublas::compressed_matrix UblasMatrix; + +void eiToUblas(const EigenSparseMatrix& src, UblasMatrix& dst) +{ + for (int j=0; j + #ifndef SIZE -#define SIZE 10000 +#define SIZE 1000000 #endif #ifndef NNZPERCOL -#define NNZPERCOL 32 +#define NNZPERCOL 6 #endif #ifndef REPEAT @@ -20,7 +23,7 @@ #include "BenchSparseUtil.h" #ifndef NBTRIES -#define NBTRIES 4 +#define NBTRIES 1 #endif #define BENCH(X) \ @@ -60,6 +63,7 @@ cs* cs_sorted_multiply(const cs* a, const cs* b) { // return cs_multiply(a,b); + cs* A = cs_transpose(a, 1); cs* B = cs_transpose(b, 1); cs* D = cs_multiply(B,A); /* D = B'*A' */ @@ -155,26 +159,26 @@ int main(int argc, char *argv[]) // BENCH(sm3 = sm1.transpose() * sm2; ) // std::cout << " a' * b:\t" << timer.value() << endl; -// +// // // BENCH(sm3 = sm1.transpose() * sm2.transpose(); ) // std::cout << " a' * b':\t" << timer.value() << endl; -// +// // // BENCH(sm3 = sm1 * sm2.transpose(); ) // std::cout << " a * b' :\t" << timer.value() << endl; -// std::cout << "\n\n"; - - BENCH( sm3.setprod(sm1, sm2); ) - std::cout << " a * b:\t" << timer.value() << endl; - -// BENCH(sm3.setprod(sm1.transpose(),sm2); ) +// std::cout << "\n"; +// +// BENCH( sm3._experimentalNewProduct(sm1, sm2); ) +// std::cout << " a * b:\t" << timer.value() << endl; +// +// BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2); ) // std::cout << " a' * b:\t" << timer.value() << endl; -// -// BENCH(sm3.setprod(sm1.transpose(),sm2.transpose()); ) +// // +// BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2.transpose()); ) // std::cout << " a' * b':\t" << timer.value() << endl; -// -// BENCH(sm3.setprod(sm1, sm2.transpose());) +// // +// BENCH(sm3._experimentalNewProduct(sm1, sm2.transpose());) // std::cout << " a * b' :\t" << timer.value() << endl; } @@ -247,6 +251,23 @@ int main(int argc, char *argv[]) } #endif + #ifndef NOUBLAS + { + std::cout << "ublas\t" << nnzPerCol << "%\n"; + UblasMatrix m1(rows,cols), m2(rows,cols), m3(rows,cols); + eiToUblas(sm1, m1); + eiToUblas(sm2, m2); + + BENCH(boost::numeric::ublas::prod(m1, m2, m3);); +// timer.reset(); +// timer.start(); +// for (int k=0; k Date: Tue, 9 Feb 2010 16:37:24 +0100 Subject: [PATCH 078/109] Now variadic macro related warnings should be supressed as well under Linux. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 210c90725..07d5806e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ endif() if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fexceptions -fno-check-new -fno-common -fstrict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wno-variadic-macros -fexceptions -fno-check-new -fno-common -fstrict-aliasing") set(CMAKE_CXX_FLAGS_DEBUG "-g3") set(CMAKE_CXX_FLAGS_RELEASE "-g0 -O2") check_cxx_compiler_flag("-Wextra" COMPILER_SUPPORT_WEXTRA) From 71e580c4aa1f321aa453add4a279ee8d31914590 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Feb 2010 16:38:36 +0100 Subject: [PATCH 079/109] fix nesting in Arraywrapper and nesting_ops --- Eigen/src/Array/ArrayWrapper.h | 12 ++++++++---- test/inverse.cpp | 1 + test/nesting_ops.cpp | 5 +++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Array/ArrayWrapper.h b/Eigen/src/Array/ArrayWrapper.h index 9b7c83951..75bc33770 100644 --- a/Eigen/src/Array/ArrayWrapper.h +++ b/Eigen/src/Array/ArrayWrapper.h @@ -36,7 +36,7 @@ */ template struct ei_traits > - : public ei_traits + : public ei_traits::type > { typedef DenseStorageArray DenseStorageType; }; @@ -49,6 +49,8 @@ class ArrayWrapper : public ArrayBase > EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename ei_nested::type NestedExpressionType; + inline ArrayWrapper(const ExpressionType& matrix) : m_expression(matrix) {} inline int rows() const { return m_expression.rows(); } @@ -103,7 +105,7 @@ class ArrayWrapper : public ArrayBase > inline void evalTo(Dest& dst) const { dst = m_expression; } protected: - const ExpressionType& m_expression; + const NestedExpressionType m_expression; }; /** \class MatrixWrapper @@ -118,7 +120,7 @@ class ArrayWrapper : public ArrayBase > template struct ei_traits > - : public ei_traits + : public ei_traits::type > { typedef DenseStorageMatrix DenseStorageType; }; @@ -131,6 +133,8 @@ class MatrixWrapper : public MatrixBase > EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper); + typedef typename ei_nested::type NestedExpressionType; + inline MatrixWrapper(const ExpressionType& matrix) : m_expression(matrix) {} inline int rows() const { return m_expression.rows(); } @@ -182,7 +186,7 @@ class MatrixWrapper : public MatrixBase > } protected: - const ExpressionType& m_expression; + const NestedExpressionType& m_expression; }; #endif // EIGEN_ARRAYWRAPPER_H diff --git a/test/inverse.cpp b/test/inverse.cpp index b80e139e0..713caf4a6 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -96,5 +96,6 @@ void test_inverse() CALL_SUBTEST_5( inverse(MatrixXf(s,s)) ); s = ei_random(25,100); CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) ); + CALL_SUBTEST_7( inverse(Matrix4d()) ); } } diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 565bc3644..831c71da7 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -24,8 +24,9 @@ #include "main.h" -template void run_nesting_ops(const MatrixType& m) +template void run_nesting_ops(const MatrixType& _m) { + typename MatrixType::Nested m(_m); typedef typename MatrixType::Scalar Scalar; #ifdef NDEBUG @@ -38,7 +39,7 @@ template void run_nesting_ops(const MatrixType& m) // inlining for these tests to pass. VERIFY(is_debug); - // The only intention of these tests is to ensure that this code does + // The only intention of these tests is to ensure that this code does // not trigger any asserts or segmentation faults... more to come. VERIFY( (m.transpose() * m).diagonal().sum() == (m.transpose() * m).diagonal().sum() ); VERIFY( (m.transpose() * m).diagonal().array().abs().sum() == (m.transpose() * m).diagonal().array().abs().sum() ); From 5da3049b80dc8bb2de796d151e3d83844fe21a5e Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 9 Feb 2010 20:32:48 +0100 Subject: [PATCH 080/109] Regression tests for number of nested temporaries. Moved EIGEN_DEBUG_MATRIX_CTOR to ei_matrix_storage to capture resize related allocations. --- Eigen/src/Core/DenseStorageBase.h | 4 ---- Eigen/src/Core/MatrixStorage.h | 18 +++++++++++++++--- test/product_notemporary.cpp | 23 ++++++++++++++++------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index 313ac037c..7006e3a95 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -492,10 +492,6 @@ class DenseStorageBase : public _Base EIGEN_STRONG_INLINE void _check_template_params() { - #ifdef EIGEN_DEBUG_MATRIX_CTOR - EIGEN_DEBUG_MATRIX_CTOR; - #endif - EIGEN_STATIC_ASSERT(((RowsAtCompileTime >= MaxRowsAtCompileTime) && (ColsAtCompileTime >= MaxColsAtCompileTime) && (MaxRowsAtCompileTime >= 0) diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index 584ba8ca3..046670452 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -26,6 +26,12 @@ #ifndef EIGEN_MATRIXSTORAGE_H #define EIGEN_MATRIXSTORAGE_H +#ifdef EIGEN_DEBUG_MATRIX_CTOR + #define EIGEN_INT_DEBUG_MATRIX_CTOR EIGEN_DEBUG_MATRIX_CTOR; +#else + #define EIGEN_INT_DEBUG_MATRIX_CTOR +#endif + struct ei_constructor_without_unaligned_array_assert {}; /** \internal @@ -183,7 +189,8 @@ template class ei_matrix_storage(size)), m_rows(rows), m_cols(cols) {} + : m_data(ei_conditional_aligned_new(size)), m_rows(rows), m_cols(cols) + { EIGEN_INT_DEBUG_MATRIX_CTOR } inline ~ei_matrix_storage() { ei_conditional_aligned_delete(m_data, m_rows*m_cols); } inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } @@ -198,6 +205,7 @@ template class ei_matrix_storage(size); else m_data = 0; + EIGEN_INT_DEBUG_MATRIX_CTOR } m_rows = rows; m_cols = cols; @@ -214,7 +222,8 @@ template class ei_matrix_storage(size)), m_cols(cols) {} + inline ei_matrix_storage(int size, int, int cols) : m_data(ei_conditional_aligned_new(size)), m_cols(cols) + { EIGEN_INT_DEBUG_MATRIX_CTOR } inline ~ei_matrix_storage() { ei_conditional_aligned_delete(m_data, _Rows*m_cols); } inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } inline static int rows(void) {return _Rows;} @@ -228,6 +237,7 @@ template class ei_matrix_storage(size); else m_data = 0; + EIGEN_INT_DEBUG_MATRIX_CTOR } m_cols = cols; } @@ -243,7 +253,8 @@ template class ei_matrix_storage(size)), m_rows(rows) {} + inline ei_matrix_storage(int size, int rows, int) : m_data(ei_conditional_aligned_new(size)), m_rows(rows) + { EIGEN_INT_DEBUG_MATRIX_CTOR } inline ~ei_matrix_storage() { ei_conditional_aligned_delete(m_data, _Cols*m_rows); } inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } inline int rows(void) const {return m_rows;} @@ -257,6 +268,7 @@ template class ei_matrix_storage(size); else m_data = 0; + EIGEN_INT_DEBUG_MATRIX_CTOR } m_rows = rows; } diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index cddf7eb39..c637039e7 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -24,10 +24,7 @@ static int nb_temporaries; -#define EIGEN_DEBUG_MATRIX_CTOR { \ - if(SizeAtCompileTime==Dynamic && this->data()!=0) \ - nb_temporaries++; \ - } +#define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; } #include "main.h" @@ -40,10 +37,11 @@ static int nb_temporaries; template void product_notemporary(const MatrixType& m) { - /* This test checks the number of tempories created + /* This test checks the number of temporaries created * during the evaluation of a complex expression */ typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; typedef Matrix RowVectorType; typedef Matrix ColVectorType; typedef Matrix RowMajorMatrixType; @@ -105,10 +103,21 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3.template selfadjointView().rankUpdate(m2.adjoint()), 0); + // Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero temporaries m3.resize(1,1); - VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template selfadjointView() * m2.block(r0,c0,r1,c1), 1); m3.resize(1,1); - VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView() * m2.block(r0,c0,r1,c1), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView() * m2.block(r0,c0,r1,c1), 1); + + // Zero temporaries for lazy products ... + VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 ); + + // ... and one temporary for even deeply (>=2) nested products + VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 1 ); + VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 1 ); + + // Zero temporaries for ... CoeffBasedProductMode + VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 ); } void test_product_notemporary() From c11df02f0d8fdc546a9de27038d8a9d175936a54 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 9 Feb 2010 20:52:15 +0100 Subject: [PATCH 081/109] Deactivated test which requires variadic macros. --- test/product_notemporary.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index c637039e7..bb213368e 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -117,7 +117,8 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 1 ); // Zero temporaries for ... CoeffBasedProductMode - VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 ); + // - does not work with GCC because of the <..>, we'ld need variadic macros ... + //VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 ); } void test_product_notemporary() From fe0827495ab34749b8896bbebc0ff9fcc661c13b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Feb 2010 10:52:28 +0100 Subject: [PATCH 082/109] * move dummy_precision and epsilon to NumTraits * make NumTraits inherits std::numeric_limits --- Eigen/src/Cholesky/LDLT.h | 2 +- Eigen/src/Core/DenseBase.h | 14 +++--- Eigen/src/Core/IO.h | 2 +- Eigen/src/Core/MathFunctions.h | 57 ++++++++-------------- Eigen/src/Core/MatrixBase.h | 16 +++--- Eigen/src/Core/NumTraits.h | 20 ++++++++ Eigen/src/Eigenvalues/ComplexEigenSolver.h | 2 +- Eigen/src/Eigenvalues/ComplexSchur.h | 2 +- Eigen/src/Geometry/AlignedBox.h | 2 +- Eigen/src/Geometry/AngleAxis.h | 4 +- Eigen/src/Geometry/EulerAngles.h | 2 +- Eigen/src/Geometry/Hyperplane.h | 2 +- Eigen/src/Geometry/ParametrizedLine.h | 2 +- Eigen/src/Geometry/Quaternion.h | 6 +-- Eigen/src/Geometry/Rotation2D.h | 2 +- Eigen/src/Geometry/Scaling.h | 2 +- Eigen/src/Geometry/Transform.h | 2 +- Eigen/src/Geometry/Translation.h | 2 +- Eigen/src/LU/FullPivLU.h | 2 +- Eigen/src/QR/ColPivHouseholderQR.h | 4 +- Eigen/src/QR/FullPivHouseholderQR.h | 4 +- Eigen/src/SVD/JacobiSVD.h | 2 +- Eigen/src/SVD/SVD.h | 2 +- Eigen/src/Sparse/AmbiVector.h | 2 +- Eigen/src/Sparse/CompressedStorage.h | 2 +- Eigen/src/Sparse/DynamicSparseMatrix.h | 2 +- Eigen/src/Sparse/SparseLDLT.h | 4 +- Eigen/src/Sparse/SparseLLT.h | 4 +- Eigen/src/Sparse/SparseLU.h | 4 +- Eigen/src/Sparse/SparseMatrix.h | 2 +- Eigen/src/Sparse/SparseMatrixBase.h | 26 +++++----- Eigen/src/Sparse/SparseVector.h | 2 +- test/prec_inverse_4x4.cpp | 6 +-- test/product.h | 2 +- 34 files changed, 108 insertions(+), 103 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 54bd2d58a..b794b0c43 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -206,7 +206,7 @@ LDLT& LDLT::compute(const MatrixType& a) // in "Analysis of the Cholesky Decomposition of a Semi-definite Matrix" by // Nicholas J. Higham. Also see "Accuracy and Stability of Numerical // Algorithms" page 217, also by Higham. - cutoff = ei_abs(epsilon() * RealScalar(size) * biggest_in_corner); + cutoff = ei_abs(NumTraits::epsilon() * RealScalar(size) * biggest_in_corner); m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; } diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 9ef9108e4..700c11929 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -381,17 +381,17 @@ template class DenseBase template bool isApprox(const DenseBase& other, - RealScalar prec = dummy_precision()) const; + RealScalar prec = NumTraits::dummy_precision()) const; bool isMuchSmallerThan(const RealScalar& other, - RealScalar prec = dummy_precision()) const; + RealScalar prec = NumTraits::dummy_precision()) const; template bool isMuchSmallerThan(const DenseBase& other, - RealScalar prec = dummy_precision()) const; + RealScalar prec = NumTraits::dummy_precision()) const; - bool isApproxToConstant(const Scalar& value, RealScalar prec = dummy_precision()) const; - bool isConstant(const Scalar& value, RealScalar prec = dummy_precision()) const; - bool isZero(RealScalar prec = dummy_precision()) const; - bool isOnes(RealScalar prec = dummy_precision()) const; + bool isApproxToConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; + bool isConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; + bool isZero(RealScalar prec = NumTraits::dummy_precision()) const; + bool isOnes(RealScalar prec = NumTraits::dummy_precision()) const; inline Derived& operator*=(const Scalar& other); inline Derived& operator/=(const Scalar& other); diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index 8f91e272e..3e8d2bc66 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -146,7 +146,7 @@ std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOForm if (NumTraits::HasFloatingPoint) { typedef typename NumTraits::Real RealScalar; - RealScalar explicit_precision_fp = std::ceil(-ei_log(epsilon())/ei_log(10.0)); + RealScalar explicit_precision_fp = std::ceil(-ei_log(NumTraits::epsilon())/ei_log(10.0)); explicit_precision = static_cast(explicit_precision_fp); } else diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 1ea0116b4..1a4561555 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -25,13 +25,6 @@ #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H -template inline typename NumTraits::Real epsilon() -{ - return std::numeric_limits::Real>::epsilon(); -} - -template inline typename NumTraits::Real dummy_precision(); - template inline T ei_random(T a, T b); template inline T ei_random(); template inline T ei_random_amplitude() @@ -55,7 +48,6 @@ template inline typename NumTraits::Real ei_hypot(T x, T y) *** int *** **************/ -template<> inline int dummy_precision() { return 0; } inline int ei_real(int x) { return x; } inline int& ei_real_ref(int& x) { return x; } inline int ei_imag(int) { return 0; } @@ -92,15 +84,15 @@ template<> inline int ei_random() { return ei_random(-ei_random_amplitude(), ei_random_amplitude()); } -inline bool ei_isMuchSmallerThan(int a, int, int = dummy_precision()) +inline bool ei_isMuchSmallerThan(int a, int, int = NumTraits::dummy_precision()) { return a == 0; } -inline bool ei_isApprox(int a, int b, int = dummy_precision()) +inline bool ei_isApprox(int a, int b, int = NumTraits::dummy_precision()) { return a == b; } -inline bool ei_isApproxOrLessThan(int a, int b, int = dummy_precision()) +inline bool ei_isApproxOrLessThan(int a, int b, int = NumTraits::dummy_precision()) { return a <= b; } @@ -109,7 +101,6 @@ inline bool ei_isApproxOrLessThan(int a, int b, int = dummy_precision()) *** float *** **************/ -template<> inline float dummy_precision() { return 1e-5f; } inline float ei_real(float x) { return x; } inline float& ei_real_ref(float& x) { return x; } inline float ei_imag(float) { return 0.f; } @@ -140,15 +131,15 @@ template<> inline float ei_random() { return ei_random(-ei_random_amplitude(), ei_random_amplitude()); } -inline bool ei_isMuchSmallerThan(float a, float b, float prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(float a, float b, float prec = NumTraits::dummy_precision()) { return ei_abs(a) <= ei_abs(b) * prec; } -inline bool ei_isApprox(float a, float b, float prec = dummy_precision()) +inline bool ei_isApprox(float a, float b, float prec = NumTraits::dummy_precision()) { return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; } -inline bool ei_isApproxOrLessThan(float a, float b, float prec = dummy_precision()) +inline bool ei_isApproxOrLessThan(float a, float b, float prec = NumTraits::dummy_precision()) { return a <= b || ei_isApprox(a, b, prec); } @@ -157,8 +148,6 @@ inline bool ei_isApproxOrLessThan(float a, float b, float prec = dummy_precision *** double *** **************/ -template<> inline double dummy_precision() { return 1e-12; } - inline double ei_real(double x) { return x; } inline double& ei_real_ref(double& x) { return x; } inline double ei_imag(double) { return 0.; } @@ -189,15 +178,15 @@ template<> inline double ei_random() { return ei_random(-ei_random_amplitude(), ei_random_amplitude()); } -inline bool ei_isMuchSmallerThan(double a, double b, double prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(double a, double b, double prec = NumTraits::dummy_precision()) { return ei_abs(a) <= ei_abs(b) * prec; } -inline bool ei_isApprox(double a, double b, double prec = dummy_precision()) +inline bool ei_isApprox(double a, double b, double prec = NumTraits::dummy_precision()) { return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; } -inline bool ei_isApproxOrLessThan(double a, double b, double prec = dummy_precision()) +inline bool ei_isApproxOrLessThan(double a, double b, double prec = NumTraits::dummy_precision()) { return a <= b || ei_isApprox(a, b, prec); } @@ -206,7 +195,6 @@ inline bool ei_isApproxOrLessThan(double a, double b, double prec = dummy_precis *** complex *** *********************/ -template<> inline float dummy_precision >() { return dummy_precision(); } inline float ei_real(const std::complex& x) { return std::real(x); } inline float ei_imag(const std::complex& x) { return std::imag(x); } inline float& ei_real_ref(std::complex& x) { return reinterpret_cast(&x)[0]; } @@ -225,15 +213,15 @@ template<> inline std::complex ei_random() { return std::complex(ei_random(), ei_random()); } -inline bool ei_isMuchSmallerThan(const std::complex& a, const std::complex& b, float prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(const std::complex& a, const std::complex& b, float prec = NumTraits::dummy_precision()) { return ei_abs2(a) <= ei_abs2(b) * prec * prec; } -inline bool ei_isMuchSmallerThan(const std::complex& a, float b, float prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(const std::complex& a, float b, float prec = NumTraits::dummy_precision()) { return ei_abs2(a) <= ei_abs2(b) * prec * prec; } -inline bool ei_isApprox(const std::complex& a, const std::complex& b, float prec = dummy_precision()) +inline bool ei_isApprox(const std::complex& a, const std::complex& b, float prec = NumTraits::dummy_precision()) { return ei_isApprox(ei_real(a), ei_real(b), prec) && ei_isApprox(ei_imag(a), ei_imag(b), prec); @@ -244,7 +232,6 @@ inline bool ei_isApprox(const std::complex& a, const std::complex& *** complex *** **********************/ -template<> inline double dummy_precision >() { return dummy_precision(); } inline double ei_real(const std::complex& x) { return std::real(x); } inline double ei_imag(const std::complex& x) { return std::imag(x); } inline double& ei_real_ref(std::complex& x) { return reinterpret_cast(&x)[0]; } @@ -263,15 +250,15 @@ template<> inline std::complex ei_random() { return std::complex(ei_random(), ei_random()); } -inline bool ei_isMuchSmallerThan(const std::complex& a, const std::complex& b, double prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(const std::complex& a, const std::complex& b, double prec = NumTraits::dummy_precision()) { return ei_abs2(a) <= ei_abs2(b) * prec * prec; } -inline bool ei_isMuchSmallerThan(const std::complex& a, double b, double prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(const std::complex& a, double b, double prec = NumTraits::dummy_precision()) { return ei_abs2(a) <= ei_abs2(b) * prec * prec; } -inline bool ei_isApprox(const std::complex& a, const std::complex& b, double prec = dummy_precision()) +inline bool ei_isApprox(const std::complex& a, const std::complex& b, double prec = NumTraits::dummy_precision()) { return ei_isApprox(ei_real(a), ei_real(b), prec) && ei_isApprox(ei_imag(a), ei_imag(b), prec); @@ -283,7 +270,6 @@ inline bool ei_isApprox(const std::complex& a, const std::complex inline long double dummy_precision() { return dummy_precision(); } 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_imag(long double) { return 0.; } @@ -306,15 +292,15 @@ template<> inline long double ei_random() { return ei_random(-ei_random_amplitude(), ei_random_amplitude()); } -inline bool ei_isMuchSmallerThan(long double a, long double b, long double prec = dummy_precision()) +inline bool ei_isMuchSmallerThan(long double a, long double b, long double prec = NumTraits::dummy_precision()) { return ei_abs(a) <= ei_abs(b) * prec; } -inline bool ei_isApprox(long double a, long double b, long double prec = dummy_precision()) +inline bool ei_isApprox(long double a, long double b, long double prec = NumTraits::dummy_precision()) { return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; } -inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec = dummy_precision()) +inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec = NumTraits::dummy_precision()) { return a <= b || ei_isApprox(a, b, prec); } @@ -323,7 +309,6 @@ inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec *** bool *** **************/ -template<> inline bool dummy_precision() { return 0; } inline bool ei_real(bool x) { return x; } inline bool& ei_real_ref(bool& x) { return x; } inline bool ei_imag(bool) { return 0; } @@ -336,15 +321,15 @@ template<> inline bool ei_random() { return (ei_random(0,1) == 1); } -inline bool ei_isMuchSmallerThan(bool a, bool, bool = dummy_precision()) +inline bool ei_isMuchSmallerThan(bool a, bool, bool = NumTraits::dummy_precision()) { return !a; } -inline bool ei_isApprox(bool a, bool b, bool = dummy_precision()) +inline bool ei_isApprox(bool a, bool b, bool = NumTraits::dummy_precision()) { return a == b; } -inline bool ei_isApproxOrLessThan(bool a, bool b, bool = dummy_precision()) +inline bool ei_isApproxOrLessThan(bool a, bool b, bool = NumTraits::dummy_precision()) { return int(a) <= int(b); } diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 65b3bfb7c..229195046 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -253,16 +253,16 @@ template class MatrixBase Derived& setIdentity(); Derived& setIdentity(int rows, int cols); - bool isIdentity(RealScalar prec = dummy_precision()) const; - bool isDiagonal(RealScalar prec = dummy_precision()) const; + bool isIdentity(RealScalar prec = NumTraits::dummy_precision()) const; + bool isDiagonal(RealScalar prec = NumTraits::dummy_precision()) const; - bool isUpperTriangular(RealScalar prec = dummy_precision()) const; - bool isLowerTriangular(RealScalar prec = dummy_precision()) const; + bool isUpperTriangular(RealScalar prec = NumTraits::dummy_precision()) const; + bool isLowerTriangular(RealScalar prec = NumTraits::dummy_precision()) const; template bool isOrthogonal(const MatrixBase& other, - RealScalar prec = dummy_precision()) const; - bool isUnitary(RealScalar prec = dummy_precision()) const; + RealScalar prec = NumTraits::dummy_precision()) const; + bool isUnitary(RealScalar prec = NumTraits::dummy_precision()) const; /** \returns true if each coefficients of \c *this and \a other are all exactly equal. * \warning When using floating point scalar values you probably should rather use a @@ -310,13 +310,13 @@ template class MatrixBase ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, - const RealScalar& absDeterminantThreshold = dummy_precision() + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template void computeInverseWithCheck( ResultType& inverse, bool& invertible, - const RealScalar& absDeterminantThreshold = dummy_precision() + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; Scalar determinant() const; diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 304e2c1d6..7279e156d 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -49,6 +49,7 @@ template struct NumTraits; template<> struct NumTraits + : std::numeric_limits { typedef int Real; typedef double FloatingPoint; @@ -60,9 +61,12 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; + + inline static int dummy_precision() { return 0; } }; template<> struct NumTraits + : std::numeric_limits { typedef float Real; typedef float FloatingPoint; @@ -74,9 +78,12 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; + + inline static float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits + : std::numeric_limits { typedef double Real; typedef double FloatingPoint; @@ -88,9 +95,12 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; + + inline static double dummy_precision() { return 1e-12; } }; template struct NumTraits > + : std::numeric_limits > { typedef _Real Real; typedef std::complex<_Real> FloatingPoint; @@ -102,9 +112,13 @@ template struct NumTraits > AddCost = 2 * NumTraits::AddCost, MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; + + inline static Real epsilon() { return std::numeric_limits::epsilon(); } + inline static Real dummy_precision() { return NumTraits::dummy_precision(); } }; template<> struct NumTraits + : std::numeric_limits { typedef long long int Real; typedef long double FloatingPoint; @@ -119,6 +133,7 @@ template<> struct NumTraits }; template<> struct NumTraits + : std::numeric_limits { typedef long double Real; typedef long double FloatingPoint; @@ -130,9 +145,12 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; + + static inline long double dummy_precision() { return NumTraits::dummy_precision(); } }; template<> struct NumTraits + : std::numeric_limits { typedef bool Real; typedef float FloatingPoint; @@ -144,6 +162,8 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; + + inline static bool dummy_precision() { return 0; } }; #endif // EIGEN_NUMTRAITS_H diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index d55dc2a96..27c52b4dc 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -94,7 +94,7 @@ void ComplexEigenSolver::compute(const MatrixType& matrix) m_eivalues.resize(n,1); m_eivec.resize(n,n); - RealScalar eps = epsilon(); + RealScalar eps = NumTraits::epsilon(); // Reduce to complex Schur form ComplexSchur schur(matrix); diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 38a1f56dc..5deac3247 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -159,7 +159,7 @@ void ComplexSchur::compute(const MatrixType& matrix, bool skipU) RealScalar d,sd,sf; Complex c,b,disc,r1,r2,kappa; - RealScalar eps = epsilon(); + RealScalar eps = NumTraits::epsilon(); int iter = 0; while(true) diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index 1865b179b..5c1f992c6 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -171,7 +171,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const AlignedBox& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const AlignedBox& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); } protected: diff --git a/Eigen/src/Geometry/AngleAxis.h b/Eigen/src/Geometry/AngleAxis.h index 284c60a74..d02ecf4c5 100644 --- a/Eigen/src/Geometry/AngleAxis.h +++ b/Eigen/src/Geometry/AngleAxis.h @@ -146,7 +146,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const AngleAxis& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const AngleAxis& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_axis.isApprox(other.m_axis, prec) && ei_isApprox(m_angle,other.m_angle, prec); } }; @@ -165,7 +165,7 @@ template AngleAxis& AngleAxis::operator=(const QuaternionBase& q) { Scalar n2 = q.vec().squaredNorm(); - if (n2 < dummy_precision()*dummy_precision()) + if (n2 < NumTraits::dummy_precision()*NumTraits::dummy_precision()) { m_angle = 0; m_axis << 1, 0, 0; diff --git a/Eigen/src/Geometry/EulerAngles.h b/Eigen/src/Geometry/EulerAngles.h index b6dbf8ae9..13d23761a 100644 --- a/Eigen/src/Geometry/EulerAngles.h +++ b/Eigen/src/Geometry/EulerAngles.h @@ -50,7 +50,7 @@ MatrixBase::eulerAngles(int a0, int a1, int a2) const Matrix res; typedef Matrix Vector2; - const Scalar epsilon = dummy_precision(); + const Scalar epsilon = NumTraits::dummy_precision(); const int odd = ((a0+1)%3 == a1) ? 0 : 1; const int i = a0; diff --git a/Eigen/src/Geometry/Hyperplane.h b/Eigen/src/Geometry/Hyperplane.h index aab3d5b35..1d0b299ba 100644 --- a/Eigen/src/Geometry/Hyperplane.h +++ b/Eigen/src/Geometry/Hyperplane.h @@ -257,7 +257,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const Hyperplane& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const Hyperplane& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_coeffs.isApprox(other.m_coeffs, prec); } protected: diff --git a/Eigen/src/Geometry/ParametrizedLine.h b/Eigen/src/Geometry/ParametrizedLine.h index 21a5595b9..1846a440a 100644 --- a/Eigen/src/Geometry/ParametrizedLine.h +++ b/Eigen/src/Geometry/ParametrizedLine.h @@ -123,7 +123,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const ParametrizedLine& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const ParametrizedLine& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_origin.isApprox(other.m_origin, prec) && m_direction.isApprox(other.m_direction, prec); } protected: diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 98b91e2de..67319d15b 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -163,7 +163,7 @@ public: * * \sa MatrixBase::isApprox() */ template - bool isApprox(const QuaternionBase& other, RealScalar prec = dummy_precision()) const + bool isApprox(const QuaternionBase& other, RealScalar prec = NumTraits::dummy_precision()) const { return coeffs().isApprox(other.coeffs(), prec); } /** return the result vector of \a v through the rotation*/ @@ -508,7 +508,7 @@ inline Derived& QuaternionBase::setFromTwoVectors(const MatrixBase()) + if (c < Scalar(-1)+NumTraits::dummy_precision()) { c = std::max(c,-1); Matrix m; m << v0.transpose(), v1.transpose(); @@ -584,7 +584,7 @@ template Quaternion::Scalar> QuaternionBase::slerp(Scalar t, const QuaternionBase& other) const { - static const Scalar one = Scalar(1) - epsilon(); + static const Scalar one = Scalar(1) - NumTraits::epsilon(); Scalar d = this->dot(other); Scalar absD = ei_abs(d); diff --git a/Eigen/src/Geometry/Rotation2D.h b/Eigen/src/Geometry/Rotation2D.h index 7f24a3eae..73f731f76 100644 --- a/Eigen/src/Geometry/Rotation2D.h +++ b/Eigen/src/Geometry/Rotation2D.h @@ -121,7 +121,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const Rotation2D& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const Rotation2D& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return ei_isApprox(m_angle,other.m_angle, prec); } }; diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h index 4695914fd..2ff8eaba3 100644 --- a/Eigen/src/Geometry/Scaling.h +++ b/Eigen/src/Geometry/Scaling.h @@ -107,7 +107,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const UniformScaling& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const UniformScaling& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return ei_isApprox(m_factor, other.factor(), prec); } }; diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index 309c1e1fd..40bc7033a 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -429,7 +429,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const Transform& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const Transform& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_matrix.isApprox(other.m_matrix, prec); } /** Sets the last row to [0 ... 0 1] diff --git a/Eigen/src/Geometry/Translation.h b/Eigen/src/Geometry/Translation.h index b7477df9f..1e3906bde 100644 --- a/Eigen/src/Geometry/Translation.h +++ b/Eigen/src/Geometry/Translation.h @@ -154,7 +154,7 @@ public: * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const Translation& other, typename NumTraits::Real prec = dummy_precision()) const + bool isApprox(const Translation& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const { return m_coeffs.isApprox(other.m_coeffs, prec); } }; diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 657cbbf1c..72e878223 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -276,7 +276,7 @@ template class FullPivLU return m_usePrescribedThreshold ? m_prescribedThreshold // this formula comes from experimenting (see "LU precision tuning" thread on the list) // and turns out to be identical to Higham's formula used already in LDLt. - : epsilon() * m_lu.diagonalSize(); + : NumTraits::epsilon() * m_lu.diagonalSize(); } /** \returns the rank of the matrix of which *this is the LU decomposition. diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index 63d069081..bf28605dd 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -282,7 +282,7 @@ template class ColPivHouseholderQR return m_usePrescribedThreshold ? m_prescribedThreshold // this formula comes from experimenting (see "LU precision tuning" thread on the list) // and turns out to be identical to Higham's formula used already in LDLt. - : epsilon() * m_qr.diagonalSize(); + : NumTraits::epsilon() * m_qr.diagonalSize(); } /** \returns the number of nonzero pivots in the QR decomposition. @@ -350,7 +350,7 @@ ColPivHouseholderQR& ColPivHouseholderQR::compute(const for(int k = 0; k < cols; ++k) colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm(); - RealScalar threshold_helper = colSqNorms.maxCoeff() * ei_abs2(epsilon()) / rows; + RealScalar threshold_helper = colSqNorms.maxCoeff() * ei_abs2(NumTraits::epsilon()) / rows; m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case) m_maxpivot = RealScalar(0); diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 8e8dbbbf8..1ec60aeaf 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -270,7 +270,7 @@ FullPivHouseholderQR& FullPivHouseholderQR::compute(cons RowVectorType temp(cols); - m_precision = epsilon() * size; + m_precision = NumTraits::epsilon() * size; m_rows_transpositions.resize(matrix.rows()); IntRowVectorType cols_transpositions(matrix.cols()); @@ -370,7 +370,7 @@ struct ei_solve_retval, Rhs> RealScalar biggest_in_upper_part_of_c = c.corner(TopLeft, dec().rank(), c.cols()).cwiseAbs().maxCoeff(); RealScalar biggest_in_lower_part_of_c = c.corner(BottomLeft, rows-dec().rank(), c.cols()).cwiseAbs().maxCoeff(); // FIXME brain dead - const RealScalar m_precision = epsilon() * std::min(rows,cols); + const RealScalar m_precision = NumTraits::epsilon() * std::min(rows,cols); if(!ei_isMuchSmallerThan(biggest_in_lower_part_of_c, biggest_in_upper_part_of_c, m_precision)) return; } diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 55fac3d12..94375725f 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -295,7 +295,7 @@ JacobiSVD& JacobiSVD::compute(const Ma int cols = matrix.cols(); int diagSize = std::min(rows, cols); m_singularValues.resize(diagSize); - const RealScalar precision = 2 * epsilon(); + const RealScalar precision = 2 * NumTraits::epsilon(); if(!ei_svd_precondition_if_more_rows_than_cols::run(matrix, work_matrix, *this) && !ei_svd_precondition_if_more_cols_than_rows::run(matrix, work_matrix, *this)) diff --git a/Eigen/src/SVD/SVD.h b/Eigen/src/SVD/SVD.h index 1d4bbe417..c308ff3ee 100644 --- a/Eigen/src/SVD/SVD.h +++ b/Eigen/src/SVD/SVD.h @@ -193,7 +193,7 @@ SVD& SVD::compute(const MatrixType& matrix) int i=0,its=0,j=0,k=0,l=0,nm=0; Scalar anorm, c, f, g, h, s, scale, x, y, z; bool convergence = true; - Scalar eps = dummy_precision(); + Scalar eps = NumTraits::dummy_precision(); Matrix rv1(n); g = scale = anorm = 0; diff --git a/Eigen/src/Sparse/AmbiVector.h b/Eigen/src/Sparse/AmbiVector.h index 6bb6ee3e4..1ac28272b 100644 --- a/Eigen/src/Sparse/AmbiVector.h +++ b/Eigen/src/Sparse/AmbiVector.h @@ -296,7 +296,7 @@ class AmbiVector<_Scalar>::Iterator * In practice, all coefficients having a magnitude smaller than \a epsilon * are skipped. */ - Iterator(const AmbiVector& vec, RealScalar epsilon = RealScalar(0.1)*dummy_precision()) + Iterator(const AmbiVector& vec, RealScalar epsilon = RealScalar(0.1)*NumTraits::dummy_precision()) : m_vector(vec) { m_epsilon = epsilon; diff --git a/Eigen/src/Sparse/CompressedStorage.h b/Eigen/src/Sparse/CompressedStorage.h index b25b05e91..4fc1797d1 100644 --- a/Eigen/src/Sparse/CompressedStorage.h +++ b/Eigen/src/Sparse/CompressedStorage.h @@ -185,7 +185,7 @@ class CompressedStorage return m_values[id]; } - void prune(Scalar reference, RealScalar epsilon = dummy_precision()) + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) { size_t k = 0; size_t n = size(); diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index 96385df50..2594ffebc 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -209,7 +209,7 @@ class DynamicSparseMatrix inline void finalize() {} - void prune(Scalar reference, RealScalar epsilon = dummy_precision()) + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) { for (int j=0; j(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); } /** Creates a LDLT object and compute the respective factorization of \a matrix using @@ -103,7 +103,7 @@ class SparseLDLT : m_matrix(matrix.rows(), matrix.cols()), m_flags(flags), m_status(0) { ei_assert((MatrixType::Flags&RowMajorBit)==0); - m_precision = RealScalar(0.1) * Eigen::dummy_precision(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); compute(matrix); } diff --git a/Eigen/src/Sparse/SparseLLT.h b/Eigen/src/Sparse/SparseLLT.h index 9018fe0df..a1c10ba13 100644 --- a/Eigen/src/Sparse/SparseLLT.h +++ b/Eigen/src/Sparse/SparseLLT.h @@ -54,7 +54,7 @@ class SparseLLT SparseLLT(int flags = 0) : m_flags(flags), m_status(0) { - m_precision = RealScalar(0.1) * Eigen::dummy_precision(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); } /** Creates a LLT object and compute the respective factorization of \a matrix using @@ -62,7 +62,7 @@ class SparseLLT SparseLLT(const MatrixType& matrix, int flags = 0) : m_matrix(matrix.rows(), matrix.cols()), m_flags(flags), m_status(0) { - m_precision = RealScalar(0.1) * Eigen::dummy_precision(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); compute(matrix); } diff --git a/Eigen/src/Sparse/SparseLU.h b/Eigen/src/Sparse/SparseLU.h index 0802b0807..3fe9df1ef 100644 --- a/Eigen/src/Sparse/SparseLU.h +++ b/Eigen/src/Sparse/SparseLU.h @@ -59,7 +59,7 @@ class SparseLU SparseLU(int flags = 0) : m_flags(flags), m_status(0) { - m_precision = RealScalar(0.1) * Eigen::dummy_precision(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); } /** Creates a LU object and compute the respective factorization of \a matrix using @@ -67,7 +67,7 @@ class SparseLU SparseLU(const MatrixType& matrix, int flags = 0) : /*m_matrix(matrix.rows(), matrix.cols()),*/ m_flags(flags), m_status(0) { - m_precision = RealScalar(0.1) * Eigen::dummy_precision(); + m_precision = RealScalar(0.1) * Eigen::NumTraits::dummy_precision(); compute(matrix); } diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index bba0404c3..68385f564 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -350,7 +350,7 @@ class SparseMatrix } } - void prune(Scalar reference, RealScalar epsilon = dummy_precision()) + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) { int k = 0; for (int j=0; j class SparseMatrixBase : public AnyMatrixBase bool isApprox(const SparseMatrixBase& other, - RealScalar prec = dummy_precision()) const + RealScalar prec = NumTraits::dummy_precision()) const { return toDense().isApprox(other.toDense(),prec); } template bool isApprox(const MatrixBase& other, - RealScalar prec = dummy_precision()) const + RealScalar prec = NumTraits::dummy_precision()) const { return toDense().isApprox(other,prec); } // bool isMuchSmallerThan(const RealScalar& other, -// RealScalar prec = dummy_precision()) const; +// RealScalar prec = NumTraits::dummy_precision()) const; // template // bool isMuchSmallerThan(const MatrixBase& other, -// RealScalar prec = dummy_precision()) const; +// RealScalar prec = NumTraits::dummy_precision()) const; -// bool isApproxToConstant(const Scalar& value, RealScalar prec = dummy_precision()) const; -// bool isZero(RealScalar prec = dummy_precision()) const; -// bool isOnes(RealScalar prec = dummy_precision()) const; -// bool isIdentity(RealScalar prec = dummy_precision()) const; -// bool isDiagonal(RealScalar prec = dummy_precision()) const; +// bool isApproxToConstant(const Scalar& value, RealScalar prec = NumTraits::dummy_precision()) const; +// bool isZero(RealScalar prec = NumTraits::dummy_precision()) const; +// bool isOnes(RealScalar prec = NumTraits::dummy_precision()) const; +// bool isIdentity(RealScalar prec = NumTraits::dummy_precision()) const; +// bool isDiagonal(RealScalar prec = NumTraits::dummy_precision()) const; -// bool isUpper(RealScalar prec = dummy_precision()) const; -// bool isLower(RealScalar prec = dummy_precision()) const; +// bool isUpper(RealScalar prec = NumTraits::dummy_precision()) const; +// bool isLower(RealScalar prec = NumTraits::dummy_precision()) const; // template // bool isOrthogonal(const MatrixBase& other, -// RealScalar prec = dummy_precision()) const; -// bool isUnitary(RealScalar prec = dummy_precision()) const; +// RealScalar prec = NumTraits::dummy_precision()) const; +// bool isUnitary(RealScalar prec = NumTraits::dummy_precision()) const; // template // inline bool operator==(const MatrixBase& other) const diff --git a/Eigen/src/Sparse/SparseVector.h b/Eigen/src/Sparse/SparseVector.h index 13b4f75a6..58f3ec342 100644 --- a/Eigen/src/Sparse/SparseVector.h +++ b/Eigen/src/Sparse/SparseVector.h @@ -202,7 +202,7 @@ class SparseVector EIGEN_DEPRECATED void endFill() {} inline void finalize() {} - void prune(Scalar reference, RealScalar epsilon = dummy_precision()) + void prune(Scalar reference, RealScalar epsilon = NumTraits::dummy_precision()) { m_data.prune(reference,epsilon); } diff --git a/test/prec_inverse_4x4.cpp b/test/prec_inverse_4x4.cpp index e1b05aa0d..59ccbbcaf 100644 --- a/test/prec_inverse_4x4.cpp +++ b/test/prec_inverse_4x4.cpp @@ -35,7 +35,7 @@ template void inverse_permutation_4x4() { MatrixType m = PermutationMatrix<4>(indices); MatrixType inv = m.inverse(); - double error = double( (m*inv-MatrixType::Identity()).norm() / epsilon() ); + double error = double( (m*inv-MatrixType::Identity()).norm() / NumTraits::epsilon() ); VERIFY(error == 0.0); std::next_permutation(indices.data(),indices.data()+4); } @@ -53,9 +53,9 @@ template void inverse_general_4x4(int repeat) do { m = MatrixType::Random(); absdet = ei_abs(m.determinant()); - } while(absdet < epsilon()); + } while(absdet < NumTraits::epsilon()); MatrixType inv = m.inverse(); - double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / epsilon() ); + double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / NumTraits::epsilon() ); error_sum += error; error_max = std::max(error_max, error); } diff --git a/test/product.h b/test/product.h index 85afbe1e4..f6109fae4 100644 --- a/test/product.h +++ b/test/product.h @@ -26,7 +26,7 @@ #include template -bool areNotApprox(const MatrixBase& m1, const MatrixBase& m2, typename Derived1::RealScalar epsilon = dummy_precision()) +bool areNotApprox(const MatrixBase& m1, const MatrixBase& m2, typename Derived1::RealScalar epsilon = NumTraits::dummy_precision()) { return !((m1-m2).cwiseAbs2().maxCoeff() < epsilon * epsilon * std::max(m1.cwiseAbs2().maxCoeff(), m2.cwiseAbs2().maxCoeff())); From bb290977b8e4ec43dbd1f628e357d762da0e33d5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Feb 2010 11:11:21 +0100 Subject: [PATCH 083/109] add highest and lowest functions to NumTraits --- Eigen/src/Core/NumTraits.h | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 7279e156d..f4036dc0c 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -34,7 +34,7 @@ * \c std::complex, \c std::complex, and \c long \c double (especially * useful to enforce x87 arithmetics when SSE is the default). * - * The provided data consists of: + * The provided data consists of everything that is supported by std::numeric_limits, plus: * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real * is a typedef to \a U. @@ -45,11 +45,29 @@ * type, and to 0 otherwise. * \li An enum \a HasFloatingPoint. It is equal to \c 0 if \a T is \c int, * and to \c 1 otherwise. + * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. + * \li A dummy_precision() function returning a weak epsilon value. It is mainly used by the fuzzy comparison operators. + * \li Two higest() and lowest() functions returning the higest and lowest possible values respectively. */ template struct NumTraits; +template struct ei_default_float_numtraits + : std::numeric_limits +{ + inline static T higest() { return std::numeric_limits::max(); } + inline static T lowest() { return -std::numeric_limits::max(); } +}; + +template struct ei_default_integral_numtraits + : std::numeric_limits +{ + inline static int dummy_precision() { return 0; } + inline static T highest() { return std::numeric_limits::max(); } + inline static T lowest() { return std::numeric_limits::min(); } +}; + template<> struct NumTraits - : std::numeric_limits + : ei_default_integral_numtraits { typedef int Real; typedef double FloatingPoint; @@ -61,12 +79,10 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; - - inline static int dummy_precision() { return 0; } }; template<> struct NumTraits - : std::numeric_limits + : ei_default_float_numtraits { typedef float Real; typedef float FloatingPoint; @@ -83,7 +99,7 @@ template<> struct NumTraits }; template<> struct NumTraits - : std::numeric_limits + : ei_default_float_numtraits { typedef double Real; typedef double FloatingPoint; @@ -100,7 +116,7 @@ template<> struct NumTraits }; template struct NumTraits > - : std::numeric_limits > + : ei_default_float_numtraits > { typedef _Real Real; typedef std::complex<_Real> FloatingPoint; @@ -118,7 +134,7 @@ template struct NumTraits > }; template<> struct NumTraits - : std::numeric_limits + : ei_default_integral_numtraits { typedef long long int Real; typedef long double FloatingPoint; @@ -133,7 +149,7 @@ template<> struct NumTraits }; template<> struct NumTraits - : std::numeric_limits + : ei_default_float_numtraits { typedef long double Real; typedef long double FloatingPoint; @@ -150,7 +166,7 @@ template<> struct NumTraits }; template<> struct NumTraits - : std::numeric_limits + : ei_default_integral_numtraits { typedef bool Real; typedef float FloatingPoint; @@ -162,8 +178,6 @@ template<> struct NumTraits AddCost = 1, MulCost = 1 }; - - inline static bool dummy_precision() { return 0; } }; #endif // EIGEN_NUMTRAITS_H From 8918d18e219c9a31219e2b90bbe522d344495881 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Feb 2010 11:40:55 +0100 Subject: [PATCH 084/109] Improved patch from Manuel Yguel: Enhance AlignedBox to accept integral types and add some usefull methods: diagonal, volume, sample. --- Eigen/src/Core/NumTraits.h | 4 +- Eigen/src/Geometry/AlignedBox.h | 218 ++++++++++++++++++++++++++------ 2 files changed, 181 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index f4036dc0c..1baf62496 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -54,8 +54,8 @@ template struct NumTraits; template struct ei_default_float_numtraits : std::numeric_limits { - inline static T higest() { return std::numeric_limits::max(); } - inline static T lowest() { return -std::numeric_limits::max(); } + inline static T highest() { return std::numeric_limits::max(); } + inline static T lowest() { return -std::numeric_limits::max(); } }; template struct ei_default_integral_numtraits diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index 5c1f992c6..c5510e5ad 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -43,37 +43,70 @@ class AlignedBox public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) enum { AmbientDimAtCompileTime = _AmbientDim }; - typedef _Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; + typedef _Scalar Scalar; + typedef NumTraits ScalarTraits; + typedef typename ScalarTraits::Real RealScalar; + typedef typename ScalarTraits::FloatingPoint FloatingPoint; + typedef Matrix VectorType; + + /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */ + enum CornerType + { + /** 1D names */ + Min=0, Max=1, + + /** Added names for 2D */ + BottomLeft=0, BottomRight=1, + TopLeft=2, TopRight=3, + + /** Added names for 3D */ + BottomLeftFloor=0, BottomRightFloor=1, + TopLeftFloor=2, TopRightFloor=3, + BottomLeftCeil=4, BottomRightCeil=5, + TopLeftCeil=6, TopRightCeil=7 + }; + /** Default constructor initializing a null box. */ inline explicit AlignedBox() - { if (AmbientDimAtCompileTime!=Dynamic) setNull(); } + { if (AmbientDimAtCompileTime!=Dynamic) setEmpty(); } /** Constructs a null box with \a _dim the dimension of the ambient space. */ inline explicit AlignedBox(int _dim) : m_min(_dim), m_max(_dim) - { setNull(); } + { setEmpty(); } /** Constructs a box with extremities \a _min and \a _max. */ - inline AlignedBox(const VectorType& _min, const VectorType& _max) : m_min(_min), m_max(_max) {} + template + inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {} /** Constructs a box containing a single point \a p. */ - inline explicit AlignedBox(const VectorType& p) : m_min(p), m_max(p) {} + template + inline explicit AlignedBox(const MatrixBase& a_p) + { + const typename ei_nested::type p(a_p.derived()); + m_min = p; + m_max = p; + } ~AlignedBox() {} /** \returns the dimension in which the box holds */ inline int dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size()-1 : AmbientDimAtCompileTime; } - /** \returns true if the box is null, i.e, empty. */ - inline bool isNull() const { return (m_min.array() > m_max.array()).any(); } + /** \deprecated use isEmpty */ + inline bool isNull() const { return isEmpty(); } - /** Makes \c *this a null/empty box. */ - inline void setNull() + /** \deprecated use setEmpty */ + inline void setNull() { setEmpty(); } + + /** \returns true if the box is empty. */ + inline bool isEmpty() const { return (m_min.cwise() > m_max).any(); } + + /** Makes \c *this an empty box. */ + inline void setEmpty() { - m_min.setConstant( std::numeric_limits::max()); - m_max.setConstant(-std::numeric_limits::max()); + m_min.setConstant( ScalarTraits::highest() ); + m_max.setConstant( ScalarTraits::lowest() ); } /** \returns the minimal corner */ @@ -86,45 +119,135 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) inline VectorType& max() { return m_max; } /** \returns the center of the box */ - inline VectorType center() const { return (m_min + m_max) / 2; } + inline const CwiseUnaryOp, + CwiseBinaryOp, VectorType, VectorType> > + center() const + { return (m_min+m_max)/2; } + + /** \returns the lengths of the sides of the bounding box. + * Note that this function does not get the same + * result for integral or floating scalar types: see + */ + inline const CwiseBinaryOp< ei_scalar_difference_op, VectorType, VectorType> sizes() const + { return m_max - m_min; } + + /** \returns the volume of the bounding box */ + inline Scalar volume() const + { return sizes().prod(); } + + /** \returns an expression for the bounding box diagonal vector + * if the length of the diagonal is needed: diagonal().norm() + * will provide it. + */ + inline CwiseBinaryOp< ei_scalar_difference_op, VectorType, VectorType> diagonal() const + { return sizes(); } + + /** \returns the vertex of the bounding box at the corner defined by + * the corner-id corner. It works only for a 1D, 2D or 3D bounding box. + * For 1D bounding boxes corners are named by 2 enum constants: + * BottomLeft and BottomRight. + * For 2D bounding boxes, corners are named by 4 enum constants: + * BottomLeft, BottomRight, TopLeft, TopRight. + * For 3D bounding boxes, the following names are added: + * BottomLeftCeil, BottomRightCeil, TopLeftCeil, TopRightCeil. + */ + inline VectorType corner(CornerType corner) const + { + EIGEN_STATIC_ASSERT(_AmbientDim <= 3, THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE); + + VectorType res; + + int mult = 1; + for(int d=0; d() + ei_random_amplitude()) + / (Scalar(2)*ei_random_amplitude() ); + } + else + r[d] = ei_random(m_min[d], m_max[d]); + } + return r; + } /** \returns true if the point \a p is inside the box \c *this. */ - inline bool contains(const VectorType& p) const - { return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all(); } + template + inline bool contains(const MatrixBase& a_p) const + { + const typename ei_nested::type p(a_p.derived()); + return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all(); + } /** \returns true if the box \a b is entirely inside the box \c *this. */ inline bool contains(const AlignedBox& b) const { return (m_min.array()<=b.min().array()).all() && (b.max().array()<=m_max.array()).all(); } /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */ - inline AlignedBox& extend(const VectorType& p) - { m_min = m_min.cwiseMin(p); m_max = m_max.cwiseMax(p); return *this; } + template + inline AlignedBox& extend(const MatrixBase& a_p) + { + const typename ei_nested::type p(a_p.derived()); + m_min = m_min.cwiseMin(p); + m_max = m_max.cwiseMax(p); + return *this; + } /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */ inline AlignedBox& extend(const AlignedBox& b) - { m_min = m_min.cwiseMin(b.m_min); m_max = m_max.cwiseMax(b.m_max); return *this; } + { + m_min = m_min.cwiseMin(b.m_min); + m_max = m_max.cwiseMax(b.m_max); + return *this; + } /** Clamps \c *this by the box \a b and returns a reference to \c *this. */ inline AlignedBox& clamp(const AlignedBox& b) - { m_min = m_min.cwiseMax(b.m_min); m_max = m_max.cwiseMin(b.m_max); return *this; } + { + m_min = m_min.cwiseMax(b.m_min); + m_max = m_max.cwiseMin(b.m_max); + return *this; + } /** Returns an AlignedBox that is the intersection of \a b and \c *this */ - inline AlignedBox intersection(const AlignedBox &b) const - { return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); } + inline AlignedBox intersection(const AlignedBox& b) const + {return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); } /** Returns an AlignedBox that is the union of \a b and \c *this */ - inline AlignedBox merged(const AlignedBox &b) const + inline AlignedBox merged(const AlignedBox& b) const { return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); } /** Translate \c *this by the vector \a t and returns a reference to \c *this. */ - inline AlignedBox& translate(const VectorType& t) - { m_min += t; m_max += t; return *this; } + template + inline AlignedBox& translate(const MatrixBase& a_t) + { + const typename ei_nested::type t(a_t.derived()); + m_min += t; + m_max += t; + return *this; + } /** \returns the squared distance between the point \a p and the box \c *this, * and zero if \a p is inside the box. * \sa exteriorDistance() */ - inline Scalar squaredExteriorDistance(const VectorType& p) const; + template + inline Scalar squaredExteriorDistance(const MatrixBase& a_p) const; /** \returns the squared distance between the boxes \a b and \c *this, * and zero if the boxes intersect. @@ -136,15 +259,16 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * and zero if \a p is inside the box. * \sa squaredExteriorDistance() */ - inline Scalar exteriorDistance(const VectorType& p) const - { return ei_sqrt(squaredExteriorDistance(p)); } + template + inline FloatingPoint exteriorDistance(const MatrixBase& p) const + { return ei_sqrt(FloatingPoint(squaredExteriorDistance(p))); } /** \returns the distance between the boxes \a b and \c *this, * and zero if the boxes intersect. * \sa squaredExteriorDistance() */ - inline Scalar exteriorDistance(const AlignedBox& b) const - { return ei_sqrt(squaredExteriorDistance(b)); } + inline FloatingPoint exteriorDistance(const AlignedBox& b) const + { return ei_sqrt(FloatingPoint(squaredExteriorDistance(b))); } /** \returns \c *this with scalar type casted to \a NewScalarType * @@ -171,7 +295,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * determined by \a prec. * * \sa MatrixBase::isApprox() */ - bool isApprox(const AlignedBox& other, typename NumTraits::Real prec = NumTraits::dummy_precision()) const + bool isApprox(const AlignedBox& other, RealScalar prec = ScalarTraits::dummy_precision()) const { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); } protected: @@ -179,32 +303,48 @@ protected: VectorType m_min, m_max; }; -template -inline Scalar AlignedBox::squaredExteriorDistance(const VectorType& p) const + + +template +template +inline Scalar AlignedBox::squaredExteriorDistance(const MatrixBase& a_p) const { + const typename ei_nested::type p(a_p.derived()); Scalar dist2 = 0.; Scalar aux; for (int k=0; k p[k] ) + { + aux = m_min[k] - p[k]; dist2 += aux*aux; - else if ( (aux = (m_max[k]-p[k])) m_max[k] ) + { + aux = p[k] - m_max[k]; dist2 += aux*aux; + } } return dist2; } -template -inline Scalar AlignedBox::squaredExteriorDistance(const AlignedBox& b) const +template +inline Scalar AlignedBox::squaredExteriorDistance(const AlignedBox& b) const { Scalar dist2 = 0.; Scalar aux; for (int k=0; k0.) + if( m_min[k] > b.m_max[k] ) + { + aux = m_min[k] - b.m_max[k]; dist2 += aux*aux; - else if ( (aux = (m_min[k]-b.m_max[k]))>0. ) + } + else if( b.m_min[k] > m_max[k] ) + { + aux = b.m_min[k] - m_max[k]; dist2 += aux*aux; + } } return dist2; } From 71b64d34987ae7d3fbe70f0098c12a7c65b41084 Mon Sep 17 00:00:00 2001 From: Manuel Yguel Date: Wed, 20 Jan 2010 14:55:10 +0100 Subject: [PATCH 085/109] Updated tests for enhanced AlignedBox with volume, diagonal and better handling of integral types. --- test/geo_alignedbox.cpp | 124 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 11 deletions(-) diff --git a/test/geo_alignedbox.cpp b/test/geo_alignedbox.cpp index d496578da..5233d602a 100644 --- a/test/geo_alignedbox.cpp +++ b/test/geo_alignedbox.cpp @@ -27,6 +27,9 @@ #include #include +#include +using namespace std; + template void alignedbox(const BoxType& _box) { /* this test covers the following files: @@ -40,6 +43,8 @@ template void alignedbox(const BoxType& _box) VectorType p0 = VectorType::Random(dim); VectorType p1 = VectorType::Random(dim); + while( p1 == p0 ){ + p1 = VectorType::Random(dim); } RealScalar s1 = ei_random(0,1); BoxType b0(dim); @@ -49,20 +54,13 @@ template void alignedbox(const BoxType& _box) b0.extend(p0); b0.extend(p1); VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1)); - VERIFY(!b0.contains(p0 + (1+s1)*(p1-p0))); + VERIFY(!b0.contains(p0 + (2+s1)*(p1-p0))); (b2 = b0).extend(b1); VERIFY(b2.contains(b0)); VERIFY(b2.contains(b1)); VERIFY_IS_APPROX(b2.clamp(b0), b0); - // casting - const int Dim = BoxType::AmbientDimAtCompileTime; - typedef typename GetDifferentType::type OtherScalar; - AlignedBox hp1f = b0.template cast(); - VERIFY_IS_APPROX(hp1f.template cast(),b0); - AlignedBox hp1d = b0.template cast(); - VERIFY_IS_APPROX(hp1d.template cast(),b0); // alignment -- make sure there is no memory alignment assertion BoxType *bp0 = new BoxType(dim); @@ -70,13 +68,117 @@ template void alignedbox(const BoxType& _box) bp0->extend(*bp1); delete bp0; delete bp1; + + // sampling + for( int i=0; i<10; ++i ) + { + VectorType r = b0.sample(); + VERIFY(b0.contains(r)); + } + } + + +template +void alignedboxCastTests(const BoxType& _box) +{ + // casting + const int dim = _box.dim(); + typedef typename BoxType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef Matrix VectorType; + + VectorType p0 = VectorType::Random(dim); + VectorType p1 = VectorType::Random(dim); + + BoxType b0(dim); + + b0.extend(p0); + b0.extend(p1); + + const int Dim = BoxType::AmbientDimAtCompileTime; + typedef typename GetDifferentType::type OtherScalar; + AlignedBox hp1f = b0.template cast(); + VERIFY_IS_APPROX(hp1f.template cast(),b0); + AlignedBox hp1d = b0.template cast(); + VERIFY_IS_APPROX(hp1d.template cast(),b0); +} + + +void specificTest1() +{ + Vector2f m; m << -1.0f, -2.0f; + Vector2f M; M << 1.0f, 5.0f; + + typedef AlignedBox BoxType; + BoxType box( m, M ); + + Vector2f sides = M-m; + VERIFY_IS_APPROX(sides, box.sizes() ); + VERIFY_IS_APPROX(sides[1], box.sizes()[1] ); + VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() ); + VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() ); + + VERIFY_IS_APPROX( 14.0f, box.volume() ); + VERIFY_IS_APPROX( 53.0f, box.diagonal().squaredNorm() ); + VERIFY_IS_APPROX( ei_sqrt( 53.0f ), box.diagonal().norm() ); + + VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeft ) ); + VERIFY_IS_APPROX( M, box.corner( BoxType::TopRight ) ); + Vector2f bottomRight; bottomRight << M[0], m[1]; + Vector2f topLeft; topLeft << m[0], M[1]; + VERIFY_IS_APPROX( bottomRight, box.corner( BoxType::BottomRight ) ); + VERIFY_IS_APPROX( topLeft, box.corner( BoxType::TopLeft ) ); +} + + +void specificTest2() +{ + Vector3i m; m << -1, -2, 0; + Vector3i M; M << 1, 5, 3; + + typedef AlignedBox BoxType; + BoxType box( m, M ); + + Vector3i sides = M-m; + VERIFY_IS_APPROX(sides, box.sizes() ); + VERIFY_IS_APPROX(sides[1], box.sizes()[1] ); + VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() ); + VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() ); + + VERIFY_IS_APPROX( 42, box.volume() ); + VERIFY_IS_APPROX( 62, box.diagonal().squaredNorm() ); + + VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeftFloor ) ); + VERIFY_IS_APPROX( M, box.corner( BoxType::TopRightCeil ) ); + Vector3i bottomRightFloor; bottomRightFloor << M[0], m[1], m[2]; + Vector3i topLeftFloor; topLeftFloor << m[0], M[1], m[2]; + VERIFY_IS_APPROX( bottomRightFloor, box.corner( BoxType::BottomRightFloor ) ); + VERIFY_IS_APPROX( topLeftFloor, box.corner( BoxType::TopLeftFloor ) ); +} + + void test_geo_alignedbox() { - for(int i = 0; i < g_repeat; i++) { + for(int i = 0; i < g_repeat; i++) + { CALL_SUBTEST_1( alignedbox(AlignedBox()) ); - CALL_SUBTEST_2( alignedbox(AlignedBox()) ); - CALL_SUBTEST_3( alignedbox(AlignedBox()) ); + CALL_SUBTEST_2( alignedboxCastTests(AlignedBox()) ); + + CALL_SUBTEST_3( alignedbox(AlignedBox()) ); + CALL_SUBTEST_4( alignedboxCastTests(AlignedBox()) ); + + CALL_SUBTEST_5( alignedbox(AlignedBox()) ); + CALL_SUBTEST_6( alignedboxCastTests(AlignedBox()) ); + + CALL_SUBTEST_7( alignedbox(AlignedBox()) ); + CALL_SUBTEST_8( alignedboxCastTests(AlignedBox()) ); + + CALL_SUBTEST_9( alignedbox(AlignedBox()) ); + CALL_SUBTEST_10( alignedbox(AlignedBox()) ); + CALL_SUBTEST_11( alignedbox(AlignedBox()) ); } + CALL_SUBTEST_12( specificTest1() ); + CALL_SUBTEST_13( specificTest2() ); } From 0ca67afe6abbe9c19a8254d50daaddd2a343531c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Feb 2010 14:08:47 +0100 Subject: [PATCH 086/109] finally here is a simple solution making (a*b).diagonal() even faster than a.lazyProduct(b).diagonal() !! --- Eigen/src/Core/Product.h | 15 +++++---------- Eigen/src/Core/ProductBase.h | 13 +++++++++++++ Eigen/src/Core/products/CoeffBasedProduct.h | 16 ++++++++++++++++ doc/A05_PortingFrom2To3.dox | 8 ++++++-- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 5903476b5..af05773ee 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -447,17 +447,12 @@ MatrixBase::operator*(const MatrixBase &other) const /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * - * The coefficients of the product will be computed as requested that is particularly useful when you - * only want to compute a small fraction of the result's coefficients. - * Here is an example: - * \code - * MatrixXf a(10,10), b(10,10); - * (a*b).diagonal().sum(); // here a*b is entirely computed into a 10x10 temporary matrix - * a.lazyProduct(b).diagonal().sum(); // here a*b is evaluated in a lazy manner, - * // so only the diagonal coefficients will be computed - * \endcode + * The returned product will behave like any other expressions: the coefficients of the product will be + * computed once at a time as requested. This might be useful in some extremely rare cases when only + * a small and no coherent fraction of the result's coefficients have to be computed. * - * \warning This version of the matrix product can be much much slower if all coefficients have to be computed anyways. + * \warning This version of the matrix product can be much much slower. So use it only if you know + * what you are doing and that you measured a true speed improvement. * * \sa operator*(const MatrixBase&) */ diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index bbd77f059..481e7c760 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -83,6 +83,9 @@ class ProductBase : public MatrixBase typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename ei_cleantype::type _ActualRhsType; + // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once + typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; + public: typedef typename Base::PlainMatrixType PlainMatrixType; @@ -121,6 +124,16 @@ class ProductBase : public MatrixBase return m_result; } + const Diagonal diagonal() const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } + + template + const Diagonal diagonal() const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } + + const Diagonal diagonal(int index) const + { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } + protected: const LhsNested m_lhs; diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index c9d333072..f030d59b5 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -127,8 +127,14 @@ class CoeffBasedProduct Unroll ? InnerSize-1 : Dynamic, _LhsNested, _RhsNested, Scalar> ScalarCoeffImpl; + typedef CoeffBasedProduct LazyCoeffBasedProductType; + public: + inline CoeffBasedProduct(const CoeffBasedProduct& other) + : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) + {} + template inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) @@ -185,6 +191,16 @@ class CoeffBasedProduct const _LhsNested& lhs() const { return m_lhs; } const _RhsNested& rhs() const { return m_rhs; } + const Diagonal diagonal() const + { return reinterpret_cast(*this); } + + template + const Diagonal diagonal() const + { return reinterpret_cast(*this); } + + const Diagonal diagonal(int index) const + { return reinterpret_cast(*this).diagonal(index); } + protected: const LhsNested m_lhs; const RhsNested m_rhs; diff --git a/doc/A05_PortingFrom2To3.dox b/doc/A05_PortingFrom2To3.dox index 9c157b016..57f801f84 100644 --- a/doc/A05_PortingFrom2To3.dox +++ b/doc/A05_PortingFrom2To3.dox @@ -81,9 +81,9 @@ With Eigen2 you would have written: c = (a.cwise().abs().cwise().pow(3)).cwise() * (b.cwise().abs().cwise().sin()); \endcode -\section LazyVsNoalias Lazy evaluation versus noalias +\section LazyVsNoalias Lazy evaluation and noalias -In Eigen all operations are performed in a lazy fashion except the matrix products which are always evaluated to a temporary by default. +In Eigen all operations are performed in a lazy fashion except the matrix products which are always evaluated into a temporary by default. In Eigen2, lazy evaluation could be enforced by tagging a product using the .lazy() function. However, in complex expressions it was not easy to determine where to put the lazy() function. In Eigen3, the lazy() feature has been superseded by the MatrixBase::noalias() function which can be used on the left hand side of an assignment when no aliasing can occur. Here is an example: @@ -92,6 +92,10 @@ MatrixXf a, b, c; ... c.noalias() += 2 * a.transpose() * b; \endcode +However, the noalias mechanism does not cover all the features of the old .lazy(). Indeed, in some extremely rare cases, +it might be useful to explicit request for a lay product, i.e., for a product which will be evaluated one coefficient at once, on request, +just like any other expressions. To this end you can use the MatrixBase::lazyProduct() function, however we strongly discourage you to +use it unless you are sure of what you are doing, i.e., you have rigourosly measured a speed improvement. */ From d0e8342a048d7933f8decefc853bb561f90eb917 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Wed, 10 Feb 2010 18:00:36 +0100 Subject: [PATCH 087/109] Fixed warning. --- test/product_notemporary.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index bb213368e..79720145e 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -110,11 +110,11 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView() * m2.block(r0,c0,r1,c1), 1); // Zero temporaries for lazy products ... - VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 ); + VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 ); // ... and one temporary for even deeply (>=2) nested products - VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 1 ); - VERIFY_EVALUATION_COUNT( Scalar tmp = Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 1 ); + VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 1 ); + VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 1 ); // Zero temporaries for ... CoeffBasedProductMode // - does not work with GCC because of the <..>, we'ld need variadic macros ... From fc5fa7774340da06cb4de7337c0928e76dfe4946 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Wed, 10 Feb 2010 17:59:27 +0000 Subject: [PATCH 088/109] unsupported/Eigen/AlignedVector3: dummy_precision is now in NumTraits --- unsupported/Eigen/AlignedVector3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index 15510a258..6e9772cf5 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -189,7 +189,7 @@ template class AlignedVector3 } template - inline bool isApprox(const MatrixBase& other, RealScalar eps=dummy_precision()) const + inline bool isApprox(const MatrixBase& other, RealScalar eps=NumTraits::dummy_precision()) const { return m_coeffs.template head<3>().isApprox(other,eps); } From ccc58e935ea2123590013f0cdc8e6ae25bca4f28 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 11 Feb 2010 01:43:03 +0100 Subject: [PATCH 089/109] fix usage of epsilon wrt to latest API change --- .../HybridNonLinearSolver.h | 10 ++++----- .../LevenbergMarquardt.h | 22 +++++++++---------- .../Eigen/src/NonLinearOptimization/chkder.h | 6 ++--- .../Eigen/src/NonLinearOptimization/covar.h | 2 +- .../Eigen/src/NonLinearOptimization/dogleg.h | 2 +- .../Eigen/src/NonLinearOptimization/fdjac1.h | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index 5c832b73d..0754a426b 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -63,7 +63,7 @@ public: Parameters() : factor(Scalar(100.)) , maxfev(1000) - , xtol(ei_sqrt(epsilon())) + , xtol(ei_sqrt(NumTraits::epsilon())) , nb_of_subdiagonals(-1) , nb_of_superdiagonals(-1) , epsfcn(Scalar(0.)) {} @@ -81,7 +81,7 @@ public: HybridNonLinearSolverSpace::Status hybrj1( FVectorType &x, - const Scalar tol = ei_sqrt(epsilon()) + const Scalar tol = ei_sqrt(NumTraits::epsilon()) ); HybridNonLinearSolverSpace::Status solveInit( @@ -99,7 +99,7 @@ public: HybridNonLinearSolverSpace::Status hybrd1( FVectorType &x, - const Scalar tol = ei_sqrt(epsilon()) + const Scalar tol = ei_sqrt(NumTraits::epsilon()) ); HybridNonLinearSolverSpace::Status solveNumericalDiffInit( @@ -341,7 +341,7 @@ HybridNonLinearSolver::solveOneStep( /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) return HybridNonLinearSolverSpace::TooManyFunctionEvaluation; - if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) + if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= NumTraits::epsilon() * xnorm) return HybridNonLinearSolverSpace::TolTooSmall; if (nslow2 == 5) return HybridNonLinearSolverSpace::NotMakingProgressJacobian; @@ -590,7 +590,7 @@ HybridNonLinearSolver::solveNumericalDiffOneStep( /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) return HybridNonLinearSolverSpace::TooManyFunctionEvaluation; - if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= epsilon() * xnorm) + if (Scalar(.1) * std::max(Scalar(.1) * delta, pnorm) <= NumTraits::epsilon() * xnorm) return HybridNonLinearSolverSpace::TolTooSmall; if (nslow2 == 5) return HybridNonLinearSolverSpace::NotMakingProgressJacobian; diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 49b63bed8..f21331e3e 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -67,8 +67,8 @@ public: Parameters() : factor(Scalar(100.)) , maxfev(400) - , ftol(ei_sqrt(epsilon())) - , xtol(ei_sqrt(epsilon())) + , ftol(ei_sqrt(NumTraits::epsilon())) + , xtol(ei_sqrt(NumTraits::epsilon())) , gtol(Scalar(0.)) , epsfcn(Scalar(0.)) {} Scalar factor; @@ -84,7 +84,7 @@ public: LevenbergMarquardtSpace::Status lmder1( FVectorType &x, - const Scalar tol = ei_sqrt(epsilon()) + const Scalar tol = ei_sqrt(NumTraits::epsilon()) ); LevenbergMarquardtSpace::Status minimize( @@ -104,12 +104,12 @@ public: FunctorType &functor, FVectorType &x, int *nfev, - const Scalar tol = ei_sqrt(epsilon()) + const Scalar tol = ei_sqrt(NumTraits::epsilon()) ); LevenbergMarquardtSpace::Status lmstr1( FVectorType &x, - const Scalar tol = ei_sqrt(epsilon()) + const Scalar tol = ei_sqrt(NumTraits::epsilon()) ); LevenbergMarquardtSpace::Status minimizeOptimumStorage( @@ -370,11 +370,11 @@ LevenbergMarquardt::minimizeOneStep( /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) return LevenbergMarquardtSpace::TooManyFunctionEvaluation; - if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) + if (ei_abs(actred) <= NumTraits::epsilon() && prered <= NumTraits::epsilon() && Scalar(.5) * ratio <= 1.) return LevenbergMarquardtSpace::FtolTooSmall; - if (delta <= epsilon() * xnorm) + if (delta <= NumTraits::epsilon() * xnorm) return LevenbergMarquardtSpace::XtolTooSmall; - if (gnorm <= epsilon()) + if (gnorm <= NumTraits::epsilon()) return LevenbergMarquardtSpace::GtolTooSmall; } while (ratio < Scalar(1e-4)); @@ -621,11 +621,11 @@ LevenbergMarquardt::minimizeOptimumStorageOneStep( /* tests for termination and stringent tolerances. */ if (nfev >= parameters.maxfev) return LevenbergMarquardtSpace::TooManyFunctionEvaluation; - if (ei_abs(actred) <= epsilon() && prered <= epsilon() && Scalar(.5) * ratio <= 1.) + if (ei_abs(actred) <= NumTraits::epsilon() && prered <= NumTraits::epsilon() && Scalar(.5) * ratio <= 1.) return LevenbergMarquardtSpace::FtolTooSmall; - if (delta <= epsilon() * xnorm) + if (delta <= NumTraits::epsilon() * xnorm) return LevenbergMarquardtSpace::XtolTooSmall; - if (gnorm <= epsilon()) + if (gnorm <= NumTraits::epsilon()) return LevenbergMarquardtSpace::GtolTooSmall; } while (ratio < Scalar(1e-4)); diff --git a/unsupported/Eigen/src/NonLinearOptimization/chkder.h b/unsupported/Eigen/src/NonLinearOptimization/chkder.h index be8115230..591e8bef7 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/chkder.h +++ b/unsupported/Eigen/src/NonLinearOptimization/chkder.h @@ -13,8 +13,8 @@ void ei_chkder( Matrix< Scalar, Dynamic, 1 > &err ) { - const Scalar eps = ei_sqrt(epsilon()); - const Scalar epsf = chkder_factor * epsilon(); + const Scalar eps = ei_sqrt(NumTraits::epsilon()); + const Scalar epsf = chkder_factor * NumTraits::epsilon(); const Scalar epslog = chkder_log10e * ei_log(eps); Scalar temp; @@ -44,7 +44,7 @@ void ei_chkder( if (fvec[i] != 0. && fvecp[i] != 0. && ei_abs(fvecp[i] - fvec[i]) >= epsf * ei_abs(fvec[i])) temp = eps * ei_abs((fvecp[i] - fvec[i]) / eps - err[i]) / (ei_abs(fvec[i]) + ei_abs(fvecp[i])); err[i] = 1.; - if (temp > epsilon() && temp < eps) + if (temp > NumTraits::epsilon() && temp < eps) err[i] = (chkder_log10e * ei_log(temp) - epslog) / epslog; if (temp >= eps) err[i] = 0.; diff --git a/unsupported/Eigen/src/NonLinearOptimization/covar.h b/unsupported/Eigen/src/NonLinearOptimization/covar.h index 15c72d6ed..2f983a958 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/covar.h +++ b/unsupported/Eigen/src/NonLinearOptimization/covar.h @@ -3,7 +3,7 @@ template void ei_covar( Matrix< Scalar, Dynamic, Dynamic > &r, const VectorXi &ipvt, - Scalar tol = ei_sqrt(epsilon()) ) + Scalar tol = ei_sqrt(NumTraits::epsilon()) ) { /* Local variables */ int i, j, k, l, ii, jj; diff --git a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h index b3c4fbb96..9c1d38dea 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +++ b/unsupported/Eigen/src/NonLinearOptimization/dogleg.h @@ -14,7 +14,7 @@ void ei_dogleg( Scalar sgnorm; /* Function Body */ - const Scalar epsmch = epsilon(); + const Scalar epsmch = NumTraits::epsilon(); const int n = qrfac.cols(); assert(n==qtb.size()); assert(n==x.size()); diff --git a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h index 9564a784b..3dc1e8070 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h +++ b/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h @@ -17,7 +17,7 @@ int ei_fdjac1( int start, length; /* Function Body */ - const Scalar epsmch = epsilon(); + const Scalar epsmch = NumTraits::epsilon(); const int n = x.size(); assert(fvec.size()==n); Matrix< Scalar, Dynamic, 1 > wa1(n); From fd19dd57d81df2505638d170a3149e710699dafb Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 11 Feb 2010 01:43:36 +0100 Subject: [PATCH 090/109] fix usage of epsilon wrt to latest API change --- unsupported/Eigen/src/NumericalDiff/NumericalDiff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h index db6f791df..8d23cb4ae 100644 --- a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h +++ b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h @@ -80,7 +80,7 @@ public: Scalar h; int nfev=0; const int n = _x.size(); - const Scalar eps = ei_sqrt((std::max(epsfcn,epsilon() ))); + const Scalar eps = ei_sqrt((std::max(epsfcn,NumTraits::epsilon() ))); ValueType val1, val2; InputType x = _x; // TODO : we should do this only if the size is not already known From 602778ea26ae345b40958728da918fbd0ba23dad Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 11 Feb 2010 01:49:27 +0100 Subject: [PATCH 091/109] also fix tests for NumTraits::epsilon() --- unsupported/test/NonLinearOptimization.cpp | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index c8b0b55a1..1313726a1 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -692,8 +692,8 @@ void testNistChwirut2(void) x<< 0.15, 0.008, 0.010; // do the computation lm.resetParameters(); - lm.parameters.ftol = 1.E6*epsilon(); - lm.parameters.xtol = 1.E6*epsilon(); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); info = lm.minimize(x); // check return value @@ -1243,8 +1243,8 @@ void testNistBoxBOD(void) // do the computation BoxBOD_functor functor; LevenbergMarquardt lm(functor); - lm.parameters.ftol = 1.E6*epsilon(); - lm.parameters.xtol = 1.E6*epsilon(); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); lm.parameters.factor = 10.; info = lm.minimize(x); @@ -1264,8 +1264,8 @@ void testNistBoxBOD(void) x<< 100., 0.75; // do the computation lm.resetParameters(); - lm.parameters.ftol = epsilon(); - lm.parameters.xtol = epsilon(); + lm.parameters.ftol = NumTraits::epsilon(); + lm.parameters.xtol = NumTraits::epsilon(); info = lm.minimize(x); // check return value @@ -1325,8 +1325,8 @@ void testNistMGH17(void) // do the computation MGH17_functor functor; LevenbergMarquardt lm(functor); - lm.parameters.ftol = epsilon(); - lm.parameters.xtol = epsilon(); + lm.parameters.ftol = NumTraits::epsilon(); + lm.parameters.xtol = NumTraits::epsilon(); lm.parameters.maxfev = 1000; info = lm.minimize(x); @@ -1584,8 +1584,8 @@ void testNistThurber(void) // do the computation thurber_functor functor; LevenbergMarquardt lm(functor); - lm.parameters.ftol = 1.E4*epsilon(); - lm.parameters.xtol = 1.E4*epsilon(); + lm.parameters.ftol = 1.E4*NumTraits::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits::epsilon(); info = lm.minimize(x); // check return value @@ -1609,8 +1609,8 @@ void testNistThurber(void) x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ; // do the computation lm.resetParameters(); - lm.parameters.ftol = 1.E4*epsilon(); - lm.parameters.xtol = 1.E4*epsilon(); + lm.parameters.ftol = 1.E4*NumTraits::epsilon(); + lm.parameters.xtol = 1.E4*NumTraits::epsilon(); info = lm.minimize(x); // check return value @@ -1676,8 +1676,8 @@ void testNistRat43(void) // do the computation rat43_functor functor; LevenbergMarquardt lm(functor); - lm.parameters.ftol = 1.E6*epsilon(); - lm.parameters.xtol = 1.E6*epsilon(); + lm.parameters.ftol = 1.E6*NumTraits::epsilon(); + lm.parameters.xtol = 1.E6*NumTraits::epsilon(); info = lm.minimize(x); // check return value @@ -1698,8 +1698,8 @@ void testNistRat43(void) x<< 700., 5., 0.75, 1.3; // do the computation lm.resetParameters(); - lm.parameters.ftol = 1.E5*epsilon(); - lm.parameters.xtol = 1.E5*epsilon(); + lm.parameters.ftol = 1.E5*NumTraits::epsilon(); + lm.parameters.xtol = 1.E5*NumTraits::epsilon(); info = lm.minimize(x); // check return value From 48f59806698037fdf0517c3bbe19e4f50865d655 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 11 Feb 2010 09:24:29 +0100 Subject: [PATCH 092/109] fix compilation (cwise and epsilon) --- Eigen/src/Geometry/AlignedBox.h | 2 +- unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index c5510e5ad..b5b40a82d 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -100,7 +100,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) inline void setNull() { setEmpty(); } /** \returns true if the box is empty. */ - inline bool isEmpty() const { return (m_min.cwise() > m_max).any(); } + inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); } /** Makes \c *this an empty box. */ inline void setEmpty() diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h index d82b7626f..4bcae47c0 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h @@ -121,7 +121,7 @@ bool MatrixFunctionAtomic::taylorConverged(int s, const MatrixType& const int n = F.rows(); const RealScalar F_norm = F.cwiseAbs().rowwise().sum().maxCoeff(); const RealScalar Fincr_norm = Fincr.cwiseAbs().rowwise().sum().maxCoeff(); - if (Fincr_norm < epsilon() * F_norm) { + if (Fincr_norm < NumTraits::epsilon() * F_norm) { RealScalar delta = 0; RealScalar rfactorial = 1; for (int r = 0; r < n; r++) { @@ -133,7 +133,7 @@ bool MatrixFunctionAtomic::taylorConverged(int s, const MatrixType& delta = std::max(delta, mx / rfactorial); } const RealScalar P_norm = P.cwiseAbs().rowwise().sum().maxCoeff(); - if (m_mu * delta * P_norm < epsilon() * F_norm) + if (m_mu * delta * P_norm < NumTraits::epsilon() * F_norm) return true; } return false; From 93e86b0884fa9ad6f6fe02645ce8dc15c2a6daf9 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 11 Feb 2010 11:31:22 +0100 Subject: [PATCH 093/109] Fixed typos. Replace NumTraits::dummy_precision() (three locations) by false in order to suppress warnings. --- Eigen/src/Core/MathFunctions.h | 6 +++--- Eigen/src/Core/NumTraits.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 1a4561555..d9119c245 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -321,15 +321,15 @@ template<> inline bool ei_random() { return (ei_random(0,1) == 1); } -inline bool ei_isMuchSmallerThan(bool a, bool, bool = NumTraits::dummy_precision()) +inline bool ei_isMuchSmallerThan(bool a, bool, bool = false/*NumTraits::dummy_precision()*/) { return !a; } -inline bool ei_isApprox(bool a, bool b, bool = NumTraits::dummy_precision()) +inline bool ei_isApprox(bool a, bool b, bool = false/*NumTraits::dummy_precision()*/) { return a == b; } -inline bool ei_isApproxOrLessThan(bool a, bool b, bool = NumTraits::dummy_precision()) +inline bool ei_isApproxOrLessThan(bool a, bool b, bool = false/*NumTraits::dummy_precision()*/) { return int(a) <= int(b); } diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 1baf62496..4f0cc04eb 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -47,7 +47,7 @@ * and to \c 1 otherwise. * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. * \li A dummy_precision() function returning a weak epsilon value. It is mainly used by the fuzzy comparison operators. - * \li Two higest() and lowest() functions returning the higest and lowest possible values respectively. + * \li Two highest() and lowest() functions returning the highest and lowest possible values respectively. */ template struct NumTraits; From 13ce92f5ba8a17530d837c145df88837eee0076c Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 11 Feb 2010 11:31:36 +0100 Subject: [PATCH 094/109] Fixed notemporary unit test. --- test/product_notemporary.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 79720145e..332858851 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -112,9 +112,9 @@ template void product_notemporary(const MatrixType& m) // Zero temporaries for lazy products ... VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 ); - // ... and one temporary for even deeply (>=2) nested products - VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 1 ); - VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 1 ); + // ... and even no temporary for even deeply (>=2) nested products + VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 0 ); + VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0 ); // Zero temporaries for ... CoeffBasedProductMode // - does not work with GCC because of the <..>, we'ld need variadic macros ... From ae0a17d30be41bf66a2915ce7b059f818a820241 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 11 Feb 2010 11:39:02 +0100 Subject: [PATCH 095/109] Here is the proper fix. --- Eigen/src/Core/MathFunctions.h | 6 +++--- Eigen/src/Core/NumTraits.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index d9119c245..1a4561555 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -321,15 +321,15 @@ template<> inline bool ei_random() { return (ei_random(0,1) == 1); } -inline bool ei_isMuchSmallerThan(bool a, bool, bool = false/*NumTraits::dummy_precision()*/) +inline bool ei_isMuchSmallerThan(bool a, bool, bool = NumTraits::dummy_precision()) { return !a; } -inline bool ei_isApprox(bool a, bool b, bool = false/*NumTraits::dummy_precision()*/) +inline bool ei_isApprox(bool a, bool b, bool = NumTraits::dummy_precision()) { return a == b; } -inline bool ei_isApproxOrLessThan(bool a, bool b, bool = false/*NumTraits::dummy_precision()*/) +inline bool ei_isApproxOrLessThan(bool a, bool b, bool = NumTraits::dummy_precision()) { return int(a) <= int(b); } diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 4f0cc04eb..37787b569 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -61,7 +61,7 @@ template struct ei_default_float_numtraits template struct ei_default_integral_numtraits : std::numeric_limits { - inline static int dummy_precision() { return 0; } + inline static T dummy_precision() { return T(0); } inline static T highest() { return std::numeric_limits::max(); } inline static T lowest() { return std::numeric_limits::min(); } }; From 1701a5d1f83028100799c7dabe55fcd767028e3d Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Wed, 10 Feb 2010 13:24:47 +0100 Subject: [PATCH 096/109] std:: namespace fixup for more restricive compilers such as QNX's QCC --- Eigen/src/Core/MathFunctions.h | 4 +- Eigen/src/Core/MatrixStorage.h | 2 +- .../Core/products/SelfadjointMatrixVector.h | 14 +++--- Eigen/src/Core/util/Memory.h | 46 +++++++++---------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 1a4561555..c97a68e50 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -52,7 +52,7 @@ inline int ei_real(int x) { return x; } inline int& ei_real_ref(int& x) { return x; } inline int ei_imag(int) { return 0; } inline int ei_conj(int x) { return x; } -inline int ei_abs(int x) { return abs(x); } +inline int ei_abs(int x) { return std::abs(x); } inline int ei_abs2(int x) { return x*x; } inline int ei_sqrt(int) { ei_assert(false); return 0; } inline int ei_exp(int) { ei_assert(false); return 0; } @@ -78,7 +78,7 @@ inline int ei_pow(int x, int y) template<> inline int ei_random(int a, int b) { // We can't just do rand()%n as only the high-order bits are really random - return a + static_cast((b-a+1) * (rand() / (RAND_MAX + 1.0))); + return a + static_cast((b-a+1) * (std::rand() / (RAND_MAX + 1.0))); } template<> inline int ei_random() { diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index 046670452..22da59f3b 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -53,7 +53,7 @@ struct ei_matrix_array #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - ei_assert((reinterpret_cast(array) & sizemask) == 0 \ + ei_assert((reinterpret_cast(array) & sizemask) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index 1c48208b3..8fd09ac95 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -83,10 +83,10 @@ static EIGEN_DONT_INLINE void ei_product_selfadjoint_vector( Scalar t3 = 0; Packet ptmp3 = ei_pset1(t3); - size_t starti = FirstTriangular ? 0 : j+2; - size_t endi = FirstTriangular ? j : size; - size_t alignedEnd = starti; - size_t alignedStart = (starti) + ei_first_aligned(&res[starti], endi-starti); + std::size_t starti = FirstTriangular ? 0 : j+2; + std::size_t endi = FirstTriangular ? j : size; + std::size_t alignedEnd = starti; + std::size_t alignedStart = (starti) + ei_first_aligned(&res[starti], endi-starti); alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize); res[j] += cj0.pmul(A0[j], t0); @@ -102,7 +102,7 @@ static EIGEN_DONT_INLINE void ei_product_selfadjoint_vector( t2 += cj1.pmul(A0[j+1], rhs[j+1]); } - for (size_t i=starti; i((reinterpret_cast(original) & ~(size_t(15))) + 16); + void *original = std::malloc(size+16); + void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(std::size_t(15))) + 16); *(reinterpret_cast(aligned) - 1) = original; return aligned; } @@ -71,13 +71,13 @@ inline void* ei_handmade_aligned_malloc(size_t size) inline void ei_handmade_aligned_free(void *ptr) { if(ptr) - free(*(reinterpret_cast(ptr) - 1)); + std::free(*(reinterpret_cast(ptr) - 1)); } /** \internal allocates \a size bytes. The returned pointer is guaranteed to have 16 bytes alignment. * On allocation error, the returned pointer is null, and if exceptions are enabled then a std::bad_alloc is thrown. */ -inline void* ei_aligned_malloc(size_t size) +inline void* ei_aligned_malloc(std::size_t size) { #ifdef EIGEN_NO_MALLOC ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)"); @@ -108,18 +108,18 @@ inline void* ei_aligned_malloc(size_t size) /** allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned. * On allocation error, the returned pointer is null, and if exceptions are enabled then a std::bad_alloc is thrown. */ -template inline void* ei_conditional_aligned_malloc(size_t size) +template inline void* ei_conditional_aligned_malloc(std::size_t size) { return ei_aligned_malloc(size); } -template<> inline void* ei_conditional_aligned_malloc(size_t size) +template<> inline void* ei_conditional_aligned_malloc(std::size_t size) { #ifdef EIGEN_NO_MALLOC ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)"); #endif - void *result = malloc(size); + void *result = std::malloc(size); #ifdef EIGEN_EXCEPTIONS if(!result) throw std::bad_alloc(); #endif @@ -129,9 +129,9 @@ template<> inline void* ei_conditional_aligned_malloc(size_t size) /** \internal construct the elements of an array. * The \a size parameter tells on how many objects to call the constructor of T. */ -template inline T* ei_construct_elements_of_array(T *ptr, size_t size) +template inline T* ei_construct_elements_of_array(T *ptr, std::size_t size) { - for (size_t i=0; i < size; ++i) ::new (ptr + i) T; + for (std::size_t i=0; i < size; ++i) ::new (ptr + i) T; return ptr; } @@ -139,13 +139,13 @@ template inline T* ei_construct_elements_of_array(T *ptr, size_t siz * On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown. * The default constructor of T is called. */ -template inline T* ei_aligned_new(size_t size) +template inline T* ei_aligned_new(std::size_t size) { T *result = reinterpret_cast(ei_aligned_malloc(sizeof(T)*size)); return ei_construct_elements_of_array(result, size); } -template inline T* ei_conditional_aligned_new(size_t size) +template inline T* ei_conditional_aligned_new(std::size_t size) { T *result = reinterpret_cast(ei_conditional_aligned_malloc(sizeof(T)*size)); return ei_construct_elements_of_array(result, size); @@ -179,13 +179,13 @@ template inline void ei_conditional_aligned_free(void *ptr) template<> inline void ei_conditional_aligned_free(void *ptr) { - free(ptr); + std::free(ptr); } /** \internal destruct the elements of an array. * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_destruct_elements_of_array(T *ptr, size_t size) +template inline void ei_destruct_elements_of_array(T *ptr, std::size_t size) { // always destruct an array starting from the end. while(size) ptr[--size].~T(); @@ -194,7 +194,7 @@ template inline void ei_destruct_elements_of_array(T *ptr, size_t si /** \internal delete objects constructed with ei_aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_aligned_delete(T *ptr, size_t size) +template inline void ei_aligned_delete(T *ptr, std::size_t size) { ei_destruct_elements_of_array(ptr, size); ei_aligned_free(ptr); @@ -203,7 +203,7 @@ template inline void ei_aligned_delete(T *ptr, size_t size) /** \internal delete objects constructed with ei_conditional_aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_conditional_aligned_delete(T *ptr, size_t size) +template inline void ei_conditional_aligned_delete(T *ptr, std::size_t size) { ei_destruct_elements_of_array(ptr, size); ei_conditional_aligned_free(ptr); @@ -282,23 +282,23 @@ inline static Integer ei_first_aligned(const Scalar* array, Integer size) #if EIGEN_ALIGN #ifdef EIGEN_EXCEPTIONS #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(size_t size, const std::nothrow_t&) throw() { \ + void* operator new(std::size_t size, const std::nothrow_t&) throw() { \ try { return Eigen::ei_conditional_aligned_malloc(size); } \ catch (...) { return 0; } \ return 0; \ } #else #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(size_t size, const std::nothrow_t&) throw() { \ + void* operator new(std::size_t size, const std::nothrow_t&) throw() { \ return Eigen::ei_conditional_aligned_malloc(size); \ } #endif #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \ - void *operator new(size_t size) { \ + void *operator new(std::size_t size) { \ return Eigen::ei_conditional_aligned_malloc(size); \ } \ - void *operator new[](size_t size) { \ + void *operator new[](std::size_t size) { \ return Eigen::ei_conditional_aligned_malloc(size); \ } \ void operator delete(void * ptr) throw() { Eigen::ei_conditional_aligned_free(ptr); } \ @@ -306,7 +306,7 @@ inline static Integer ei_first_aligned(const Scalar* array, Integer size) /* in-place new and delete. since (at least afaik) there is no actual */ \ /* memory allocated we can safely let the default implementation handle */ \ /* this particular case. */ \ - static void *operator new(size_t size, void *ptr) { return ::operator new(size,ptr); } \ + static void *operator new(std::size_t size, void *ptr) { return ::operator new(size,ptr); } \ void operator delete(void * memory, void *ptr) throw() { return ::operator delete(memory,ptr); } \ /* nothrow-new (returns zero instead of std::bad_alloc) */ \ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ @@ -340,8 +340,8 @@ template class aligned_allocator { public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; From a76950bdab00e36ef7ad8a34e01fdd2e53594ec1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 12 Feb 2010 09:41:56 +0100 Subject: [PATCH 097/109] fix a couple of ICE with gcc 4.0.1 --- Eigen/src/Core/DenseStorageBase.h | 2 +- Eigen/src/Householder/Householder.h | 6 +++--- Eigen/src/LU/Determinant.h | 2 +- test/product_notemporary.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index 7006e3a95..89903d0f6 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -62,7 +62,7 @@ class DenseStorageBase : public _Base typedef class Eigen::Map AlignedMapType; protected: - ei_matrix_storage m_storage; + ei_matrix_storage m_storage; public: enum { NeedsToAlign = (!(Options&DontAlign)) diff --git a/Eigen/src/Householder/Householder.h b/Eigen/src/Householder/Householder.h index cfd3935fc..d86e287fa 100644 --- a/Eigen/src/Householder/Householder.h +++ b/Eigen/src/Householder/Householder.h @@ -45,7 +45,7 @@ void makeTrivialHouseholder( template void MatrixBase::makeHouseholderInPlace(Scalar& tau, RealScalar& beta) { - VectorBlock::ret> essentialPart(derived(), 1, size()-1); + VectorBlock::ret> essentialPart(derived(), 1, size()-1); makeHouseholder(essentialPart, tau, beta); } @@ -99,7 +99,7 @@ void MatrixBase::applyHouseholderOnTheLeft( const Scalar& tau, Scalar* workspace) { - Map > tmp(workspace,cols()); + Map > tmp(workspace,cols()); Block bottom(derived(), 1, 0, rows()-1, cols()); tmp.noalias() = essential.adjoint() * bottom; tmp += this->row(0); @@ -114,7 +114,7 @@ void MatrixBase::applyHouseholderOnTheRight( const Scalar& tau, Scalar* workspace) { - Map > tmp(workspace,rows()); + Map > tmp(workspace,rows()); Block right(derived(), 0, 1, rows(), cols()-1); tmp.noalias() = right * essential.conjugate(); tmp += this->col(0); diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h index bae01256e..fb6577f08 100644 --- a/Eigen/src/LU/Determinant.h +++ b/Eigen/src/LU/Determinant.h @@ -99,7 +99,7 @@ template inline typename ei_traits::Scalar MatrixBase::determinant() const { assert(rows() == cols()); - typedef typename ei_nested::type Nested; + typedef typename ei_nested::type Nested; Nested nested(derived()); return ei_determinant_impl::type>::run(nested); } diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 332858851..9084cde6b 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -112,7 +112,7 @@ template void product_notemporary(const MatrixType& m) // Zero temporaries for lazy products ... VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 ); - // ... and even no temporary for even deeply (>=2) nested products + // ... and even no temporary for even deeply (>=2) nested products VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 0 ); VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0 ); From 37ca4200b219e2d98bd25a9f91085d60b482d82d Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 12 Feb 2010 08:58:29 -0500 Subject: [PATCH 098/109] Piotr's patch was missing many occurences of size_t. So, using std::size_t; This is the only way that we can ensure QCC support in the long term without having to think about it everytime. --- Eigen/Core | 4 +++ Eigen/src/Core/MapBase.h | 2 +- Eigen/src/Core/MatrixStorage.h | 2 +- .../Core/products/SelfadjointMatrixVector.h | 14 ++++---- Eigen/src/Core/util/Memory.h | 36 +++++++++---------- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index b9241a730..72c64d917 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -252,6 +252,10 @@ struct Dense {}; #include "src/Array/ArrayWrapper.h" #include "src/Array/Array.h" +// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to +// ensure QNX/QCC support +using std::size_t; + } // namespace Eigen #include "src/Array/GlobalFunctions.h" diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 81feb0b5a..a922d8bb0 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -170,7 +170,7 @@ template class MapBase void checkDataAlignment() const { ei_assert( ((!(ei_traits::Flags&AlignedBit)) - || ((std::size_t(m_data)&0xf)==0)) && "data is not aligned"); + || ((size_t(m_data)&0xf)==0)) && "data is not aligned"); } const Scalar* EIGEN_RESTRICT m_data; diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index 22da59f3b..046670452 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -53,7 +53,7 @@ struct ei_matrix_array #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - ei_assert((reinterpret_cast(array) & sizemask) == 0 \ + ei_assert((reinterpret_cast(array) & sizemask) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index 8fd09ac95..1c48208b3 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -83,10 +83,10 @@ static EIGEN_DONT_INLINE void ei_product_selfadjoint_vector( Scalar t3 = 0; Packet ptmp3 = ei_pset1(t3); - std::size_t starti = FirstTriangular ? 0 : j+2; - std::size_t endi = FirstTriangular ? j : size; - std::size_t alignedEnd = starti; - std::size_t alignedStart = (starti) + ei_first_aligned(&res[starti], endi-starti); + size_t starti = FirstTriangular ? 0 : j+2; + size_t endi = FirstTriangular ? j : size; + size_t alignedEnd = starti; + size_t alignedStart = (starti) + ei_first_aligned(&res[starti], endi-starti); alignedEnd = alignedStart + ((endi-alignedStart)/(PacketSize))*(PacketSize); res[j] += cj0.pmul(A0[j], t0); @@ -102,7 +102,7 @@ static EIGEN_DONT_INLINE void ei_product_selfadjoint_vector( t2 += cj1.pmul(A0[j+1], rhs[j+1]); } - for (std::size_t i=starti; i((reinterpret_cast(original) & ~(std::size_t(15))) + 16); + void *aligned = reinterpret_cast((reinterpret_cast(original) & ~(size_t(15))) + 16); *(reinterpret_cast(aligned) - 1) = original; return aligned; } @@ -77,7 +77,7 @@ inline void ei_handmade_aligned_free(void *ptr) /** \internal allocates \a size bytes. The returned pointer is guaranteed to have 16 bytes alignment. * On allocation error, the returned pointer is null, and if exceptions are enabled then a std::bad_alloc is thrown. */ -inline void* ei_aligned_malloc(std::size_t size) +inline void* ei_aligned_malloc(size_t size) { #ifdef EIGEN_NO_MALLOC ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)"); @@ -108,12 +108,12 @@ inline void* ei_aligned_malloc(std::size_t size) /** allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned. * On allocation error, the returned pointer is null, and if exceptions are enabled then a std::bad_alloc is thrown. */ -template inline void* ei_conditional_aligned_malloc(std::size_t size) +template inline void* ei_conditional_aligned_malloc(size_t size) { return ei_aligned_malloc(size); } -template<> inline void* ei_conditional_aligned_malloc(std::size_t size) +template<> inline void* ei_conditional_aligned_malloc(size_t size) { #ifdef EIGEN_NO_MALLOC ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)"); @@ -129,9 +129,9 @@ template<> inline void* ei_conditional_aligned_malloc(std::size_t size) /** \internal construct the elements of an array. * The \a size parameter tells on how many objects to call the constructor of T. */ -template inline T* ei_construct_elements_of_array(T *ptr, std::size_t size) +template inline T* ei_construct_elements_of_array(T *ptr, size_t size) { - for (std::size_t i=0; i < size; ++i) ::new (ptr + i) T; + for (size_t i=0; i < size; ++i) ::new (ptr + i) T; return ptr; } @@ -139,13 +139,13 @@ template inline T* ei_construct_elements_of_array(T *ptr, std::size_ * On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown. * The default constructor of T is called. */ -template inline T* ei_aligned_new(std::size_t size) +template inline T* ei_aligned_new(size_t size) { T *result = reinterpret_cast(ei_aligned_malloc(sizeof(T)*size)); return ei_construct_elements_of_array(result, size); } -template inline T* ei_conditional_aligned_new(std::size_t size) +template inline T* ei_conditional_aligned_new(size_t size) { T *result = reinterpret_cast(ei_conditional_aligned_malloc(sizeof(T)*size)); return ei_construct_elements_of_array(result, size); @@ -185,7 +185,7 @@ template<> inline void ei_conditional_aligned_free(void *ptr) /** \internal destruct the elements of an array. * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_destruct_elements_of_array(T *ptr, std::size_t size) +template inline void ei_destruct_elements_of_array(T *ptr, size_t size) { // always destruct an array starting from the end. while(size) ptr[--size].~T(); @@ -194,7 +194,7 @@ template inline void ei_destruct_elements_of_array(T *ptr, std::size /** \internal delete objects constructed with ei_aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_aligned_delete(T *ptr, std::size_t size) +template inline void ei_aligned_delete(T *ptr, size_t size) { ei_destruct_elements_of_array(ptr, size); ei_aligned_free(ptr); @@ -203,7 +203,7 @@ template inline void ei_aligned_delete(T *ptr, std::size_t size) /** \internal delete objects constructed with ei_conditional_aligned_new * The \a size parameters tells on how many objects to call the destructor of T. */ -template inline void ei_conditional_aligned_delete(T *ptr, std::size_t size) +template inline void ei_conditional_aligned_delete(T *ptr, size_t size) { ei_destruct_elements_of_array(ptr, size); ei_conditional_aligned_free(ptr); @@ -282,23 +282,23 @@ inline static Integer ei_first_aligned(const Scalar* array, Integer size) #if EIGEN_ALIGN #ifdef EIGEN_EXCEPTIONS #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(std::size_t size, const std::nothrow_t&) throw() { \ + void* operator new(size_t size, const std::nothrow_t&) throw() { \ try { return Eigen::ei_conditional_aligned_malloc(size); } \ catch (...) { return 0; } \ return 0; \ } #else #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ - void* operator new(std::size_t size, const std::nothrow_t&) throw() { \ + void* operator new(size_t size, const std::nothrow_t&) throw() { \ return Eigen::ei_conditional_aligned_malloc(size); \ } #endif #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \ - void *operator new(std::size_t size) { \ + void *operator new(size_t size) { \ return Eigen::ei_conditional_aligned_malloc(size); \ } \ - void *operator new[](std::size_t size) { \ + void *operator new[](size_t size) { \ return Eigen::ei_conditional_aligned_malloc(size); \ } \ void operator delete(void * ptr) throw() { Eigen::ei_conditional_aligned_free(ptr); } \ @@ -306,7 +306,7 @@ inline static Integer ei_first_aligned(const Scalar* array, Integer size) /* in-place new and delete. since (at least afaik) there is no actual */ \ /* memory allocated we can safely let the default implementation handle */ \ /* this particular case. */ \ - static void *operator new(std::size_t size, void *ptr) { return ::operator new(size,ptr); } \ + static void *operator new(size_t size, void *ptr) { return ::operator new(size,ptr); } \ void operator delete(void * memory, void *ptr) throw() { return ::operator delete(memory,ptr); } \ /* nothrow-new (returns zero instead of std::bad_alloc) */ \ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ @@ -340,7 +340,7 @@ template class aligned_allocator { public: - typedef std::size_t size_type; + typedef size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; From 9251cfed9b9a34181b95857d89b55c0edfd500d2 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 12 Feb 2010 09:03:16 -0500 Subject: [PATCH 099/109] this had to be done here, not at the end. --- Eigen/Core | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 72c64d917..18b0fafa9 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -121,6 +121,10 @@ namespace Eigen { +// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to +// ensure QNX/QCC support +using std::size_t; + /** \defgroup Core_Module Core module * This is the main module of Eigen providing dense matrix and vector support * (both fixed and dynamic size) with all the features corresponding to a BLAS library @@ -252,10 +256,6 @@ struct Dense {}; #include "src/Array/ArrayWrapper.h" #include "src/Array/Array.h" -// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to -// ensure QNX/QCC support -using std::size_t; - } // namespace Eigen #include "src/Array/GlobalFunctions.h" From a4a2671fd0b8429a0e4a4a19f28e1f7befb85df8 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 13 Feb 2010 22:38:27 +0000 Subject: [PATCH 100/109] Refactor matrix_function test in preparation of next commit. --- unsupported/test/matrix_function.cpp | 43 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index 446fa7ec3..d1f5824d8 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -25,28 +25,19 @@ #include "main.h" #include -// Returns either a matrix with iid random entries or a matrix with -// clustered eigenvalues. Matrices with clustered eigenvalue clusters -// lead to different code paths in MatrixFunction.h and are thus -// useful for testing. +// Returns a matrix with eigenvalues clustered around 0, 1 and 2. template -MatrixType createRandomMatrix(const int size) +MatrixType randomMatrixWithRealEivals(const int size) { typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - MatrixType result; - if (ei_random(0,1) == 0) { - result = MatrixType::Random(size, size); - } else { - MatrixType diag = MatrixType::Zero(size, size); - for (int i = 0; i < size; ++i) { - diag(i, i) = Scalar(RealScalar(ei_random(0,2))) - + ei_random() * Scalar(RealScalar(0.01)); - } - MatrixType A = MatrixType::Random(size, size); - result = A.inverse() * diag * A; + MatrixType diag = MatrixType::Zero(size, size); + for (int i = 0; i < size; ++i) { + diag(i, i) = Scalar(RealScalar(ei_random(0,2))) + + ei_random() * Scalar(RealScalar(0.01)); } - return result; + MatrixType A = MatrixType::Random(size, size); + return A.inverse() * diag * A; } template @@ -108,14 +99,24 @@ void testGonioFunctions(const MatrixType& A) } } +template +void testMatrix(const MatrixType& A) +{ + testMatrixExponential(A); + testHyperbolicFunctions(A); + testGonioFunctions(A); +} + template void testMatrixType(const MatrixType& m) { + // Matrices with clustered eigenvalue lead to different code paths + // in MatrixFunction.h and are thus useful for testing. + + const int size = m.rows(); for (int i = 0; i < g_repeat; i++) { - MatrixType A = createRandomMatrix(m.rows()); - testMatrixExponential(A); - testHyperbolicFunctions(A); - testGonioFunctions(A); + testMatrix(MatrixType::Random(size, size).eval()); + testMatrix(randomMatrixWithRealEivals(size)); } } From b18f737aa103c7589f589b354676f476d644c631 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 13 Feb 2010 22:49:01 +0000 Subject: [PATCH 101/109] Test matrix functions with matrices with clustered imaginary eivals. The idea is that these test MatrixFunction::swapEntriesInSchur(), which is not covered by existing tests. This did not work out as expected, but nevertheless it is a good test so I left it in. --- unsupported/test/matrix_function.cpp | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index d1f5824d8..de63937ad 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -40,6 +40,58 @@ MatrixType randomMatrixWithRealEivals(const int size) return A.inverse() * diag * A; } +template ::Scalar>::IsComplex> +struct randomMatrixWithImagEivals +{ + // Returns a matrix with eigenvalues clustered around 0 and +/- i. + static MatrixType run(const int size); +}; + +// Partial specialization for real matrices +template +struct randomMatrixWithImagEivals +{ + static MatrixType run(const int size) + { + typedef typename MatrixType::Scalar Scalar; + MatrixType diag = MatrixType::Zero(size, size); + int i = 0; + while (i < size) { + int randomInt = ei_random(-1, 1); + if (randomInt == 0 || i == size-1) { + diag(i, i) = ei_random() * Scalar(0.01); + ++i; + } else { + Scalar alpha = Scalar(randomInt) + ei_random() * Scalar(0.01); + diag(i, i+1) = alpha; + diag(i+1, i) = -alpha; + i += 2; + } + } + MatrixType A = MatrixType::Random(size, size); + return A.inverse() * diag * A; + } +}; + +// Partial specialization for complex matrices +template +struct randomMatrixWithImagEivals +{ + static MatrixType run(const int size) + { + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + const Scalar imagUnit(0, 1); + MatrixType diag = MatrixType::Zero(size, size); + for (int i = 0; i < size; ++i) { + diag(i, i) = Scalar(RealScalar(ei_random(-1, 1))) * imagUnit + + ei_random() * Scalar(RealScalar(0.01)); + } + MatrixType A = MatrixType::Random(size, size); + return A.inverse() * diag * A; + } +}; + template void testMatrixExponential(const MatrixType& A) { @@ -117,6 +169,7 @@ void testMatrixType(const MatrixType& m) for (int i = 0; i < g_repeat; i++) { testMatrix(MatrixType::Random(size, size).eval()); testMatrix(randomMatrixWithRealEivals(size)); + testMatrix(randomMatrixWithImagEivals::run(size)); } } From 8519558d11f72e9223e9057f7ebdf66e58b6972f Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 15 Feb 2010 10:11:10 +0100 Subject: [PATCH 102/109] Workaround for compounds affected by #94. --- Eigen/src/Core/AnyMatrixBase.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/AnyMatrixBase.h b/Eigen/src/Core/AnyMatrixBase.h index cc2f4157c..e56b56deb 100644 --- a/Eigen/src/Core/AnyMatrixBase.h +++ b/Eigen/src/Core/AnyMatrixBase.h @@ -61,8 +61,7 @@ template struct AnyMatrixBase { // This is the default implementation, // derived class can reimplement it in a more optimized way. - typename Dest::PlainMatrixType res(rows(),cols()); - evalTo(res); + typename Dest::PlainMatrixType res(*this); dst += res; } @@ -71,8 +70,7 @@ template struct AnyMatrixBase { // This is the default implementation, // derived class can reimplement it in a more optimized way. - typename Dest::PlainMatrixType res(rows(),cols()); - evalTo(res); + typename Dest::PlainMatrixType res(*this); dst -= res; } From d00bff91ad8a98ef03024b1e9b862519db3f9566 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Feb 2010 11:00:30 +0100 Subject: [PATCH 103/109] workaround weird gcc 4.0.1 compilation error --- test/geo_hyperplane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/geo_hyperplane.cpp b/test/geo_hyperplane.cpp index 1fd1e281a..cd19698bc 100644 --- a/test/geo_hyperplane.cpp +++ b/test/geo_hyperplane.cpp @@ -136,6 +136,6 @@ void test_geo_hyperplane() CALL_SUBTEST_3( hyperplane(Hyperplane()) ); CALL_SUBTEST_4( hyperplane(Hyperplane,5>()) ); CALL_SUBTEST_1( lines() ); - CALL_SUBTEST_2( lines() ); + CALL_SUBTEST_3( lines() ); } } From 21d0eb3f1146a3aa801b77374cf47bdae0ba5c77 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Feb 2010 11:01:55 +0100 Subject: [PATCH 104/109] the default implementation should really call evalTo --- Eigen/src/Core/AnyMatrixBase.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/AnyMatrixBase.h b/Eigen/src/Core/AnyMatrixBase.h index e56b56deb..a5d1cfe9f 100644 --- a/Eigen/src/Core/AnyMatrixBase.h +++ b/Eigen/src/Core/AnyMatrixBase.h @@ -61,7 +61,8 @@ template struct AnyMatrixBase { // This is the default implementation, // derived class can reimplement it in a more optimized way. - typename Dest::PlainMatrixType res(*this); + typename Dest::PlainMatrixType res(rows(),cols()); + evalTo(res); dst += res; } @@ -70,7 +71,8 @@ template struct AnyMatrixBase { // This is the default implementation, // derived class can reimplement it in a more optimized way. - typename Dest::PlainMatrixType res(*this); + typename Dest::PlainMatrixType res(rows(),cols()); + evalTo(res); dst -= res; } @@ -98,9 +100,9 @@ template struct AnyMatrixBase /** \brief Copies the generic expression \a other into *this. * - * \details The expression must provide a (templated) evalTo(Derived& dst) const - * function which does the actual job. In practice, this allows any user to write - * its own special matrix without having to modify MatrixBase + * \details The expression must provide a (templated) evalTo(Derived& dst) const + * function which does the actual job. In practice, this allows any user to write + * its own special matrix without having to modify MatrixBase * * \returns a reference to *this. */ From dcb395c6f5ae420edf83d0640c3f1d4f3493f3d6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Feb 2010 11:09:33 +0100 Subject: [PATCH 105/109] explicitly disable the use of evalTo for dense object --- Eigen/src/Core/DenseBase.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 700c11929..21d792f49 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -486,6 +486,12 @@ template class DenseBase #include EIGEN_DENSEBASE_PLUGIN #endif + // disable the use of evalTo for dense objects with a nice compilation error + template inline void evalTo(Dest& dst) const + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); + } + protected: /** Default constructor. Do nothing. */ DenseBase() From 016943f8709c108a9e143e2ff95cff97cd2d1d3e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Feb 2010 11:31:36 +0100 Subject: [PATCH 106/109] avoid 2 redundant calls to resize --- Eigen/src/Core/DenseStorageBase.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index 89903d0f6..5c8e48768 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -371,8 +371,7 @@ class DenseStorageBase : public _Base : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) { _check_template_params(); - resize(other.rows(), other.cols()); - *this = other; + Base::operator=(other.derived()); } /** \name Map From a9096b626bc5aba2b9a6175d60bfd06fca8fa37a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Feb 2010 11:39:57 +0100 Subject: [PATCH 107/109] not all versions of gcc support -Wno-variadic-macros --- CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07d5806e8..f4c2973d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,9 +53,15 @@ endif() if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wno-variadic-macros -fexceptions -fno-check-new -fno-common -fstrict-aliasing") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fexceptions -fno-check-new -fno-common -fstrict-aliasing") set(CMAKE_CXX_FLAGS_DEBUG "-g3") set(CMAKE_CXX_FLAGS_RELEASE "-g0 -O2") + + check_cxx_compiler_flag("-Wno-variadic-macros" COMPILER_SUPPORT_WNOVARIADICMACRO) + if(COMPILER_SUPPORT_WNOVARIADICMACRO) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros") + endif() + check_cxx_compiler_flag("-Wextra" COMPILER_SUPPORT_WEXTRA) if(COMPILER_SUPPORT_WEXTRA) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra") From 25019f08366a027e783617b4b8bd86f00237a5ee Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Mon, 15 Feb 2010 19:17:25 +0000 Subject: [PATCH 108/109] Use ReturnByValue to return result of ei_matrix_exponential() . --- .../src/MatrixFunctions/MatrixExponential.h | 228 +++++++++++------- .../doc/examples/MatrixExponential.cpp | 3 +- unsupported/test/matrix_exponential.cpp | 13 +- unsupported/test/matrix_function.cpp | 14 +- 4 files changed, 159 insertions(+), 99 deletions(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index fd1938a87..147e21bc1 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -29,74 +29,32 @@ template Scalar log2(Scalar v) { return std::log(v)/std::log(Scalar(2)); } #endif -/** \ingroup MatrixFunctions_Module - * - * \brief Compute the matrix exponential. - * - * \param[in] M matrix whose exponential is to be computed. - * \param[out] result pointer to the matrix in which to store the result. - * - * The matrix exponential of \f$ M \f$ is defined by - * \f[ \exp(M) = \sum_{k=0}^\infty \frac{M^k}{k!}. \f] - * The matrix exponential can be used to solve linear ordinary - * differential equations: the solution of \f$ y' = My \f$ with the - * initial condition \f$ y(0) = y_0 \f$ is given by - * \f$ y(t) = \exp(M) y_0 \f$. - * - * The cost of the computation is approximately \f$ 20 n^3 \f$ for - * matrices of size \f$ n \f$. The number 20 depends weakly on the - * norm of the matrix. - * - * The matrix exponential is computed using the scaling-and-squaring - * method combined with Padé approximation. The matrix is first - * rescaled, then the exponential of the reduced matrix is computed - * approximant, and then the rescaling is undone by repeated - * squaring. The degree of the Padé approximant is chosen such - * that the approximation error is less than the round-off - * error. However, errors may accumulate during the squaring phase. - * - * Details of the algorithm can be found in: Nicholas J. Higham, "The - * scaling and squaring method for the matrix exponential revisited," - * SIAM J. %Matrix Anal. Applic., 26:1179–1193, - * 2005. - * - * Example: The following program checks that - * \f[ \exp \left[ \begin{array}{ccc} - * 0 & \frac14\pi & 0 \\ - * -\frac14\pi & 0 & 0 \\ - * 0 & 0 & 0 - * \end{array} \right] = \left[ \begin{array}{ccc} - * \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\ - * \frac12\sqrt2 & \frac12\sqrt2 & 0 \\ - * 0 & 0 & 1 - * \end{array} \right]. \f] - * This corresponds to a rotation of \f$ \frac14\pi \f$ radians around - * the z-axis. - * - * \include MatrixExponential.cpp - * Output: \verbinclude MatrixExponential.out - * - * \note \p M has to be a matrix of \c float, \c double, - * \c complex or \c complex . - */ -template -EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase &M, - typename MatrixBase::PlainMatrixType* result); /** \ingroup MatrixFunctions_Module * \brief Class for computing the matrix exponential. + * \tparam MatrixType type of the argument of the exponential, + * expected to be an instantiation of the Matrix class template. */ template class MatrixExponential { public: - /** \brief Compute the matrix exponential. - * - * \param M matrix whose exponential is to be computed. - * \param result pointer to the matrix in which to store the result. - */ - MatrixExponential(const MatrixType &M, MatrixType *result); + /** \brief Constructor. + * + * The class stores a reference to \p M, so it should not be + * changed (or destroyed) before compute() is called. + * + * \param[in] M matrix whose exponential is to be computed. + */ + MatrixExponential(const MatrixType &M); + + /** \brief Computes the matrix exponential. + * + * \param[out] result the matrix exponential of \p M in the constructor. + */ + template + void compute(ResultType &result); private: @@ -109,7 +67,7 @@ class MatrixExponential { * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. * - * \param A Argument of matrix exponential + * \param[in] A Argument of matrix exponential */ void pade3(const MatrixType &A); @@ -118,7 +76,7 @@ class MatrixExponential { * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. * - * \param A Argument of matrix exponential + * \param[in] A Argument of matrix exponential */ void pade5(const MatrixType &A); @@ -127,7 +85,7 @@ class MatrixExponential { * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. * - * \param A Argument of matrix exponential + * \param[in] A Argument of matrix exponential */ void pade7(const MatrixType &A); @@ -136,7 +94,7 @@ class MatrixExponential { * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. * - * \param A Argument of matrix exponential + * \param[in] A Argument of matrix exponential */ void pade9(const MatrixType &A); @@ -145,7 +103,7 @@ class MatrixExponential { * After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé * approximant of \f$ \exp(A) \f$ around \f$ A = 0 \f$. * - * \param A Argument of matrix exponential + * \param[in] A Argument of matrix exponential */ void pade13(const MatrixType &A); @@ -171,10 +129,10 @@ class MatrixExponential { void computeUV(float); typedef typename ei_traits::Scalar Scalar; - typedef typename NumTraits::Scalar>::Real RealScalar; + typedef typename NumTraits::Real RealScalar; - /** \brief Pointer to matrix whose exponential is to be computed. */ - const MatrixType* m_M; + /** \brief Reference to matrix whose exponential is to be computed. */ + const MatrixType& m_M; /** \brief Even-degree terms in numerator of Padé approximant. */ MatrixType m_U; @@ -199,8 +157,8 @@ class MatrixExponential { }; template -MatrixExponential::MatrixExponential(const MatrixType &M, MatrixType *result) : - m_M(&M), +MatrixExponential::MatrixExponential(const MatrixType &M) : + m_M(M), m_U(M.rows(),M.cols()), m_V(M.rows(),M.cols()), m_tmp1(M.rows(),M.cols()), @@ -208,13 +166,20 @@ MatrixExponential::MatrixExponential(const MatrixType &M, MatrixType m_Id(MatrixType::Identity(M.rows(), M.cols())), m_squarings(0), m_l1norm(static_cast(M.cwiseAbs().colwise().sum().maxCoeff())) +{ + /* empty body */ +} + +template +template +void MatrixExponential::compute(ResultType &result) { computeUV(RealScalar()); m_tmp1 = m_U + m_V; // numerator of Pade approximant m_tmp2 = -m_U + m_V; // denominator of Pade approximant - *result = m_tmp2.partialPivLu().solve(m_tmp1); + result = m_tmp2.partialPivLu().solve(m_tmp1); for (int i=0; i @@ -286,13 +251,13 @@ template void MatrixExponential::computeUV(float) { if (m_l1norm < 4.258730016922831e-001) { - pade3(*m_M); + pade3(m_M); } else if (m_l1norm < 1.880152677804762e+000) { - pade5(*m_M); + pade5(m_M); } else { const float maxnorm = 3.925724783138660f; m_squarings = std::max(0, (int)ceil(log2(m_l1norm / maxnorm))); - MatrixType A = *m_M / std::pow(Scalar(2), Scalar(static_cast(m_squarings))); + MatrixType A = m_M / std::pow(Scalar(2), Scalar(static_cast(m_squarings))); pade7(A); } } @@ -301,27 +266,126 @@ template void MatrixExponential::computeUV(double) { if (m_l1norm < 1.495585217958292e-002) { - pade3(*m_M); + pade3(m_M); } else if (m_l1norm < 2.539398330063230e-001) { - pade5(*m_M); + pade5(m_M); } else if (m_l1norm < 9.504178996162932e-001) { - pade7(*m_M); + pade7(m_M); } else if (m_l1norm < 2.097847961257068e+000) { - pade9(*m_M); + pade9(m_M); } else { const double maxnorm = 5.371920351148152; m_squarings = std::max(0, (int)ceil(log2(m_l1norm / maxnorm))); - MatrixType A = *m_M / std::pow(Scalar(2), Scalar(m_squarings)); + MatrixType A = m_M / std::pow(Scalar(2), Scalar(m_squarings)); pade13(A); } } +/** \ingroup MatrixFunctions_Module + * + * \brief Proxy for the matrix exponential of some matrix (expression). + * + * \tparam Derived Type of the argument to the matrix exponential. + * + * This class holds the argument to the matrix exponential until it + * is assigned or evaluated for some other reason (so the argument + * should not be changed in the meantime). It is the return type of + * ei_matrix_exponential() and most of the time this is the only way + * it is used. + */ +template struct MatrixExponentialReturnValue +: public ReturnByValue > +{ + public: + /** \brief Constructor. + * + * \param[in] src %Matrix (expression) forming the argument of the + * matrix exponential. + */ + MatrixExponentialReturnValue(const Derived& src) : m_src(src) { } + + /** \brief Compute the matrix exponential. + * + * \param[out] result the matrix exponential of \p src in the + * constructor. + */ + template + inline void evalTo(ResultType& result) const + { + const typename ei_eval::type srcEvaluated = m_src.eval(); + MatrixExponential me(srcEvaluated); + me.compute(result); + } + + int rows() const { return m_src.rows(); } + int cols() const { return m_src.cols(); } + + protected: + const Derived& m_src; +}; + +template +struct ei_traits > +{ + typedef typename Derived::PlainMatrixType ReturnMatrixType; +}; + +/** \ingroup MatrixFunctions_Module + * + * \brief Compute the matrix exponential. + * + * \param[in] M matrix whose exponential is to be computed. + * \returns expression representing the matrix exponential of \p M. + * + * The matrix exponential of \f$ M \f$ is defined by + * \f[ \exp(M) = \sum_{k=0}^\infty \frac{M^k}{k!}. \f] + * The matrix exponential can be used to solve linear ordinary + * differential equations: the solution of \f$ y' = My \f$ with the + * initial condition \f$ y(0) = y_0 \f$ is given by + * \f$ y(t) = \exp(M) y_0 \f$. + * + * The cost of the computation is approximately \f$ 20 n^3 \f$ for + * matrices of size \f$ n \f$. The number 20 depends weakly on the + * norm of the matrix. + * + * The matrix exponential is computed using the scaling-and-squaring + * method combined with Padé approximation. The matrix is first + * rescaled, then the exponential of the reduced matrix is computed + * approximant, and then the rescaling is undone by repeated + * squaring. The degree of the Padé approximant is chosen such + * that the approximation error is less than the round-off + * error. However, errors may accumulate during the squaring phase. + * + * Details of the algorithm can be found in: Nicholas J. Higham, "The + * scaling and squaring method for the matrix exponential revisited," + * SIAM J. %Matrix Anal. Applic., 26:1179–1193, + * 2005. + * + * Example: The following program checks that + * \f[ \exp \left[ \begin{array}{ccc} + * 0 & \frac14\pi & 0 \\ + * -\frac14\pi & 0 & 0 \\ + * 0 & 0 & 0 + * \end{array} \right] = \left[ \begin{array}{ccc} + * \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\ + * \frac12\sqrt2 & \frac12\sqrt2 & 0 \\ + * 0 & 0 & 1 + * \end{array} \right]. \f] + * This corresponds to a rotation of \f$ \frac14\pi \f$ radians around + * the z-axis. + * + * \include MatrixExponential.cpp + * Output: \verbinclude MatrixExponential.out + * + * \note \p M has to be a matrix of \c float, \c double, + * \c complex or \c complex . + */ template -EIGEN_STRONG_INLINE void ei_matrix_exponential(const MatrixBase &M, - typename MatrixBase::PlainMatrixType* result) +MatrixExponentialReturnValue +ei_matrix_exponential(const MatrixBase &M) { ei_assert(M.rows() == M.cols()); - MatrixExponential::PlainMatrixType>(M, result); + return MatrixExponentialReturnValue(M.derived()); } #endif // EIGEN_MATRIX_EXPONENTIAL diff --git a/unsupported/doc/examples/MatrixExponential.cpp b/unsupported/doc/examples/MatrixExponential.cpp index 7dc2396df..801ee4d01 100644 --- a/unsupported/doc/examples/MatrixExponential.cpp +++ b/unsupported/doc/examples/MatrixExponential.cpp @@ -12,7 +12,6 @@ int main() 0, 0, 0; std::cout << "The matrix A is:\n" << A << "\n\n"; - MatrixXd B; - ei_matrix_exponential(A, &B); + MatrixXd B = ei_matrix_exponential(A); std::cout << "The matrix exponential of A is:\n" << B << "\n\n"; } diff --git a/unsupported/test/matrix_exponential.cpp b/unsupported/test/matrix_exponential.cpp index a5b40adde..6150439c5 100644 --- a/unsupported/test/matrix_exponential.cpp +++ b/unsupported/test/matrix_exponential.cpp @@ -61,7 +61,7 @@ void test2dRotation(double tol) std::cout << "test2dRotation: i = " << i << " error funm = " << relerr(C, B); VERIFY(C.isApprox(B, static_cast(tol))); - ei_matrix_exponential(angle*A, &C); + C = ei_matrix_exponential(angle*A); std::cout << " error expm = " << relerr(C, B) << "\n"; VERIFY(C.isApprox(B, static_cast(tol))); } @@ -86,7 +86,7 @@ void test2dHyperbolicRotation(double tol) std::cout << "test2dHyperbolicRotation: i = " << i << " error funm = " << relerr(C, B); VERIFY(C.isApprox(B, static_cast(tol))); - ei_matrix_exponential(A, &C); + C = ei_matrix_exponential(A); std::cout << " error expm = " << relerr(C, B) << "\n"; VERIFY(C.isApprox(B, static_cast(tol))); } @@ -110,7 +110,7 @@ void testPascal(double tol) std::cout << "testPascal: size = " << size << " error funm = " << relerr(C, B); VERIFY(C.isApprox(B, static_cast(tol))); - ei_matrix_exponential(A, &C); + C = ei_matrix_exponential(A); std::cout << " error expm = " << relerr(C, B) << "\n"; VERIFY(C.isApprox(B, static_cast(tol))); } @@ -137,10 +137,9 @@ void randomTest(const MatrixType& m, double tol) std::cout << "randomTest: error funm = " << relerr(identity, m2 * m3); VERIFY(identity.isApprox(m2 * m3, static_cast(tol))); - ei_matrix_exponential(m1, &m2); - ei_matrix_exponential(-m1, &m3); - std::cout << " error expm = " << relerr(identity, m2 * m3) << "\n"; - VERIFY(identity.isApprox(m2 * m3, static_cast(tol))); + m2 = ei_matrix_exponential(m1) * ei_matrix_exponential(-m1); + std::cout << " error expm = " << relerr(identity, m2) << "\n"; + VERIFY(identity.isApprox(m2, static_cast(tol))); } } diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index de63937ad..25134f21d 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -100,10 +100,9 @@ void testMatrixExponential(const MatrixType& A) typedef std::complex ComplexScalar; for (int i = 0; i < g_repeat; i++) { - MatrixType expA1, expA2; - ei_matrix_exponential(A, &expA1); - ei_matrix_function(A, StdStemFunctions::exp, &expA2); - VERIFY_IS_APPROX(expA1, expA2); + MatrixType expA; + ei_matrix_function(A, StdStemFunctions::exp, &expA); + VERIFY_IS_APPROX(ei_matrix_exponential(A), expA); } } @@ -111,10 +110,10 @@ template void testHyperbolicFunctions(const MatrixType& A) { for (int i = 0; i < g_repeat; i++) { - MatrixType sinhA, coshA, expA; + MatrixType sinhA, coshA; ei_matrix_sinh(A, &sinhA); ei_matrix_cosh(A, &coshA); - ei_matrix_exponential(A, &expA); + MatrixType expA = ei_matrix_exponential(A); VERIFY_IS_APPROX(sinhA, (expA - expA.inverse())/2); VERIFY_IS_APPROX(coshA, (expA + expA.inverse())/2); } @@ -136,8 +135,7 @@ void testGonioFunctions(const MatrixType& A) for (int i = 0; i < g_repeat; i++) { ComplexMatrix Ac = A.template cast(); - ComplexMatrix exp_iA; - ei_matrix_exponential(imagUnit * Ac, &exp_iA); + ComplexMatrix exp_iA = ei_matrix_exponential(imagUnit * Ac); MatrixType sinA; ei_matrix_sin(A, &sinA); From 319bf3130b1257856408b0481401f7c353f97470 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 16 Feb 2010 16:43:11 +0000 Subject: [PATCH 109/109] Use ReturnByValue to return result of ei_matrix_function(), ... --- .../src/MatrixFunctions/MatrixExponential.h | 2 +- .../src/MatrixFunctions/MatrixFunction.h | 323 +++++++++++------- unsupported/doc/examples/MatrixFunction.cpp | 7 +- unsupported/doc/examples/MatrixSine.cpp | 6 +- unsupported/doc/examples/MatrixSinh.cpp | 6 +- unsupported/test/matrix_function.cpp | 16 +- 6 files changed, 216 insertions(+), 144 deletions(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 147e21bc1..39c23cdc5 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Jitse Niesen +// Copyright (C) 2009, 2010 Jitse Niesen // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h index fbc55507f..d63bcbce9 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h @@ -28,66 +28,11 @@ #include "StemFunction.h" #include "MatrixFunctionAtomic.h" + /** \ingroup MatrixFunctions_Module - * - * \brief Compute a matrix function. - * - * \param[in] M argument of matrix function, should be a square matrix. - * \param[in] f an entire function; \c f(x,n) should compute the n-th derivative of f at x. - * \param[out] result pointer to the matrix in which to store the result, \f$ f(M) \f$. - * - * This function computes \f$ f(A) \f$ and stores the result in the - * matrix pointed to by \p result. - * - * Suppose that \p M is a matrix whose entries have type \c Scalar. - * Then, the second argument, \p f, should be a function with prototype - * \code - * ComplexScalar f(ComplexScalar, int) - * \endcode - * where \c ComplexScalar = \c std::complex if \c Scalar is - * real (e.g., \c float or \c double) and \c ComplexScalar = - * \c Scalar if \c Scalar is complex. The return value of \c f(x,n) - * should be \f$ f^{(n)}(x) \f$, the n-th derivative of f at x. - * - * This routine uses the algorithm described in: - * Philip Davies and Nicholas J. Higham, - * "A Schur-Parlett algorithm for computing matrix functions", - * SIAM J. %Matrix Anal. Applic., 25:464–485, 2003. - * - * The actual work is done by the MatrixFunction class. - * - * Example: The following program checks that - * \f[ \exp \left[ \begin{array}{ccc} - * 0 & \frac14\pi & 0 \\ - * -\frac14\pi & 0 & 0 \\ - * 0 & 0 & 0 - * \end{array} \right] = \left[ \begin{array}{ccc} - * \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\ - * \frac12\sqrt2 & \frac12\sqrt2 & 0 \\ - * 0 & 0 & 1 - * \end{array} \right]. \f] - * This corresponds to a rotation of \f$ \frac14\pi \f$ radians around - * the z-axis. This is the same example as used in the documentation - * of ei_matrix_exponential(). - * - * \include MatrixFunction.cpp - * Output: \verbinclude MatrixFunction.out - * - * Note that the function \c expfn is defined for complex numbers - * \c x, even though the matrix \c A is over the reals. Instead of - * \c expfn, we could also have used StdStemFunctions::exp: - * \code - * ei_matrix_function(A, StdStemFunctions >::exp, &B); - * \endcode - */ -template -EIGEN_STRONG_INLINE void ei_matrix_function(const MatrixBase& M, - typename ei_stem_function::Scalar>::type f, - typename MatrixBase::PlainMatrixType* result); - - -/** \ingroup MatrixFunctions_Module - * \brief Helper class for computing matrix functions. + * \brief Class for computing matrix exponentials. + * \tparam MatrixType type of the argument of the matrix function, + * expected to be an instantiation of the Matrix class template. */ template ::Scalar>::IsComplex> class MatrixFunction @@ -99,18 +44,26 @@ class MatrixFunction public: - /** \brief Constructor. Computes matrix function. + /** \brief Constructor. * * \param[in] A argument of matrix function, should be a square matrix. * \param[in] f an entire function; \c f(x,n) should compute the n-th derivative of f at x. - * \param[out] result pointer to the matrix in which to store the result, \f$ f(A) \f$. * - * This function computes \f$ f(A) \f$ and stores the result in - * the matrix pointed to by \p result. - * - * See ei_matrix_function() for details. + * The class stores a reference to \p A, so it should not be + * changed (or destroyed) before compute() is called. */ - MatrixFunction(const MatrixType& A, StemFunction f, MatrixType* result); + MatrixFunction(const MatrixType& A, StemFunction f); + + /** \brief Compute the matrix function. + * + * \param[out] result the function \p f applied to \p A, as + * specified in the constructor. + * + * See ei_matrix_function() for details on how this computation + * is implemented. + */ + template + void compute(ResultType &result); }; @@ -136,23 +89,36 @@ class MatrixFunction public: - /** \brief Constructor. Computes matrix function. + /** \brief Constructor. * * \param[in] A argument of matrix function, should be a square matrix. * \param[in] f an entire function; \c f(x,n) should compute the n-th derivative of f at x. - * \param[out] result pointer to the matrix in which to store the result, \f$ f(A) \f$. + */ + MatrixFunction(const MatrixType& A, StemFunction f) : m_A(A), m_f(f) { } + + /** \brief Compute the matrix function. + * + * \param[out] result the function \p f applied to \p A, as + * specified in the constructor. * * This function converts the real matrix \c A to a complex matrix, * uses MatrixFunction and then converts the result back to * a real matrix. */ - MatrixFunction(const MatrixType& A, StemFunction f, MatrixType* result) + template + void compute(ResultType& result) { - ComplexMatrix CA = A.template cast(); + ComplexMatrix CA = m_A.template cast(); ComplexMatrix Cresult; - MatrixFunction(CA, f, &Cresult); - *result = Cresult.real(); + MatrixFunction mf(CA, m_f); + mf.compute(Cresult); + result = Cresult.real(); } + + private: + + const MatrixType& m_A; /**< \brief Reference to argument of matrix function. */ + StemFunction *m_f; /**< \brief Stem function for matrix function under consideration */ }; @@ -179,17 +145,12 @@ class MatrixFunction public: - /** \brief Constructor. Computes matrix function. - * - * \param[in] A argument of matrix function, should be a square matrix. - * \param[in] f an entire function; \c f(x,n) should compute the n-th derivative of f at x. - * \param[out] result pointer to the matrix in which to store the result, \f$ f(A) \f$. - */ - MatrixFunction(const MatrixType& A, StemFunction f, MatrixType* result); + MatrixFunction(const MatrixType& A, StemFunction f); + template void compute(ResultType& result); private: - void computeSchurDecomposition(const MatrixType& A); + void computeSchurDecomposition(); void partitionEigenvalues(); typename ListOfClusters::iterator findCluster(Scalar key); void computeClusterSize(); @@ -202,6 +163,7 @@ class MatrixFunction void computeOffDiagonal(); DynMatrixType solveTriangularSylvester(const DynMatrixType& A, const DynMatrixType& B, const DynMatrixType& C); + const MatrixType& m_A; /**< \brief Reference to argument of matrix function. */ StemFunction *m_f; /**< \brief Stem function for matrix function under consideration */ MatrixType m_T; /**< \brief Triangular part of Schur decomposition */ MatrixType m_U; /**< \brief Unitary part of Schur decomposition */ @@ -221,11 +183,28 @@ class MatrixFunction static const RealScalar separation() { return static_cast(0.01); } }; +/** \brief Constructor. + * + * \param[in] A argument of matrix function, should be a square matrix. + * \param[in] f an entire function; \c f(x,n) should compute the n-th derivative of f at x. + */ template -MatrixFunction::MatrixFunction(const MatrixType& A, StemFunction f, MatrixType* result) : - m_f(f) +MatrixFunction::MatrixFunction(const MatrixType& A, StemFunction f) : + m_A(A), m_f(f) { - computeSchurDecomposition(A); + /* empty body */ +} + +/** \brief Compute the matrix function. + * + * \param[out] result the function \p f applied to \p A, as + * specified in the constructor. + */ +template +template +void MatrixFunction::compute(ResultType& result) +{ + computeSchurDecomposition(); partitionEigenvalues(); computeClusterSize(); computeBlockStart(); @@ -233,14 +212,14 @@ MatrixFunction::MatrixFunction(const MatrixType& A, StemFunction f permuteSchur(); computeBlockAtomic(); computeOffDiagonal(); - *result = m_U * m_fT * m_U.adjoint(); + result = m_U * m_fT * m_U.adjoint(); } -/** \brief Store the Schur decomposition of \p A in #m_T and #m_U */ +/** \brief Store the Schur decomposition of #m_A in #m_T and #m_U */ template -void MatrixFunction::computeSchurDecomposition(const MatrixType& A) +void MatrixFunction::computeSchurDecomposition() { - const ComplexSchur schurOfA(A); + const ComplexSchur schurOfA(m_A); m_T = schurOfA.matrixT(); m_U = schurOfA.matrixU(); } @@ -498,23 +477,129 @@ typename MatrixFunction::DynMatrixType MatrixFunction class MatrixFunctionReturnValue +: public ReturnByValue > +{ + private: + typedef typename ei_traits::Scalar Scalar; + typedef typename ei_stem_function::type StemFunction; + + public: + + /** \brief Constructor. + * + * \param[in] A %Matrix (expression) forming the argument of the + * matrix function. + * \param[in] f Stem function for matrix function under consideration. + */ + MatrixFunctionReturnValue(const Derived& A, StemFunction f) : m_A(A), m_f(f) { } + + /** \brief Compute the matrix function. + * + * \param[out] result \p f applied to \p A, where \p f and \p A + * are as in the constructor. + */ + template + inline void evalTo(ResultType& result) const + { + const typename ei_eval::type Aevaluated = m_A.eval(); + MatrixFunction mf(Aevaluated, m_f); + mf.compute(result); + } + + int rows() const { return m_A.rows(); } + int cols() const { return m_A.cols(); } + + private: + const Derived& m_A; + StemFunction *m_f; +}; + +template +struct ei_traits > +{ + typedef typename Derived::PlainMatrixType ReturnMatrixType; +}; + + +/** \ingroup MatrixFunctions_Module + * + * \brief Compute a matrix function. + * + * \param[in] M argument of matrix function, should be a square matrix. + * \param[in] f an entire function; \c f(x,n) should compute the n-th + * derivative of f at x. + * \returns expression representing \p f applied to \p M. + * + * Suppose that \p M is a matrix whose entries have type \c Scalar. + * Then, the second argument, \p f, should be a function with prototype + * \code + * ComplexScalar f(ComplexScalar, int) + * \endcode + * where \c ComplexScalar = \c std::complex if \c Scalar is + * real (e.g., \c float or \c double) and \c ComplexScalar = + * \c Scalar if \c Scalar is complex. The return value of \c f(x,n) + * should be \f$ f^{(n)}(x) \f$, the n-th derivative of f at x. + * + * This routine uses the algorithm described in: + * Philip Davies and Nicholas J. Higham, + * "A Schur-Parlett algorithm for computing matrix functions", + * SIAM J. %Matrix Anal. Applic., 25:464–485, 2003. + * + * The actual work is done by the MatrixFunction class. + * + * Example: The following program checks that + * \f[ \exp \left[ \begin{array}{ccc} + * 0 & \frac14\pi & 0 \\ + * -\frac14\pi & 0 & 0 \\ + * 0 & 0 & 0 + * \end{array} \right] = \left[ \begin{array}{ccc} + * \frac12\sqrt2 & -\frac12\sqrt2 & 0 \\ + * \frac12\sqrt2 & \frac12\sqrt2 & 0 \\ + * 0 & 0 & 1 + * \end{array} \right]. \f] + * This corresponds to a rotation of \f$ \frac14\pi \f$ radians around + * the z-axis. This is the same example as used in the documentation + * of ei_matrix_exponential(). + * + * \include MatrixFunction.cpp + * Output: \verbinclude MatrixFunction.out + * + * Note that the function \c expfn is defined for complex numbers + * \c x, even though the matrix \c A is over the reals. Instead of + * \c expfn, we could also have used StdStemFunctions::exp: + * \code + * ei_matrix_function(A, StdStemFunctions >::exp, &B); + * \endcode + */ template -EIGEN_STRONG_INLINE void ei_matrix_function(const MatrixBase& M, - typename ei_stem_function::Scalar>::type f, - typename MatrixBase::PlainMatrixType* result) +MatrixFunctionReturnValue +ei_matrix_function(const MatrixBase &M, + typename ei_stem_function::Scalar>::type f) { ei_assert(M.rows() == M.cols()); - typedef typename MatrixBase::PlainMatrixType PlainMatrixType; - MatrixFunction(M, f, result); + return MatrixFunctionReturnValue(M.derived(), f); } /** \ingroup MatrixFunctions_Module * * \brief Compute the matrix sine. * - * \param[in] M a square matrix. - * \param[out] result pointer to matrix in which to store the result, \f$ \sin(M) \f$ + * \param[in] M a square matrix. + * \returns expression representing \f$ \sin(M) \f$. * * This function calls ei_matrix_function() with StdStemFunctions::sin(). * @@ -522,44 +607,42 @@ EIGEN_STRONG_INLINE void ei_matrix_function(const MatrixBase& M, * Output: \verbinclude MatrixSine.out */ template -EIGEN_STRONG_INLINE void ei_matrix_sin(const MatrixBase& M, - typename MatrixBase::PlainMatrixType* result) +MatrixFunctionReturnValue +ei_matrix_sin(const MatrixBase& M) { ei_assert(M.rows() == M.cols()); - typedef typename MatrixBase::PlainMatrixType PlainMatrixType; - typedef typename ei_traits::Scalar Scalar; + typedef typename ei_traits::Scalar Scalar; typedef typename ei_stem_function::ComplexScalar ComplexScalar; - MatrixFunction(M, StdStemFunctions::sin, result); + return MatrixFunctionReturnValue(M.derived(), StdStemFunctions::sin); } /** \ingroup MatrixFunctions_Module * * \brief Compute the matrix cosine. * - * \param[in] M a square matrix. - * \param[out] result pointer to matrix in which to store the result, \f$ \cos(M) \f$ + * \param[in] M a square matrix. + * \returns expression representing \f$ \cos(M) \f$. * * This function calls ei_matrix_function() with StdStemFunctions::cos(). * * \sa ei_matrix_sin() for an example. */ template -EIGEN_STRONG_INLINE void ei_matrix_cos(const MatrixBase& M, - typename MatrixBase::PlainMatrixType* result) +MatrixFunctionReturnValue +ei_matrix_cos(const MatrixBase& M) { ei_assert(M.rows() == M.cols()); - typedef typename MatrixBase::PlainMatrixType PlainMatrixType; - typedef typename ei_traits::Scalar Scalar; + typedef typename ei_traits::Scalar Scalar; typedef typename ei_stem_function::ComplexScalar ComplexScalar; - MatrixFunction(M, StdStemFunctions::cos, result); + return MatrixFunctionReturnValue(M.derived(), StdStemFunctions::cos); } /** \ingroup MatrixFunctions_Module * * \brief Compute the matrix hyperbolic sine. * - * \param[in] M a square matrix. - * \param[out] result pointer to matrix in which to store the result, \f$ \sinh(M) \f$ + * \param[in] M a square matrix. + * \returns expression representing \f$ \sinh(M) \f$ * * This function calls ei_matrix_function() with StdStemFunctions::sinh(). * @@ -567,36 +650,34 @@ EIGEN_STRONG_INLINE void ei_matrix_cos(const MatrixBase& M, * Output: \verbinclude MatrixSinh.out */ template -EIGEN_STRONG_INLINE void ei_matrix_sinh(const MatrixBase& M, - typename MatrixBase::PlainMatrixType* result) +MatrixFunctionReturnValue +ei_matrix_sinh(const MatrixBase& M) { ei_assert(M.rows() == M.cols()); - typedef typename MatrixBase::PlainMatrixType PlainMatrixType; - typedef typename ei_traits::Scalar Scalar; + typedef typename ei_traits::Scalar Scalar; typedef typename ei_stem_function::ComplexScalar ComplexScalar; - MatrixFunction(M, StdStemFunctions::sinh, result); + return MatrixFunctionReturnValue(M.derived(), StdStemFunctions::sinh); } /** \ingroup MatrixFunctions_Module * - * \brief Compute the matrix hyberpolic cosine. + * \brief Compute the matrix hyberbolic cosine. * - * \param[in] M a square matrix. - * \param[out] result pointer to matrix in which to store the result, \f$ \cosh(M) \f$ + * \param[in] M a square matrix. + * \returns expression representing \f$ \cosh(M) \f$ * * This function calls ei_matrix_function() with StdStemFunctions::cosh(). * * \sa ei_matrix_sinh() for an example. */ template -EIGEN_STRONG_INLINE void ei_matrix_cosh(const MatrixBase& M, - typename MatrixBase::PlainMatrixType* result) +MatrixFunctionReturnValue +ei_matrix_cosh(const MatrixBase& M) { ei_assert(M.rows() == M.cols()); - typedef typename MatrixBase::PlainMatrixType PlainMatrixType; - typedef typename ei_traits::Scalar Scalar; + typedef typename ei_traits::Scalar Scalar; typedef typename ei_stem_function::ComplexScalar ComplexScalar; - MatrixFunction(M, StdStemFunctions::cosh, result); + return MatrixFunctionReturnValue(M.derived(), StdStemFunctions::cosh); } #endif // EIGEN_MATRIX_FUNCTION diff --git a/unsupported/doc/examples/MatrixFunction.cpp b/unsupported/doc/examples/MatrixFunction.cpp index c11cb821b..075fe7361 100644 --- a/unsupported/doc/examples/MatrixFunction.cpp +++ b/unsupported/doc/examples/MatrixFunction.cpp @@ -15,9 +15,8 @@ int main() A << 0, -pi/4, 0, pi/4, 0, 0, 0, 0, 0; - std::cout << "The matrix A is:\n" << A << "\n\n"; - MatrixXd B; - ei_matrix_function(A, expfn, &B); - std::cout << "The matrix exponential of A is:\n" << B << "\n\n"; + std::cout << "The matrix A is:\n" << A << "\n\n"; + std::cout << "The matrix exponential of A is:\n" + << ei_matrix_function(A, expfn) << "\n\n"; } diff --git a/unsupported/doc/examples/MatrixSine.cpp b/unsupported/doc/examples/MatrixSine.cpp index f8780ac92..2bbf99bbb 100644 --- a/unsupported/doc/examples/MatrixSine.cpp +++ b/unsupported/doc/examples/MatrixSine.cpp @@ -7,12 +7,10 @@ int main() MatrixXd A = MatrixXd::Random(3,3); std::cout << "A = \n" << A << "\n\n"; - MatrixXd sinA; - ei_matrix_sin(A, &sinA); + MatrixXd sinA = ei_matrix_sin(A); std::cout << "sin(A) = \n" << sinA << "\n\n"; - MatrixXd cosA; - ei_matrix_cos(A, &cosA); + MatrixXd cosA = ei_matrix_cos(A); std::cout << "cos(A) = \n" << cosA << "\n\n"; // The matrix functions satisfy sin^2(A) + cos^2(A) = I, diff --git a/unsupported/doc/examples/MatrixSinh.cpp b/unsupported/doc/examples/MatrixSinh.cpp index 488d95652..036534dea 100644 --- a/unsupported/doc/examples/MatrixSinh.cpp +++ b/unsupported/doc/examples/MatrixSinh.cpp @@ -7,12 +7,10 @@ int main() MatrixXf A = MatrixXf::Random(3,3); std::cout << "A = \n" << A << "\n\n"; - MatrixXf sinhA; - ei_matrix_sinh(A, &sinhA); + MatrixXf sinhA = ei_matrix_sinh(A); std::cout << "sinh(A) = \n" << sinhA << "\n\n"; - MatrixXf coshA; - ei_matrix_cosh(A, &coshA); + MatrixXf coshA = ei_matrix_cosh(A); std::cout << "cosh(A) = \n" << coshA << "\n\n"; // The matrix functions satisfy cosh^2(A) - sinh^2(A) = I, diff --git a/unsupported/test/matrix_function.cpp b/unsupported/test/matrix_function.cpp index 25134f21d..4ff6d7f1e 100644 --- a/unsupported/test/matrix_function.cpp +++ b/unsupported/test/matrix_function.cpp @@ -100,9 +100,8 @@ void testMatrixExponential(const MatrixType& A) typedef std::complex ComplexScalar; for (int i = 0; i < g_repeat; i++) { - MatrixType expA; - ei_matrix_function(A, StdStemFunctions::exp, &expA); - VERIFY_IS_APPROX(ei_matrix_exponential(A), expA); + VERIFY_IS_APPROX(ei_matrix_exponential(A), + ei_matrix_function(A, StdStemFunctions::exp)); } } @@ -110,9 +109,8 @@ template void testHyperbolicFunctions(const MatrixType& A) { for (int i = 0; i < g_repeat; i++) { - MatrixType sinhA, coshA; - ei_matrix_sinh(A, &sinhA); - ei_matrix_cosh(A, &coshA); + MatrixType sinhA = ei_matrix_sinh(A); + MatrixType coshA = ei_matrix_cosh(A); MatrixType expA = ei_matrix_exponential(A); VERIFY_IS_APPROX(sinhA, (expA - expA.inverse())/2); VERIFY_IS_APPROX(coshA, (expA + expA.inverse())/2); @@ -137,13 +135,11 @@ void testGonioFunctions(const MatrixType& A) ComplexMatrix exp_iA = ei_matrix_exponential(imagUnit * Ac); - MatrixType sinA; - ei_matrix_sin(A, &sinA); + MatrixType sinA = ei_matrix_sin(A); ComplexMatrix sinAc = sinA.template cast(); VERIFY_IS_APPROX(sinAc, (exp_iA - exp_iA.inverse()) / (two*imagUnit)); - MatrixType cosA; - ei_matrix_cos(A, &cosA); + MatrixType cosA = ei_matrix_cos(A); ComplexMatrix cosAc = cosA.template cast(); VERIFY_IS_APPROX(cosAc, (exp_iA + exp_iA.inverse()) / 2); }