From 230f5c3aa91b843cf1864258386e3902ffb6370a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 25 Nov 2013 15:20:31 +0100 Subject: Evaluator: introduce the main Assignment class, add call_assignment to bypass NoAlias and AssumeAliasing, and some bits of cleaning --- Eigen/src/Core/AssignEvaluator.h | 232 ++++++++++----------------------------- Eigen/src/Core/NoAlias.h | 3 +- Eigen/src/Core/Swap.h | 72 ++++++++++++ Eigen/src/Core/util/XprHelper.h | 10 ++ test/evaluators.cpp | 76 ++++++++++++- 5 files changed, 220 insertions(+), 173 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 5b5d29ca9..158dc7842 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -514,7 +514,7 @@ struct dense_assignment_loop }; /*************************************************************************** -* Part 4 : Generic Assignment routine +* Part 4 : Generic dense assignment kernel ***************************************************************************/ // This class generalize the assignment of a coefficient (or packet) from one dense evaluator @@ -617,6 +617,10 @@ protected: DstXprType& m_dstExpr; }; +/*************************************************************************** +* Part 5 : Entry point for dense rectangular assignment +***************************************************************************/ + template void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { @@ -645,195 +649,81 @@ void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src) } /*************************************************************************** -* Part 5 : Entry points +* Part 6 : Generic assignment ***************************************************************************/ -// Based on DenseBase::LazyAssign() -// The following functions are just for testing and they are meant to be moved to operator= and the likes. -template class StorageBase, typename SrcXprType> -EIGEN_STRONG_INLINE -const DstXprType& copy_using_evaluator(const NoAlias& dst, - const EigenBase& src) -{ - return noalias_copy_using_evaluator(dst.expression(), src.derived(), internal::assign_op()); -} +// An evaluator must define its shape. It can be one of the following: +struct DenseShape {}; +struct DiagonalShape {}; +struct BandShape {}; +struct TriangularShape {}; +struct SelfAdjointShape {}; +struct SparseShape {}; -template::AssumeAliasing> -struct AddEvalIfAssumingAliasing; -template -struct AddEvalIfAssumingAliasing -{ - static const XprType& run(const XprType& xpr) - { - return xpr; - } -}; +// Based on the respective shapes of the destination and source, +// the class AssignmentKind determine the kind of assignment mechanism. +// AssignmentKind must define a Kind typedef. +template struct AssignmentKind; -template -struct AddEvalIfAssumingAliasing -{ - static const EvalToTemp run(const XprType& xpr) - { - return EvalToTemp(xpr); - } -}; +// AssignmentKind<.,.>::Kind can be one of the following: + struct Dense2Dense {}; + struct Triangular2Triangular {}; +// struct Diagonal2Diagonal {}; // <=> Dense2Dense + struct Sparse2Dense {}; + struct Sparse2Sparse {}; -template -EIGEN_STRONG_INLINE -const DstXprType& copy_using_evaluator(const EigenBase& dst, const EigenBase& src, const Functor &func) -{ - return noalias_copy_using_evaluator(dst.const_cast_derived(), - AddEvalIfAssumingAliasing::run(src.derived()), - func - ); -} +// This is the main assignment class +template< typename DstXprType, typename SrcXprType, typename Functor, + typename Kind = Dense2Dense,//AssignmentKind< evaluator::Shape , evaluator::Shape >::Kind, + typename Scalar = typename DstXprType::Scalar> +struct Assignment; -// this mimics operator= -template -EIGEN_STRONG_INLINE -const DstXprType& copy_using_evaluator(const EigenBase& dst, const EigenBase& src) -{ - return copy_using_evaluator(dst.const_cast_derived(), src.derived(), internal::assign_op()); -} -template -EIGEN_STRONG_INLINE -const DstXprType& noalias_copy_using_evaluator(const PlainObjectBase& dst, const EigenBase& src, const Functor &func) +// The only purpose of this call_assignment() function is to deal with noalias() / AssumeAliasing. +// Indeed, I (Gael) think that this concept of AssumeAliasing was a mistake, and it makes thing quite complicated. +// So this intermediate function removes everything related to AssumeAliasing such that Assignment +// does not has to bother about these annoying details. + +template +void call_assignment(Dst& dst, const Src& src, const Func& func) { -#ifdef EIGEN_DEBUG_ASSIGN - internal::copy_using_evaluator_traits::debug(); -#endif -#ifdef EIGEN_NO_AUTOMATIC_RESIZING - eigen_assert((dst.size()==0 || (IsVectorAtCompileTime ? (dst.size() == src.size()) - : (dst.rows() == src.rows() && dst.cols() == src.cols()))) - && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); -#else - dst.const_cast_derived().resizeLike(src.derived()); -#endif - call_dense_assignment_loop(dst.const_cast_derived(), src.derived(), func); - return dst.derived(); + typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; + Assignment::run(dst, src, func); } -template -EIGEN_STRONG_INLINE -const DstXprType& noalias_copy_using_evaluator(const EigenBase& dst, const EigenBase& src, const Functor &func) +// by-pass AssumeAliasing +template class StorageBase, typename Src, typename Func> +void call_assignment(const NoAlias& dst, const Src& src, const Func& func) { - call_dense_assignment_loop(dst.const_cast_derived(), src.derived(), func); - return dst.derived(); + Assignment::run(dst.expression(), src, func); } -// Based on DenseBase::swap() -// TODO: Check whether we need to do something special for swapping two -// Arrays or Matrices. (Jitse) - -// Overload default assignPacket behavior for swapping them -template -class swap_kernel : public generic_dense_assignment_kernel > +// Generic Dense to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment { - typedef generic_dense_assignment_kernel > Base; - typedef typename DstEvaluatorTypeT::PacketScalar PacketScalar; - using Base::m_dst; - using Base::m_src; - using Base::m_functor; - -public: - typedef typename Base::Scalar Scalar; - typedef typename Base::Index Index; - typedef typename Base::DstXprType DstXprType; - - swap_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, DstXprType& dstExpr) - : Base(dst, src, swap_assign_op(), dstExpr) - {} - - template - void assignPacket(Index row, Index col) + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { - m_functor.template swapPacket(&m_dst.coeffRef(row,col), &const_cast(m_src).coeffRef(row,col)); - } - - template - void assignPacket(Index index) - { - m_functor.template swapPacket(&m_dst.coeffRef(index), &const_cast(m_src).coeffRef(index)); - } - - // TODO find a simple way not to have to copy/paste this function from generic_dense_assignment_kernel, by simple I mean no CRTP (Gael) - template - void assignPacketByOuterInner(Index outer, Index inner) - { - Index row = Base::rowIndexByOuterInner(outer, inner); - Index col = Base::colIndexByOuterInner(outer, inner); - assignPacket(row, col); - } -}; - -template -void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src) -{ - // TODO there is too much redundancy with call_dense_assignment_loop - - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); - - typedef typename evaluator::type DstEvaluatorType; - typedef typename evaluator::type SrcEvaluatorType; + // TODO check whether this is the right place to perform these checks: + enum{ + SameType = internal::is_same::value + }; - DstEvaluatorType dstEvaluator(dst); - SrcEvaluatorType srcEvaluator(src); + EIGEN_STATIC_ASSERT_LVALUE(DstXprType) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(DstXprType,SrcXprType) + EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - typedef swap_kernel Kernel; - Kernel kernel(dstEvaluator, srcEvaluator, dst.const_cast_derived()); - - dense_assignment_loop::run(kernel); -} - -// Based on MatrixBase::operator+= (in CwiseBinaryOp.h) -template -void add_assign_using_evaluator(const MatrixBase& dst, const MatrixBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), add_assign_op()); -} - -// Based on ArrayBase::operator+= -template -void add_assign_using_evaluator(const ArrayBase& dst, const ArrayBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), add_assign_op()); -} - -// TODO: Add add_assign_using_evaluator for EigenBase ? (Jitse) - -template -void subtract_assign_using_evaluator(const MatrixBase& dst, const MatrixBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), sub_assign_op()); -} - -template -void subtract_assign_using_evaluator(const ArrayBase& dst, const ArrayBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), sub_assign_op()); -} - -template -void multiply_assign_using_evaluator(const ArrayBase& dst, const ArrayBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), mul_assign_op()); -} - -template -void divide_assign_using_evaluator(const ArrayBase& dst, const ArrayBase& src) -{ - typedef typename DstXprType::Scalar Scalar; - copy_using_evaluator(dst.derived(), src.derived(), div_assign_op()); -} - + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + #ifdef EIGEN_DEBUG_ASSIGN + internal::copy_using_evaluator_traits::debug(); + #endif + + call_dense_assignment_loop(dst, src, func); + } +}; } // namespace internal diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 0a1c32743..65117a806 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -30,8 +30,9 @@ namespace Eigen { template class StorageBase> class NoAlias { - typedef typename ExpressionType::Scalar Scalar; public: + typedef typename ExpressionType::Scalar Scalar; + NoAlias(ExpressionType& expression) : m_expression(expression) {} /** Behaves like MatrixBase::lazyAssign(other) diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index d602fba65..8fd94b3c7 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -12,6 +12,8 @@ namespace Eigen { +// #ifndef EIGEN_TEST_EVALUATORS + /** \class SwapWrapper * \ingroup Core_Module * @@ -135,6 +137,76 @@ template class SwapWrapper ExpressionType& m_expression; }; +// #endif + +#ifdef EIGEN_TEST_EVALUATORS + +namespace internal { + +// Overload default assignPacket behavior for swapping them +template +class dense_swap_kernel : public generic_dense_assignment_kernel > +{ + typedef generic_dense_assignment_kernel > Base; + typedef typename DstEvaluatorTypeT::PacketScalar PacketScalar; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; + +public: + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::DstXprType DstXprType; + + dense_swap_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, DstXprType& dstExpr) + : Base(dst, src, swap_assign_op(), dstExpr) + {} + + template + void assignPacket(Index row, Index col) + { + m_functor.template swapPacket(&m_dst.coeffRef(row,col), &const_cast(m_src).coeffRef(row,col)); + } + + template + void assignPacket(Index index) + { + m_functor.template swapPacket(&m_dst.coeffRef(index), &const_cast(m_src).coeffRef(index)); + } + + // TODO find a simple way not to have to copy/paste this function from generic_dense_assignment_kernel, by simple I mean no CRTP (Gael) + template + void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = Base::rowIndexByOuterInner(outer, inner); + Index col = Base::colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } +}; + +template +void call_dense_swap_loop(const DstXprType& dst, const SrcXprType& src) +{ + // TODO there is too much redundancy with call_dense_assignment_loop + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + typedef typename evaluator::type DstEvaluatorType; + typedef typename evaluator::type SrcEvaluatorType; + + DstEvaluatorType dstEvaluator(dst); + SrcEvaluatorType srcEvaluator(src); + + typedef dense_swap_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +} // namespace internal + +#endif + } // end namespace Eigen #endif // EIGEN_SWAP_H diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 195d9e2e1..189928c8f 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -293,6 +293,15 @@ struct transfer_constness >::type type; }; +#ifdef EIGEN_TEST_EVALUATORS + +// When using evaluators, we never evaluate when assembling the expression!! +template::type> struct nested +{ + typedef typename ref_selector::type type; +}; + +#else /** \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 @@ -339,6 +348,7 @@ template::type> str typename ref_selector::type >::type type; }; +#endif // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC diff --git a/test/evaluators.cpp b/test/evaluators.cpp index e3922c1be..3fb0d9896 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -1,7 +1,81 @@ + +#ifndef EIGEN_ENABLE_EVALUATORS #define EIGEN_ENABLE_EVALUATORS +#endif + #include "main.h" -using internal::copy_using_evaluator; +namespace Eigen { + + template + EIGEN_STRONG_INLINE + DstXprType& copy_using_evaluator(const EigenBase &dst, const SrcXprType &src) + { + call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op()); + return dst.const_cast_derived(); + } + + template class StorageBase, typename SrcXprType> + EIGEN_STRONG_INLINE + const DstXprType& copy_using_evaluator(const NoAlias& dst, const SrcXprType &src) + { + call_assignment(dst, src.derived(), internal::assign_op()); + return dst.expression(); + } + + template + EIGEN_STRONG_INLINE + DstXprType& copy_using_evaluator(const PlainObjectBase &dst, const SrcXprType &src) + { + #ifdef EIGEN_NO_AUTOMATIC_RESIZING + eigen_assert((dst.size()==0 || (IsVectorAtCompileTime ? (dst.size() == src.size()) + : (dst.rows() == src.rows() && dst.cols() == src.cols()))) + && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); + #else + dst.const_cast_derived().resizeLike(src.derived()); + #endif + + call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op()); + return dst.const_cast_derived(); + } + + template + void add_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::add_assign_op()); + } + + template + void subtract_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::sub_assign_op()); + } + + template + void multiply_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::mul_assign_op()); + } + + template + void divide_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::div_assign_op()); + } + + template + void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + call_dense_swap_loop(dst.const_cast_derived(), src.const_cast_derived()); + } + +} + + using namespace std; #define VERIFY_IS_APPROX_EVALUATOR(DEST,EXPR) VERIFY_IS_APPROX(copy_using_evaluator(DEST,(EXPR)), (EXPR).eval()); -- cgit v1.2.3 From fc6ecebc69dcd11221233216d70746d495b1f29b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 27 Nov 2013 11:32:07 +0100 Subject: Simplify evaluator of EvalToTemp --- Eigen/src/Core/CoreEvaluators.h | 78 +++++++++++------------------------------ 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 3568cb85f..57960fcf6 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -105,7 +105,14 @@ struct evaluator_impl > RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, ColsAtCompileTime = PlainObjectType::ColsAtCompileTime }; - + + evaluator_impl() + : m_data(0), + m_outerStride(IsVectorAtCompileTime ? 0 + : int(IsRowMajor) ? ColsAtCompileTime + : RowsAtCompileTime) + {} + evaluator_impl(const PlainObjectType& m) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { } @@ -188,6 +195,8 @@ struct evaluator_impl > : evaluator_impl > > { typedef Matrix XprType; + + evaluator_impl() {} evaluator_impl(const XprType& m) : evaluator_impl >(m) @@ -200,6 +209,8 @@ struct evaluator_impl > { typedef Array XprType; + evaluator_impl() {} + evaluator_impl(const XprType& m) : evaluator_impl >(m) { } @@ -246,80 +257,31 @@ class EvalToTemp template struct evaluator_impl > + : public evaluator::type { - typedef EvalToTemp XprType; - typedef typename ArgType::PlainObject PlainObject; + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef typename evaluator::type Base; evaluator_impl(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()), m_resultImpl(m_result) + : m_result(xpr.rows(), xpr.cols()) { + ::new (static_cast(this)) Base(m_result); // TODO we should simply do m_result(xpr.arg()); call_dense_assignment_loop(m_result, xpr.arg()); } // This constructor is used when nesting an EvalTo evaluator in another evaluator evaluator_impl(const ArgType& arg) - : m_result(arg.rows(), arg.cols()), m_resultImpl(m_result) + : m_result(arg.rows(), arg.cols()) { + ::new (static_cast(this)) Base(m_result); // TODO we should simply do m_result(xpr.arg()); call_dense_assignment_loop(m_result, arg); } - typedef typename PlainObject::Index Index; - typedef typename PlainObject::Scalar Scalar; - typedef typename PlainObject::CoeffReturnType CoeffReturnType; - typedef typename PlainObject::PacketScalar PacketScalar; - typedef typename PlainObject::PacketReturnType PacketReturnType; - - // All other functions are forwarded to m_resultImpl - - CoeffReturnType coeff(Index row, Index col) const - { - return m_resultImpl.coeff(row, col); - } - - CoeffReturnType coeff(Index index) const - { - return m_resultImpl.coeff(index); - } - - Scalar& coeffRef(Index row, Index col) - { - return m_resultImpl.coeffRef(row, col); - } - - Scalar& coeffRef(Index index) - { - return m_resultImpl.coeffRef(index); - } - - template - PacketReturnType packet(Index row, Index col) const - { - return m_resultImpl.template packet(row, col); - } - - template - PacketReturnType packet(Index index) const - { - return m_resultImpl.packet(index); - } - - template - void writePacket(Index row, Index col, const PacketScalar& x) - { - m_resultImpl.template writePacket(row, col, x); - } - - template - void writePacket(Index index, const PacketScalar& x) - { - m_resultImpl.template writePacket(index, x); - } - protected: PlainObject m_result; - typename evaluator::nestedType m_resultImpl; }; // -------------------- Transpose -------------------- -- cgit v1.2.3 From cc6dd878ee5a80375c587d018c2ae89fc2216dd1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 27 Nov 2013 17:32:57 +0100 Subject: Refactor dense product evaluators --- Eigen/Core | 5 +- Eigen/src/Core/Product.h | 35 +++-- Eigen/src/Core/ProductEvaluators.h | 220 ++++++++++++++++++++---------- Eigen/src/Core/util/Constants.h | 2 +- Eigen/src/Core/util/ForwardDeclarations.h | 17 ++- 5 files changed, 189 insertions(+), 90 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 468ae0c76..e2c9c69cd 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -316,7 +316,6 @@ using std::ptrdiff_t; #include "src/Core/Product.h" #include "src/Core/CoreEvaluators.h" #include "src/Core/AssignEvaluator.h" -#include "src/Core/ProductEvaluators.h" #endif #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 @@ -382,6 +381,10 @@ using std::ptrdiff_t; #include "src/Core/BandMatrix.h" #include "src/Core/CoreIterators.h" +#ifdef EIGEN_ENABLE_EVALUATORS +#include "src/Core/ProductEvaluators.h" +#endif + #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" #include "src/Core/VectorwiseOp.h" diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 5d3789be7..52586e5c0 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -12,8 +12,7 @@ namespace Eigen { -template class Product; -template class ProductImpl; +template class ProductImpl; /** \class Product * \ingroup Core_Module @@ -24,13 +23,17 @@ template class ProductImpl; * \param Rhs the type of the right-hand side expression * * This class represents an expression of the product of two arbitrary matrices. + * + * The other template parameters are: + * \tparam Option can be DefaultProduct or LazyProduct + * \tparam ProductTag can be InnerProduct, OuterProduct, GemvProduct, GemmProduct. It is used to ease expression manipulations. * */ // Use ProductReturnType to get correct traits, in particular vectorization flags namespace internal { -template -struct traits > +template +struct traits > : traits::Type> { // We want A+B*C to be of type Product and not Product @@ -42,14 +45,15 @@ struct traits > } // end namespace internal -template -class Product : public ProductImpl::StorageKind, - typename internal::traits::StorageKind>::ret> +template +class Product : public ProductImpl::StorageKind, + typename internal::traits::StorageKind>::ret> { public: typedef typename ProductImpl< - Lhs, Rhs, + Lhs, Rhs, Option, ProductTag, typename internal::promote_storage_type::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) @@ -78,13 +82,13 @@ class Product : public ProductImpl -class ProductImpl : public internal::dense_xpr_base >::type +template +class ProductImpl : public internal::dense_xpr_base >::type { typedef Product Derived; public: - typedef typename internal::dense_xpr_base >::type Base; + typedef typename internal::dense_xpr_base >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) }; @@ -102,6 +106,15 @@ prod(const Lhs& lhs, const Rhs& rhs) return Product(lhs,rhs); } +/** \internal used to test the evaluator only + */ +template +const Product +lazyprod(const Lhs& lhs, const Rhs& rhs) +{ + return Product(lhs,rhs); +} + } // end namespace Eigen #endif // EIGEN_PRODUCT_H diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 855914f2e..42dd3c7ac 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -17,94 +17,172 @@ namespace Eigen { namespace internal { -// We can evaluate the product either all at once, like GeneralProduct and its evalTo() function, or -// traverse the matrix coefficient by coefficient, like CoeffBasedProduct. Use the existing logic -// in ProductReturnType to decide. + +// Helper class to perform a dense product with the destination at hand. +// Depending on the sizes of the factors, there are different evaluation strategies +// as controlled by internal::product_type. +template::value> +struct dense_product_impl; -template -struct product_evaluator_dispatcher; -template -struct evaluator_impl > - : product_evaluator_dispatcher, typename ProductReturnType::Type> +// The evaluator for default dense products creates a temporary and call dense_product_impl +template +struct evaluator_impl > + : public evaluator::PlainObject>::type { - typedef Product XprType; - typedef product_evaluator_dispatcher::Type> Base; + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; - evaluator_impl(const XprType& xpr) : Base(xpr) - { } + evaluator_impl(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + dense_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; }; -template -struct product_evaluator_traits_dispatcher; template -struct evaluator_traits > - : product_evaluator_traits_dispatcher, typename ProductReturnType::Type> -{ - static const int AssumeAliasing = 1; +struct dense_product_impl +{ + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } }; -// Case 1: Evaluate all at once -// -// We can view the GeneralProduct class as a part of the product evaluator. -// Four sub-cases: InnerProduct, OuterProduct, GemmProduct and GemvProduct. -// InnerProduct is special because GeneralProduct does not have an evalTo() method in this case. + template -struct product_evaluator_traits_dispatcher, GeneralProduct > +struct dense_product_impl +{ + typedef typename Product::Scalar Scalar; + + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).evalTo(dst); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).addTo(dst); + } + + template + static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).subTo(dst); + } + + template + static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); + } + +}; + + +// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo +template +struct dense_product_impl_base { - static const int HasEvalTo = 0; + typedef typename Product::Scalar Scalar; + + template + static void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } + + template + static void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } + + template + static void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } + }; template -struct product_evaluator_dispatcher, GeneralProduct > - : public evaluator::PlainObject>::type +struct dense_product_impl : dense_product_impl_base > { - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type evaluator_base; + typedef typename Product::Scalar Scalar; + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::conditional::type MatrixType; - // TODO: Computation is too early (?) - product_evaluator_dispatcher(const XprType& xpr) : evaluator_base(m_result) + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - m_result.coeffRef(0,0) = (xpr.lhs().transpose().cwiseProduct(xpr.rhs())).sum(); + internal::gemv_selector::HasUsableDirectAccess) + >::run(GeneralProduct(lhs,rhs), dst, alpha); } - -protected: - PlainObject m_result; }; -// For the other three subcases, simply call the evalTo() method of GeneralProduct -// TODO: GeneralProduct should take evaluators, not expression objects. - -template -struct product_evaluator_traits_dispatcher, GeneralProduct > +template +struct dense_product_impl : dense_product_impl_base > { - static const int HasEvalTo = 1; + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); + } }; -template -struct product_evaluator_dispatcher, GeneralProduct > +template +struct dense_product_impl { - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type evaluator_base; + typedef typename Product::Scalar Scalar; - product_evaluator_dispatcher(const XprType& xpr) : m_xpr(xpr) - { } + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst = lazyprod(lhs,rhs); } - template - void evalTo(DstEvaluatorType /* not used */, DstXprType& dst) const - { - dst.resize(m_xpr.rows(), m_xpr.cols()); - GeneralProduct(m_xpr.lhs(), m_xpr.rhs()).evalTo(dst); - } + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst += lazyprod(lhs,rhs); } + + template + static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst -= lazyprod(lhs,rhs); } -protected: - const XprType& m_xpr; + template + static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { dst += alpha * lazyprod(lhs,rhs); } }; +template +struct dense_product_impl : dense_product_impl {}; + // Case 2: Evaluate coeff by coeff // // This is mostly taken from CoeffBasedProduct.h @@ -117,20 +195,14 @@ struct etor_product_coeff_impl; template struct etor_product_packet_impl; -template -struct product_evaluator_traits_dispatcher, CoeffBasedProduct > +template +struct evaluator_impl > + : evaluator_impl_base > { - static const int HasEvalTo = 0; -}; + typedef Product XprType; + typedef CoeffBasedProduct CoeffBasedProductType; -template -struct product_evaluator_dispatcher, CoeffBasedProduct > - : evaluator_impl_base > -{ - typedef Product XprType; - typedef CoeffBasedProduct CoeffBasedProductType; - - product_evaluator_dispatcher(const XprType& xpr) + evaluator_impl(const XprType& xpr) : m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_innerDim(xpr.lhs().cols()) @@ -150,11 +222,13 @@ struct product_evaluator_dispatcher, CoeffBasedProduct::InnerSize, CoeffReadCost = traits::CoeffReadCost, Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = traits::CanVectorizeInner + CanVectorizeInner = traits::CanVectorizeInner, + Flags = CoeffBasedProductType::Flags }; typedef typename evaluator::type LhsEtorType; typedef typename evaluator::type RhsEtorType; + typedef etor_product_coeff_impl CoeffImpl; @@ -183,8 +257,8 @@ struct product_evaluator_dispatcher, CoeffBasedProduct PacketImpl; + Unroll ? InnerSize-1 : Dynamic, + LhsEtorType, RhsEtorType, PacketScalar, LoadMode> PacketImpl; PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); return res; } @@ -197,6 +271,7 @@ protected: Index m_innerDim; }; + /*************************************************************************** * Normal product .coeff() implementation (with meta-unrolling) ***************************************************************************/ @@ -275,7 +350,6 @@ struct etor_product_coeff_impl::run(row, col, lhs, rhs, innerDim, pres); - etor_product_coeff_impl::run(row, col, lhs, rhs, innerDim, res); res = predux(pres); } }; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 05107fdfe..3178ff06e 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -425,7 +425,7 @@ namespace Architecture /** \internal \ingroup enums * Enum used as template parameter in GeneralProduct. */ -enum { CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; +enum { DefaultProduct=0, CoeffBasedProductMode, LazyCoeffBasedProductMode, LazyProduct, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; /** \internal \ingroup enums * Enum used in experimental parallel implementation. */ diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 0a2144c69..459422524 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -87,11 +87,20 @@ template class CwiseNullaryOp; template class CwiseUnaryOp; template class CwiseUnaryView; template class CwiseBinaryOp; -template class SelfCwiseBinaryOp; +template class SelfCwiseBinaryOp; // TODO deprecated template class ProductBase; -template class Product; -template class GeneralProduct; -template class CoeffBasedProduct; + +namespace internal { + template struct product_tag; +} + +template::ret + > class Product; + +template class GeneralProduct; // TODO deprecated +template class CoeffBasedProduct; // TODO deprecated template class DiagonalBase; template class DiagonalWrapper; -- cgit v1.2.3 From 558427532565bf9c81bd4473591cfc6b552deff2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Nov 2013 13:38:59 +0100 Subject: Remove HasEvalTo and all at once eval mode --- Eigen/src/Core/AssignEvaluator.h | 23 ++--------------------- Eigen/src/Core/CoreEvaluators.h | 22 +--------------------- 2 files changed, 3 insertions(+), 42 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 158dc7842..99ae3f89d 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -32,8 +32,7 @@ public: DstIsAligned = Derived::Flags & AlignedBit, DstHasDirectAccess = Derived::Flags & DirectAccessBit, SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned, - SrcEvalBeforeAssign = (evaluator_traits::HasEvalTo == 1) + JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned }; private: @@ -68,8 +67,7 @@ private: public: enum { - Traversal = int(SrcEvalBeforeAssign) ? int(AllAtOnceTraversal) - : int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(MayLinearize) ? int(LinearTraversal) @@ -496,23 +494,6 @@ struct dense_assignment_loop } }; -/**************************** -*** All-at-once traversal *** -****************************/ - -// TODO: this 'AllAtOnceTraversal' should be dropped or caught earlier (Gael) -// Indeed, what to do with the kernel's functor?? -template -struct dense_assignment_loop -{ - static inline void run(Kernel & kernel) - { - // Evaluate rhs in temporary to prevent aliasing problems in a = a * a; - // TODO: Do not pass the xpr object to evalTo() (Jitse) - kernel.srcEvaluator().evalTo(kernel.dstEvaluator(), kernel.dstExpression()); - } -}; - /*************************************************************************** * Part 4 : Generic dense assignment kernel ***************************************************************************/ diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 57960fcf6..c998c37cb 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -22,10 +22,6 @@ namespace internal { template struct evaluator_traits { - // 1 if evaluator_impl::evalTo() exists - // 0 if evaluator_impl allows coefficient-based access - static const int HasEvalTo = 0; - // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a // temporary; 0 if not. static const int AssumeAliasing = 0; @@ -37,32 +33,16 @@ template class EvalToTemp; // evaluator::type is type of evaluator for T -// evaluator::nestedType is type of evaluator if T is nested inside another evaluator template struct evaluator_impl { }; - -template::HasEvalTo> -struct evaluator_nested_type; - -template -struct evaluator_nested_type -{ - typedef evaluator_impl type; -}; - -template -struct evaluator_nested_type -{ - typedef evaluator_impl > type; -}; template struct evaluator { typedef evaluator_impl type; - typedef typename evaluator_nested_type::type nestedType; + typedef evaluator_impl nestedType; }; // TODO: Think about const-correctness -- cgit v1.2.3 From d331def6cce11fa4635a0b25cfda294805763955 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Nov 2013 16:18:22 +0100 Subject: add definition of product_tag --- Eigen/src/Core/GeneralProduct.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index e3a165ac6..c9ab63782 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -98,6 +98,31 @@ public: #endif }; +template struct product_tag +{ +private: + + typedef typename remove_all::type _Lhs; + typedef typename remove_all::type _Rhs; + enum { + Rows = _Lhs::RowsAtCompileTime, + Cols = _Rhs::ColsAtCompileTime, + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, _Rhs::RowsAtCompileTime) + }; + + enum { + rows_select = Rows==1 ? int(Rows) : int(Large), + cols_select = Cols==1 ? int(Cols) : int(Large), + depth_select = Depth==1 ? int(Depth) : int(Large) + }; + typedef product_type_selector selector; + +public: + enum { + ret = selector::ret + }; + +}; /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. -- cgit v1.2.3 From fb6e32a62fe288aa7236394fc16eb57f3fc40335 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Nov 2013 16:45:47 +0100 Subject: Get rid of evalautor_impl --- Eigen/src/Core/CoreEvaluators.h | 181 +++++++++++++++++++------------------ Eigen/src/Core/ProductEvaluators.h | 13 ++- 2 files changed, 102 insertions(+), 92 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index c998c37cb..c63ff8acd 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -17,33 +17,33 @@ namespace Eigen { namespace internal { -// evaluator_traits contains traits for evaluator_impl +template struct evaluator; -template -struct evaluator_traits +// evaluator_traits contains traits for evaluator + + template +struct evaluator_traits_base { + // TODO check whether these two indirections are really needed. + // Basically, if nobody overwrite type and nestedType, then, they can be dropped + typedef evaluator type; + typedef evaluator nestedType; + // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a // temporary; 0 if not. static const int AssumeAliasing = 0; }; +template +struct evaluator_traits : public evaluator_traits_base +{ +}; + // expression class for evaluating nested expression to a temporary template class EvalToTemp; -// evaluator::type is type of evaluator for T - -template -struct evaluator_impl -{ }; - -template -struct evaluator -{ - typedef evaluator_impl type; - typedef evaluator_impl nestedType; -}; // TODO: Think about const-correctness @@ -56,26 +56,24 @@ struct evaluator // TODO this class does not seem to be necessary anymore template -struct evaluator_impl_base +struct evaluator_base { + typedef typename evaluator_traits::type type; + typedef typename evaluator_traits::nestedType nestedType; + typedef typename ExpressionType::Index Index; // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. typedef traits ExpressionTraits; - - evaluator_impl& derived() - { - return *static_cast*>(this); - } }; // -------------------- Matrix and Array -------------------- // -// evaluator_impl is a common base class for the +// evaluator is a common base class for the // Matrix and Array evaluators. template -struct evaluator_impl > - : evaluator_impl_base +struct evaluator > + : evaluator_base { typedef PlainObjectBase PlainObjectType; @@ -86,14 +84,14 @@ struct evaluator_impl > ColsAtCompileTime = PlainObjectType::ColsAtCompileTime }; - evaluator_impl() + evaluator() : m_data(0), m_outerStride(IsVectorAtCompileTime ? 0 : int(IsRowMajor) ? ColsAtCompileTime : RowsAtCompileTime) {} - evaluator_impl(const PlainObjectType& m) + evaluator(const PlainObjectType& m) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { } @@ -171,28 +169,28 @@ protected: }; template -struct evaluator_impl > - : evaluator_impl > > +struct evaluator > + : evaluator > > { typedef Matrix XprType; - evaluator_impl() {} + evaluator() {} - evaluator_impl(const XprType& m) - : evaluator_impl >(m) + evaluator(const XprType& m) + : evaluator >(m) { } }; template -struct evaluator_impl > - : evaluator_impl > > +struct evaluator > + : evaluator > > { typedef Array XprType; - evaluator_impl() {} + evaluator() {} - evaluator_impl(const XprType& m) - : evaluator_impl >(m) + evaluator(const XprType& m) + : evaluator >(m) { } }; @@ -236,14 +234,17 @@ class EvalToTemp }; template -struct evaluator_impl > +struct evaluator > : public evaluator::type { typedef EvalToTemp XprType; typedef typename ArgType::PlainObject PlainObject; typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; - evaluator_impl(const XprType& xpr) + evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -252,7 +253,7 @@ struct evaluator_impl > } // This constructor is used when nesting an EvalTo evaluator in another evaluator - evaluator_impl(const ArgType& arg) + evaluator(const ArgType& arg) : m_result(arg.rows(), arg.cols()) { ::new (static_cast(this)) Base(m_result); @@ -267,12 +268,12 @@ protected: // -------------------- Transpose -------------------- template -struct evaluator_impl > - : evaluator_impl_base > +struct evaluator > + : evaluator_base > { typedef Transpose XprType; - evaluator_impl(const XprType& t) : m_argImpl(t.nestedExpression()) {} + evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -331,11 +332,12 @@ protected: // -------------------- CwiseNullaryOp -------------------- template -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef CwiseNullaryOp XprType; - evaluator_impl(const XprType& n) + evaluator(const XprType& n) : m_functor(n.functor()) { } @@ -372,11 +374,12 @@ protected: // -------------------- CwiseUnaryOp -------------------- template -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef CwiseUnaryOp XprType; - evaluator_impl(const XprType& op) + evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -415,11 +418,12 @@ protected: // -------------------- CwiseBinaryOp -------------------- template -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef CwiseBinaryOp XprType; - evaluator_impl(const XprType& xpr) + evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -462,12 +466,12 @@ protected: // -------------------- CwiseUnaryView -------------------- template -struct evaluator_impl > - : evaluator_impl_base > +struct evaluator > + : evaluator_base > { typedef CwiseUnaryView XprType; - evaluator_impl(const XprType& op) + evaluator(const XprType& op) : m_unaryOp(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -504,8 +508,8 @@ protected: // -------------------- Map -------------------- template -struct evaluator_impl > - : evaluator_impl_base +struct evaluator > + : evaluator_base { typedef MapBase MapType; typedef Derived XprType; @@ -517,7 +521,7 @@ struct evaluator_impl > typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; - evaluator_impl(const XprType& map) + evaluator(const XprType& map) : m_data(const_cast(map.data())), m_rowStride(map.rowStride()), m_colStride(map.colStride()) @@ -585,13 +589,13 @@ protected: }; template -struct evaluator_impl > - : public evaluator_impl > > +struct evaluator > + : public evaluator > > { typedef Map XprType; - evaluator_impl(const XprType& map) - : evaluator_impl >(map) + evaluator(const XprType& map) + : evaluator >(map) { } }; @@ -601,17 +605,17 @@ template::ret> struct block_evaluator; template -struct evaluator_impl > +struct evaluator > : block_evaluator { typedef Block XprType; typedef block_evaluator block_evaluator_type; - evaluator_impl(const XprType& block) : block_evaluator_type(block) {} + evaluator(const XprType& block) : block_evaluator_type(block) {} }; template struct block_evaluator - : evaluator_impl_base > + : evaluator_base > { typedef Block XprType; @@ -691,12 +695,12 @@ protected: template struct block_evaluator - : evaluator_impl > > + : evaluator > > { typedef Block XprType; block_evaluator(const XprType& block) - : evaluator_impl >(block) + : evaluator >(block) { } }; @@ -704,11 +708,12 @@ struct block_evaluator -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef Select XprType; - evaluator_impl(const XprType& select) + evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), m_thenImpl(select.thenMatrix()), m_elseImpl(select.elseMatrix()) @@ -743,11 +748,12 @@ protected: // -------------------- Replicate -------------------- template -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef Replicate XprType; - evaluator_impl(const XprType& replicate) + evaluator(const XprType& replicate) : m_argImpl(replicate.nestedExpression()), m_rows(replicate.nestedExpression().rows()), m_cols(replicate.nestedExpression().cols()) @@ -797,11 +803,12 @@ protected: // the row() and col() member functions. template< typename ArgType, typename MemberOp, int Direction> -struct evaluator_impl > +struct evaluator > + : evaluator_base > { typedef PartialReduxExpr XprType; - evaluator_impl(const XprType expr) + evaluator(const XprType expr) : m_expr(expr) { } @@ -825,16 +832,16 @@ protected: // -------------------- MatrixWrapper and ArrayWrapper -------------------- // -// evaluator_impl_wrapper_base is a common base class for the +// evaluator_wrapper_base is a common base class for the // MatrixWrapper and ArrayWrapper evaluators. template -struct evaluator_impl_wrapper_base - : evaluator_impl_base +struct evaluator_wrapper_base + : evaluator_base { typedef typename remove_all::type ArgType; - evaluator_impl_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} typedef typename ArgType::Index Index; typedef typename ArgType::Scalar Scalar; @@ -891,24 +898,24 @@ protected: }; template -struct evaluator_impl > - : evaluator_impl_wrapper_base > +struct evaluator > + : evaluator_wrapper_base > { typedef MatrixWrapper XprType; - evaluator_impl(const XprType& wrapper) - : evaluator_impl_wrapper_base >(wrapper.nestedExpression()) + evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; template -struct evaluator_impl > - : evaluator_impl_wrapper_base > +struct evaluator > + : evaluator_wrapper_base > { typedef ArrayWrapper XprType; - evaluator_impl(const XprType& wrapper) - : evaluator_impl_wrapper_base >(wrapper.nestedExpression()) + evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -919,8 +926,8 @@ struct evaluator_impl > template struct reverse_packet_cond; template -struct evaluator_impl > - : evaluator_impl_base > +struct evaluator > + : evaluator_base > { typedef Reverse XprType; typedef typename XprType::Index Index; @@ -943,7 +950,7 @@ struct evaluator_impl > }; typedef internal::reverse_packet_cond reverse_packet; - evaluator_impl(const XprType& reverse) + evaluator(const XprType& reverse) : m_argImpl(reverse.nestedExpression()), m_rows(ReverseRow ? reverse.nestedExpression().rows() : 0), m_cols(ReverseCol ? reverse.nestedExpression().cols() : 0) @@ -1013,12 +1020,12 @@ protected: // -------------------- Diagonal -------------------- template -struct evaluator_impl > - : evaluator_impl_base > +struct evaluator > + : evaluator_base > { typedef Diagonal XprType; - evaluator_impl(const XprType& diagonal) + evaluator(const XprType& diagonal) : m_argImpl(diagonal.nestedExpression()), m_index(diagonal.index()) { } diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 42dd3c7ac..9f5f6eb0c 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -27,14 +27,17 @@ struct dense_product_impl; // The evaluator for default dense products creates a temporary and call dense_product_impl template -struct evaluator_impl > +struct evaluator > : public evaluator::PlainObject>::type { typedef Product XprType; typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; - evaluator_impl(const XprType& xpr) + evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -196,13 +199,13 @@ template -struct evaluator_impl > - : evaluator_impl_base > +struct evaluator > + : evaluator_base > { typedef Product XprType; typedef CoeffBasedProduct CoeffBasedProductType; - evaluator_impl(const XprType& xpr) + evaluator(const XprType& xpr) : m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_innerDim(xpr.lhs().cols()) -- cgit v1.2.3 From c15c65990fc322891b10a6a20db9bc6c127fae26 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Nov 2013 17:50:59 +0100 Subject: First step toward the generalization of evaluators to triangular, sparse and other fancyness. Remove product_tag template parameter to Product. --- Eigen/src/Core/AssignEvaluator.h | 6 ++- Eigen/src/Core/CoreEvaluators.h | 66 +++++++++++++++++++++++++++---- Eigen/src/Core/Product.h | 28 +++++++------ Eigen/src/Core/ProductEvaluators.h | 40 +++++++++++++------ Eigen/src/Core/util/ForwardDeclarations.h | 5 +-- 5 files changed, 109 insertions(+), 36 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 99ae3f89d..2f18cbc95 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -646,7 +646,7 @@ struct SparseShape {}; // Based on the respective shapes of the destination and source, // the class AssignmentKind determine the kind of assignment mechanism. // AssignmentKind must define a Kind typedef. -template struct AssignmentKind; +template struct AssignmentKind; // AssignmentKind<.,.>::Kind can be one of the following: struct Dense2Dense {}; @@ -655,9 +655,11 @@ template struct AssignmentKind; struct Sparse2Dense {}; struct Sparse2Sparse {}; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + // This is the main assignment class template< typename DstXprType, typename SrcXprType, typename Functor, - typename Kind = Dense2Dense,//AssignmentKind< evaluator::Shape , evaluator::Shape >::Kind, + typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, typename Scalar = typename DstXprType::Scalar> struct Assignment; diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index c63ff8acd..9460e675f 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -14,20 +14,70 @@ #define EIGEN_COREEVALUATORS_H namespace Eigen { - + namespace internal { -template struct evaluator; +struct IndexBased {}; +struct IteratorBased {}; + +// This class returns the evaluator kind from the expression storage kind. +// Default assumes index based accessors +template +struct storage_kind_to_evaluator_kind { + typedef IndexBased Kind; +}; + +// TODO to be moved to SparseCore: +/* +template<> +struct storage_kind_to_evaluator_kind { + typedef IteratorBased Kind +}; +*/ + +// This class returns the evaluator shape from the expression storage kind. +// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. +template struct storage_kind_to_shape; + + +template<> +struct storage_kind_to_shape { + typedef Dense Shape; +}; + +// TODO to be moved to SparseCore: +/* +template<> +struct storage_kind_to_shape { + typedef Sparse Shape; +}; +*/ + +template struct evaluator_traits; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct evaluator; + +template< typename T, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename T::Lhs::Scalar, + typename RhsScalar = typename T::Rhs::Scalar> struct binary_evaluator; // evaluator_traits contains traits for evaluator - template +template struct evaluator_traits_base { // TODO check whether these two indirections are really needed. // Basically, if nobody overwrite type and nestedType, then, they can be dropped - typedef evaluator type; - typedef evaluator nestedType; +// typedef evaluator type; +// typedef evaluator nestedType; + + // by default, get evalautor kind and shape from storage + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef typename storage_kind_to_shape::Shape Shape; // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a // temporary; 0 if not. @@ -58,8 +108,10 @@ struct evaluator template struct evaluator_base { - typedef typename evaluator_traits::type type; - typedef typename evaluator_traits::nestedType nestedType; +// typedef typename evaluator_traits::type type; +// typedef typename evaluator_traits::nestedType nestedType; + typedef evaluator type; + typedef evaluator nestedType; typedef typename ExpressionType::Index Index; // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 52586e5c0..970d257a5 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -12,7 +12,7 @@ namespace Eigen { -template class ProductImpl; +template class ProductImpl; /** \class Product * \ingroup Core_Module @@ -26,14 +26,13 @@ template -struct traits > +template +struct traits > : traits::Type> { // We want A+B*C to be of type Product and not Product @@ -45,18 +44,23 @@ struct traits > } // end namespace internal -template -class Product : public ProductImpl::StorageKind, - typename internal::traits::StorageKind>::ret> +template +class Product : public ProductImpl<_Lhs,_Rhs,Option, + typename internal::promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind>::ret> { public: + typedef _Lhs Lhs; + typedef _Rhs Rhs; + typedef typename ProductImpl< - Lhs, Rhs, Option, ProductTag, + Lhs, Rhs, Option, typename internal::promote_storage_type::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; @@ -82,13 +86,13 @@ class Product : public ProductImpl -class ProductImpl : public internal::dense_xpr_base >::type +template +class ProductImpl : public internal::dense_xpr_base >::type { typedef Product Derived; public: - typedef typename internal::dense_xpr_base >::type Base; + typedef typename internal::dense_xpr_base >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) }; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 9f5f6eb0c..e3a893651 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -16,7 +16,28 @@ namespace Eigen { namespace internal { + +// Like more general binary expressions, products need they own evaluator: +template< typename T, + int ProductTag = internal::product_tag::ret, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + typename LhsScalar = typename T::Lhs::Scalar, + typename RhsScalar = typename T::Rhs::Scalar + > struct product_evaluator; + +template +struct evaluator > + : public product_evaluator > +{ + typedef Product XprType; + typedef product_evaluator Base; + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType& xpr) : Base(xpr) {} +}; // Helper class to perform a dense product with the destination at hand. // Depending on the sizes of the factors, there are different evaluation strategies @@ -27,17 +48,14 @@ struct dense_product_impl; // The evaluator for default dense products creates a temporary and call dense_product_impl template -struct evaluator > - : public evaluator::PlainObject>::type +struct product_evaluator, ProductTag, Dense, Dense, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type { - typedef Product XprType; + typedef Product XprType; typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; - - typedef evaluator type; - typedef evaluator nestedType; - evaluator(const XprType& xpr) + product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -199,13 +217,13 @@ template -struct evaluator > - : evaluator_base > +struct product_evaluator, ProductTag, Dense, Dense, typename Lhs::Scalar, typename Rhs::Scalar > + : evaluator_base > { - typedef Product XprType; + typedef Product XprType; typedef CoeffBasedProduct CoeffBasedProductType; - evaluator(const XprType& xpr) + product_evaluator(const XprType& xpr) : m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_innerDim(xpr.lhs().cols()) diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 459422524..776eac587 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -94,10 +94,7 @@ namespace internal { template struct product_tag; } -template::ret - > class Product; +template class Product; template class GeneralProduct; // TODO deprecated template class CoeffBasedProduct; // TODO deprecated -- cgit v1.2.3 From d0261bd26c3900a5e52da3574fc2aeab3392c30b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 30 Nov 2013 10:42:23 +0100 Subject: Fix swap in DenseBase --- Eigen/src/Core/DenseBase.h | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 4794c2f13..50a63c85c 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -387,7 +387,29 @@ template class DenseBase // size types on MSVC. return typename internal::eval::type(derived()); } + +#ifdef EIGEN_TEST_EVALUATORS + /** swaps *this with the expression \a other. + * + */ + template + EIGEN_DEVICE_FUNC + void swap(const DenseBase& other, + int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) + { + swap_using_evaluator(derived(), other.derived()); + } + /** swaps *this with the matrix or array \a other. + * + */ + template + EIGEN_DEVICE_FUNC + void swap(PlainObjectBase& other) + { + swap_using_evaluator(derived(), other.derived()); + } +#else // EIGEN_TEST_EVALUATORS /** swaps *this with the expression \a other. * */ @@ -408,7 +430,7 @@ template class DenseBase { SwapWrapper(derived()).lazyAssign(other.derived()); } - +#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; -- cgit v1.2.3 From 27ca9437a1e191f20724492275bf0b1415eee2d6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 14:05:34 +0100 Subject: Fix usage of Dense versus DenseShape --- Eigen/src/Core/AssignEvaluator.h | 31 ++++++++++++++----------------- Eigen/src/Core/CoreEvaluators.h | 4 ++-- Eigen/src/Core/ProductEvaluators.h | 4 ++-- Eigen/src/Core/util/Constants.h | 12 ++++++++++++ 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 2f18cbc95..2c9f2426b 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -526,6 +526,8 @@ public: Index size() const { return m_dstExpr.size(); } Index innerSize() const { return m_dstExpr.innerSize(); } Index outerSize() const { return m_dstExpr.outerSize(); } + Index rows() const { return m_dstExpr.rows(); } + Index cols() const { return m_dstExpr.cols(); } Index outerStride() const { return m_dstExpr.outerStride(); } // TODO get rid of this one: @@ -534,16 +536,25 @@ public: DstEvaluatorType& dstEvaluator() { return m_dst; } const SrcEvaluatorType& srcEvaluator() const { return m_src; } + /// Assign src(row,col) to dst(row,col) through the assignment functor. void assignCoeff(Index row, Index col) { m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); } + /// This overload by-passes the source expression, i.e., dst(row,col) ?= value + void assignCoeff(Index row, Index col, const Scalar &value) + { + m_functor.assignCoeff(m_dst.coeffRef(row,col), value); + } + + /// \sa assignCoeff(Index,Index) void assignCoeff(Index index) { m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); } + /// \sa assignCoeff(Index,Index) void assignCoeffByOuterInner(Index outer, Index inner) { Index row = rowIndexByOuterInner(outer, inner); @@ -633,29 +644,15 @@ void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src) * Part 6 : Generic assignment ***************************************************************************/ - -// An evaluator must define its shape. It can be one of the following: -struct DenseShape {}; -struct DiagonalShape {}; -struct BandShape {}; -struct TriangularShape {}; -struct SelfAdjointShape {}; -struct SparseShape {}; - - // Based on the respective shapes of the destination and source, // the class AssignmentKind determine the kind of assignment mechanism. // AssignmentKind must define a Kind typedef. template struct AssignmentKind; -// AssignmentKind<.,.>::Kind can be one of the following: - struct Dense2Dense {}; - struct Triangular2Triangular {}; -// struct Diagonal2Diagonal {}; // <=> Dense2Dense - struct Sparse2Dense {}; - struct Sparse2Sparse {}; +// Assignement kind defined in this file: +struct Dense2Dense {}; -template<> struct AssignmentKind { typedef Dense2Dense Kind; }; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; // This is the main assignment class template< typename DstXprType, typename SrcXprType, typename Functor, diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 9460e675f..961b56e55 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -42,14 +42,14 @@ template struct storage_kind_to_shape; template<> struct storage_kind_to_shape { - typedef Dense Shape; + typedef DenseShape Shape; }; // TODO to be moved to SparseCore: /* template<> struct storage_kind_to_shape { - typedef Sparse Shape; + typedef SparseSpape Shape; }; */ diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index e3a893651..51228be5f 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -48,7 +48,7 @@ struct dense_product_impl; // The evaluator for default dense products creates a temporary and call dense_product_impl template -struct product_evaluator, ProductTag, Dense, Dense, typename Lhs::Scalar, typename Rhs::Scalar> +struct product_evaluator, ProductTag, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; @@ -217,7 +217,7 @@ template -struct product_evaluator, ProductTag, Dense, Dense, typename Lhs::Scalar, typename Rhs::Scalar > +struct product_evaluator, ProductTag, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar > : evaluator_base > { typedef Product XprType; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 3178ff06e..14449eb6c 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -440,6 +440,18 @@ struct MatrixXpr {}; /** The type used to identify an array expression */ struct ArrayXpr {}; + +#ifdef EIGEN_ENABLE_EVALUATORS +// An evaluator must define its shape. By default, it can be one of the following: +struct DenseShape { static std::string debugName() { return "DenseShape"; } }; +struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; +struct BandShape { static std::string debugName() { return "BandShape"; } }; +struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; +struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; +struct SparseShape { static std::string debugName() { return "SparseShape"; } }; +#endif + + } // end namespace Eigen #endif // EIGEN_CONSTANTS_H -- cgit v1.2.3 From 626821b0e34a624e8fa8980339b771e155722ace Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 14:06:17 +0100 Subject: Add evaluator/assignment to TriangularView expressions --- Eigen/src/Core/TriangularMatrix.h | 317 +++++++++++++++++++++++++++++++++++++- test/evaluators.cpp | 35 ++++- 2 files changed, 350 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 1d6e34650..96ed9cef9 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -36,7 +36,13 @@ template class TriangularBase : public EigenBase RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret) + /**< This is equal to the number of coefficients, i.e. the number of + * rows times the number of columns, or to \a Dynamic if this is not + * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ }; typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; @@ -408,15 +414,24 @@ template class TriangularView EIGEN_DEVICE_FUNC void swap(TriangularBase const & other) { +// #ifdef EIGEN_TEST_EVALUATORS +// swap_using_evaluator(this->derived(), other.derived()); +// #else TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); +// #endif } + // TODO: this overload is ambiguous and it should be deprecated (Gael) template EIGEN_DEVICE_FUNC void swap(MatrixBase const & other) { +// #ifdef EIGEN_TEST_EVALUATORS +// swap_using_evaluator(this->derived(), other.derived()); +// #else SwapWrapper swaper(const_cast(m_matrix)); TriangularView,Mode>(swaper).lazyAssign(other.derived()); +// #endif } EIGEN_DEVICE_FUNC @@ -895,6 +910,306 @@ bool MatrixBase::isLowerTriangular(const RealScalar& prec) const return true; } + +#ifdef EIGEN_ENABLE_EVALUATORS + +/*************************************************************************** +**************************************************************************** +* Evaluators and Assignment of triangular expressions +*************************************************************************** +***************************************************************************/ + +namespace internal { + + +// TODO currently a triangular expression has the form TriangularView<.,.> +// in the future triangular-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef TriangularShape Shape; + + // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a + // temporary; 0 if not. + static const int AssumeAliasing = 0; +}; + +template +struct evaluator, Kind, typename MatrixType::Scalar> + : evaluator +{ + typedef TriangularView XprType; + typedef evaluator Base; + typedef evaluator type; + evaluator(const XprType &xpr) : Base(xpr.nestedExpression()) {} +}; + +// Additional assignement kinds: +struct Triangular2Triangular {}; +struct Triangular2Dense {}; +struct Dense2Triangular {}; + + +template struct triangular_assignment_loop; + + +template +void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) +{ +#ifdef EIGEN_DEBUG_ASSIGN + // TODO these traits should be computed from information provided by the evaluators + internal::copy_using_evaluator_traits::debug(); +#endif + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + typedef typename evaluator::type DstEvaluatorType; + typedef typename evaluator::type SrcEvaluatorType; + + DstEvaluatorType dstEvaluator(dst); + SrcEvaluatorType srcEvaluator(src); + + typedef generic_dense_assignment_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + enum { + unroll = DstXprType::SizeAtCompileTime != Dynamic + && internal::traits::CoeffReadCost != Dynamic + && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT + }; + + triangular_assignment_loop::run(kernel); +} + +template +void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src) +{ + call_triangular_assignment_loop(dst, src, internal::assign_op()); +} + + +template<> struct AssignmentKind { typedef Triangular2Triangular Kind; }; +template<> struct AssignmentKind { typedef Triangular2Dense Kind; }; +template<> struct AssignmentKind { typedef Dense2Triangular Kind; }; + + +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + eigen_assert(int(DstXprType::Mode) == int(SrcXprType::Mode)); + + call_triangular_assignment_loop(dst, src, func); + } +}; + +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + call_triangular_assignment_loop(dst, src, func); + } +}; + +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + call_triangular_assignment_loop(dst, src, func); + } +}; + + +template +struct triangular_assignment_loop +{ + enum { + col = (UnrollCount-1) / Kernel::RowsAtCompileTime, + row = (UnrollCount-1) % Kernel::RowsAtCompileTime + }; + + typedef typename Kernel::Scalar Scalar; + + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + triangular_assignment_loop::run(kernel); + + // TODO should be a static assert + eigen_assert( Mode == Upper || Mode == Lower + || Mode == StrictlyUpper || Mode == StrictlyLower + || Mode == UnitUpper || Mode == UnitLower); + + if((Mode == Upper && row <= col) + || (Mode == Lower && row >= col) + || (Mode == StrictlyUpper && row < col) + || (Mode == StrictlyLower && row > col) + || (Mode == UnitUpper && row < col) + || (Mode == UnitLower && row > col)) + kernel.assignCoeff(row, col); + else if(ClearOpposite) + { + if((Mode&UnitDiag) && row==col) kernel.assignCoeff(row, col, Scalar(1)); + else kernel.assignCoeff(row, col, Scalar(0)); + } + } +}; + +// prevent buggy user code from causing an infinite recursion +template +struct triangular_assignment_loop +{ + EIGEN_DEVICE_FUNC + static inline void run(Kernel &) {} +}; + +// TODO: merge the following 6 variants into a single one (or max two), +// and perhaps write them using sub-expressions + +// TODO: expreiment with a recursive assignment procedure splitting the current +// triangular part into one rectangular and two triangular parts. + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + Index maxi = (std::min)(j, kernel.rows()-1); + for(Index i = 0; i <= maxi; ++i) + kernel.assignCoeff(i, j); + if (ClearOpposite) + for(Index i = maxi+1; i < kernel.rows(); ++i) + kernel.assignCoeff(i, j, Scalar(0)); + } + } +}; + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + for(Index i = j; i < kernel.rows(); ++i) + kernel.assignCoeff(i, j); + Index maxi = (std::min)(j, kernel.rows()); + if (ClearOpposite) + for(Index i = 0; i < maxi; ++i) + kernel.assignCoeff(i, j, Scalar(0)); + } + } +}; + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + Index maxi = (std::min)(j, kernel.rows()); + for(Index i = 0; i < maxi; ++i) + kernel.assignCoeff(i, j); + if (ClearOpposite) + for(Index i = maxi; i < kernel.rows(); ++i) + kernel.assignCoeff(i, j) = Scalar(0); + } + } +}; + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + for(Index i = j+1; i < kernel.rows(); ++i) + kernel.assignCoeff(i, j); + Index maxi = (std::min)(j, kernel.rows()-1); + if (ClearOpposite) + for(Index i = 0; i <= maxi; ++i) + kernel.assignCoeff(i, j, Scalar(0)); + } + } +}; + +template +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + Index maxi = (std::min)(j, kernel.rows()); + Index i = 0; + for(; i < maxi; ++i) + kernel.assignCoeff(i, j); + + if(i +struct triangular_assignment_loop +{ + typedef typename Kernel::Index Index; + typedef typename Kernel::Scalar Scalar; + EIGEN_DEVICE_FUNC + static inline void run(Kernel &kernel) + { + for(Index j = 0; j < kernel.cols(); ++j) + { + Index maxi = (std::min)(j, kernel.rows()); + Index i = 0; + if (ClearOpposite) + { + for(; i < maxi; ++i) + kernel.assignCoeff(i, j, Scalar(0)); + } + + if(i(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A; + copy_using_evaluator(B.triangularView(), A); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A)"); + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A.triangularView(); + copy_using_evaluator(B.triangularView(), A.triangularView()); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A.triangularView())"); + + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A.triangularView().transpose(); + copy_using_evaluator(B.triangularView(), A.triangularView().transpose()); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A.triangularView().transpose())"); + } } -- cgit v1.2.3 From c6f73370327e2e91a45ac13e7bbb6c7567179e49 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 14:44:13 +0100 Subject: Get rid of call_dense_swap_loop --- Eigen/src/Core/AssignEvaluator.h | 2 +- Eigen/src/Core/Swap.h | 31 +++++++------------------------ test/evaluators.cpp | 9 +++++---- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 2c9f2426b..3babc16ba 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -504,7 +504,7 @@ struct dense_assignment_loop // This abstraction level permits to keep the evaluation loops as simple and as generic as possible. // One can customize the assignment using this generic dense_assignment_kernel with different // functors, or by completely overloading it, by-passing a functor. -template +template class generic_dense_assignment_kernel { protected: diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 8fd94b3c7..117f667f6 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -139,15 +139,16 @@ template class SwapWrapper // #endif -#ifdef EIGEN_TEST_EVALUATORS +#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { // Overload default assignPacket behavior for swapping them template -class dense_swap_kernel : public generic_dense_assignment_kernel > +class generic_dense_assignment_kernel, Specialized> + : public generic_dense_assignment_kernel, BuiltIn> { - typedef generic_dense_assignment_kernel > Base; + typedef generic_dense_assignment_kernel, BuiltIn> Base; typedef typename DstEvaluatorTypeT::PacketScalar PacketScalar; using Base::m_dst; using Base::m_src; @@ -157,9 +158,10 @@ public: typedef typename Base::Scalar Scalar; typedef typename Base::Index Index; typedef typename Base::DstXprType DstXprType; + typedef swap_assign_op Functor; - dense_swap_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, DstXprType& dstExpr) - : Base(dst, src, swap_assign_op(), dstExpr) + generic_dense_assignment_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) {} template @@ -183,25 +185,6 @@ public: assignPacket(row, col); } }; - -template -void call_dense_swap_loop(const DstXprType& dst, const SrcXprType& src) -{ - // TODO there is too much redundancy with call_dense_assignment_loop - - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); - - typedef typename evaluator::type DstEvaluatorType; - typedef typename evaluator::type SrcEvaluatorType; - - DstEvaluatorType dstEvaluator(dst); - SrcEvaluatorType srcEvaluator(src); - - typedef dense_swap_kernel Kernel; - Kernel kernel(dstEvaluator, srcEvaluator, dst.const_cast_derived()); - - dense_assignment_loop::run(kernel); -} } // namespace internal diff --git a/test/evaluators.cpp b/test/evaluators.cpp index 29192d7f9..63f940318 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -74,7 +74,8 @@ namespace Eigen { template void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src) { - call_dense_swap_loop(dst.const_cast_derived(), src.const_cast_derived()); + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.const_cast_derived(), internal::swap_assign_op()); } } @@ -193,7 +194,7 @@ void test_evaluators() VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mX4,m4X), mX4*m4X); VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mXX,mXX), mXX*mXX); } - +#endif { ArrayXXf a(2,3); ArrayXXf b(3,2); @@ -202,7 +203,7 @@ void test_evaluators() // this does not work because Random is eval-before-nested: // copy_using_evaluator(w, Vector2d::Random().transpose()); - + // test CwiseUnaryOp VERIFY_IS_APPROX_EVALUATOR(v2, 3 * v); VERIFY_IS_APPROX_EVALUATOR(w, (3 * v).transpose()); @@ -405,7 +406,7 @@ void test_evaluators() arr_ref.row(1) /= (arr_ref.row(2) + 1); VERIFY_IS_APPROX(arr, arr_ref); } -#endif + { // test triangular shapes MatrixXd A = MatrixXd::Random(6,6), B(6,6), C(6,6); -- cgit v1.2.3 From 8af1ba534669a223ca69136046690eb6d49ff619 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 15:07:45 +0100 Subject: Make swap unit test work with evaluators --- Eigen/Core | 2 +- Eigen/src/Core/DenseBase.h | 4 ++-- Eigen/src/Core/TriangularMatrix.h | 23 +++++++++++------------ test/evaluators.cpp | 12 +++++++++--- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index e2c9c69cd..cdc2f2d46 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -305,6 +305,7 @@ using std::ptrdiff_t; #include "src/Core/functors/UnaryFunctors.h" #include "src/Core/functors/NullaryFunctors.h" #include "src/Core/functors/StlFunctors.h" +#include "src/Core/functors/AssignmentFunctors.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" @@ -312,7 +313,6 @@ using std::ptrdiff_t; #include "src/Core/EigenBase.h" #ifdef EIGEN_ENABLE_EVALUATORS -#include "src/Core/functors/AssignmentFunctors.h" #include "src/Core/Product.h" #include "src/Core/CoreEvaluators.h" #include "src/Core/AssignEvaluator.h" diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 50a63c85c..9bbfacbcf 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -397,7 +397,7 @@ template class DenseBase void swap(const DenseBase& other, int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) { - swap_using_evaluator(derived(), other.derived()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } /** swaps *this with the matrix or array \a other. @@ -407,7 +407,7 @@ template class DenseBase EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { - swap_using_evaluator(derived(), other.derived()); + call_assignment(derived(), other.derived(), internal::swap_assign_op()); } #else // EIGEN_TEST_EVALUATORS /** swaps *this with the expression \a other. diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 96ed9cef9..d1fd21ad7 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -414,11 +414,11 @@ template class TriangularView EIGEN_DEVICE_FUNC void swap(TriangularBase const & other) { -// #ifdef EIGEN_TEST_EVALUATORS -// swap_using_evaluator(this->derived(), other.derived()); -// #else - TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); -// #endif + #ifdef EIGEN_TEST_EVALUATORS + call_assignment(*this, other.const_cast_derived(), internal::swap_assign_op()); + #else + TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.const_cast_derived().nestedExpression()); + #endif } // TODO: this overload is ambiguous and it should be deprecated (Gael) @@ -426,12 +426,12 @@ template class TriangularView EIGEN_DEVICE_FUNC void swap(MatrixBase const & other) { -// #ifdef EIGEN_TEST_EVALUATORS -// swap_using_evaluator(this->derived(), other.derived()); -// #else + #ifdef EIGEN_TEST_EVALUATORS + call_assignment(*this, other.const_cast_derived(), internal::swap_assign_op()); + #else SwapWrapper swaper(const_cast(m_matrix)); TriangularView,Mode>(swaper).lazyAssign(other.derived()); -// #endif + #endif } EIGEN_DEVICE_FUNC @@ -988,7 +988,6 @@ void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& sr call_triangular_assignment_loop(dst, src, internal::assign_op()); } - template<> struct AssignmentKind { typedef Triangular2Triangular Kind; }; template<> struct AssignmentKind { typedef Triangular2Dense Kind; }; template<> struct AssignmentKind { typedef Dense2Triangular Kind; }; @@ -1028,8 +1027,8 @@ template(), MatrixXd(A.triangularView())); @@ -434,5 +434,11 @@ void test_evaluators() C = B; C.triangularView() = A.triangularView().transpose(); copy_using_evaluator(B.triangularView(), A.triangularView().transpose()); VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A.triangularView().transpose())"); + + + A.setRandom();B.setRandom(); C = B; D = A; + C.triangularView().swap(D.triangularView()); + swap_using_evaluator(B.triangularView(), A.triangularView()); + VERIFY(B.isApprox(C) && "swap_using_evaluator(B.triangularView(), A.triangularView())"); } } -- cgit v1.2.3 From 7f917807c6a72ae219880fb72e2d644d617427bc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 16:19:14 +0100 Subject: Fix product evaluator when TEST_EVALUATOR in not ON --- Eigen/src/Core/ProductEvaluators.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 51228be5f..26145ceff 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -58,7 +58,9 @@ struct product_evaluator, ProductTag, DenseSha product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { + ::new (static_cast(this)) Base(m_result); + dense_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } @@ -186,7 +188,11 @@ struct dense_product_impl template static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) - { dst = lazyprod(lhs,rhs); } + { + // TODO: use the following instead of calling call_assignment + // dst = lazyprod(lhs,rhs); + call_assignment(dst, lazyprod(lhs,rhs), internal::assign_op()); + } template static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) -- cgit v1.2.3 From 34ca81b1bfe77b11effdd463099b30d12b6466c9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 16:37:58 +0100 Subject: Add direct assignment of products --- Eigen/src/Core/AssignEvaluator.h | 5 +++++ Eigen/src/Core/ProductEvaluators.h | 40 ++++++++++++++++++++++++++++++++++++-- test/evaluators.cpp | 15 ++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 3babc16ba..6d3739407 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -679,6 +679,11 @@ void call_assignment(const NoAlias& dst, const Src& src, const { Assignment::run(dst.expression(), src, func); } +template class StorageBase, typename Src, typename Func> +void call_assignment(NoAlias& dst, const Src& src, const Func& func) +{ + Assignment::run(dst.expression(), src, func); +} // Generic Dense to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 26145ceff..d0dba1644 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -45,6 +45,12 @@ struct evaluator > template::value> struct dense_product_impl; +template +struct evaluator_traits > + : evaluator_traits_base > +{ + enum { AssumeAliasing = 1 }; +}; // The evaluator for default dense products creates a temporary and call dense_product_impl template @@ -58,9 +64,7 @@ struct product_evaluator, ProductTag, DenseSha product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { - ::new (static_cast(this)) Base(m_result); - dense_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } @@ -68,6 +72,38 @@ protected: PlainObject m_result; }; +// Dense = Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dense_product_impl::evalTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense += Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Dense, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + dense_product_impl::addTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense -= Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Dense, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + dense_product_impl::subTo(dst, src.lhs(), src.rhs()); + } +}; template struct dense_product_impl diff --git a/test/evaluators.cpp b/test/evaluators.cpp index 7a20014dd..c07146260 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -47,14 +47,14 @@ namespace Eigen { void add_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) { typedef typename DstXprType::Scalar Scalar; - call_assignment(dst.const_cast_derived(), src.derived(), internal::add_assign_op()); + call_assignment(const_cast(dst), src.derived(), internal::add_assign_op()); } template void subtract_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) { typedef typename DstXprType::Scalar Scalar; - call_assignment(dst.const_cast_derived(), src.derived(), internal::sub_assign_op()); + call_assignment(const_cast(dst), src.derived(), internal::sub_assign_op()); } template @@ -151,6 +151,17 @@ void test_evaluators() c = a*a; copy_using_evaluator(a, prod(a,a)); VERIFY_IS_APPROX(a,c); + + // check compound assignment of products + d = c; + add_assign_using_evaluator(c.noalias(), prod(a,b)); + d.noalias() += a*b; + VERIFY_IS_APPROX(c, d); + + d = c; + subtract_assign_using_evaluator(c.noalias(), prod(a,b)); + d.noalias() -= a*b; + VERIFY_IS_APPROX(c, d); } { -- cgit v1.2.3 From b5fd774775d31df3af532ab0798d8be3dc8448d9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 17:53:26 +0100 Subject: Fix flags of Product<> --- Eigen/src/Core/Product.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 970d257a5..3b8fd7d9a 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -33,12 +33,12 @@ template class Pro namespace internal { template struct traits > - : traits::Type> + : traits > { // We want A+B*C to be of type Product and not Product // TODO: This flag should eventually go in a separate evaluator traits class enum { - Flags = traits::Type>::Flags & ~(EvalBeforeNestingBit | DirectAccessBit) + Flags = traits >::Flags & ~(EvalBeforeNestingBit | DirectAccessBit) }; }; } // end namespace internal -- cgit v1.2.3 From 6f1a0479b3a8176f4d8db6513cbb39c027c34b7f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 17:54:15 +0100 Subject: fix a typo triangular assignment --- Eigen/src/Core/TriangularMatrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index d1fd21ad7..602f0c5d1 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -1127,7 +1127,7 @@ struct triangular_assignment_loop kernel.assignCoeff(i, j); if (ClearOpposite) for(Index i = maxi; i < kernel.rows(); ++i) - kernel.assignCoeff(i, j) = Scalar(0); + kernel.assignCoeff(i, j, Scalar(0)); } } }; -- cgit v1.2.3 From f0b82c3ab972a1eafd6aa4f08f4eaffa0d6f1e55 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 2 Dec 2013 17:54:38 +0100 Subject: Make reductions compatible with evaluators --- Eigen/src/Core/Redux.h | 81 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index b2c775d90..1b6a4177a 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -174,7 +174,7 @@ struct redux_impl typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res; @@ -200,10 +200,10 @@ struct redux_impl typedef typename packet_traits::type PacketScalar; typedef typename Derived::Index Index; - static Scalar run(const Derived& mat, const Func& func) + static Scalar run(const Derived &mat, const Func& func) { const Index size = mat.size(); - eigen_assert(size && "you are using an empty matrix"); + const Index packetSize = packet_traits::size; const Index alignedStart = internal::first_aligned(mat); enum { @@ -258,7 +258,7 @@ struct redux_impl typedef typename packet_traits::type PacketScalar; typedef typename Derived::Index Index; - static Scalar run(const Derived& mat, const Func& func) + static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); @@ -300,9 +300,8 @@ struct redux_impl Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { - eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res = func.predux(redux_vec_unroller::run(mat,func)); if (VectorizedSize != Size) res = func(res,redux_novec_unroller::run(mat,func)); @@ -310,6 +309,64 @@ struct redux_impl } }; +#ifdef EIGEN_ENABLE_EVALUATORS +// evaluator adaptor +template +class redux_evaluator +{ +public: + redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; + + enum { + MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, + // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator + Flags = XprType::Flags & ~DirectAccessBit, + IsRowMajor = XprType::IsRowMajor, + SizeAtCompileTime = XprType::SizeAtCompileTime, + InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, + CoeffReadCost = XprType::CoeffReadCost + }; + + Index rows() const { return m_xpr.rows(); } + Index cols() const { return m_xpr.cols(); } + Index size() const { return m_xpr.size(); } + Index innerSize() const { return m_xpr.innerSize(); } + Index outerSize() const { return m_xpr.outerSize(); } + + CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + + CoeffReturnType coeff(Index index) const + { return m_evaluator.coeff(index); } + + template + PacketReturnType packet(Index row, Index col) const + { return m_evaluator.template packet(row, col); } + + template + PacketReturnType packet(Index index) const + { return m_evaluator.template packet(index); } + + CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + template + PacketReturnType packetByOuterInner(Index outer, Index inner) const + { return m_evaluator.template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + +protected: + typename internal::evaluator::nestedType m_evaluator; + const XprType &m_xpr; +}; +#endif + } // end namespace internal /*************************************************************************** @@ -320,7 +377,7 @@ struct redux_impl /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be - * an associative operator. Both current STL and TR1 functor styles are handled. + * an associative operator. Both current C++98 and C++11 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ @@ -329,9 +386,19 @@ template EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type DenseBase::redux(const Func& func) const { + eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); +#ifdef EIGEN_TEST_EVALUATORS + + typedef typename internal::redux_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + return internal::redux_impl::run(thisEval, func); + +#else typedef typename internal::remove_all::type ThisNested; + return internal::redux_impl ::run(derived(), func); +#endif } /** \returns the minimum of all coefficients of \c *this. -- cgit v1.2.3 From 6c5e915e9a6c79550e7e2db2b53648f163a1411d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 3 Dec 2013 17:17:53 +0100 Subject: Enable use of evaluators for noalias and lazyProduct, add conversion to scalar for inner products --- Eigen/src/Core/CoreEvaluators.h | 4 ---- Eigen/src/Core/GeneralProduct.h | 33 ++++++++++++++++++++++++++--- Eigen/src/Core/MatrixBase.h | 4 ++++ Eigen/src/Core/NoAlias.h | 29 +++++++++++++++++++++++++ Eigen/src/Core/Product.h | 6 ++++++ Eigen/src/Core/ProductEvaluators.h | 32 ++++++++++++++++------------ Eigen/src/Core/products/CoeffBasedProduct.h | 6 +++++- Eigen/src/Core/util/ForwardDeclarations.h | 6 ++++++ Eigen/src/Core/util/StaticAssert.h | 3 ++- test/main.h | 2 ++ 10 files changed, 103 insertions(+), 22 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 961b56e55..faf5aedb5 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -53,11 +53,7 @@ struct storage_kind_to_shape { }; */ -template struct evaluator_traits; -template< typename T, - typename Kind = typename evaluator_traits::Kind, - typename Scalar = typename T::Scalar> struct evaluator; template< typename T, typename LhsKind = typename evaluator_traits::Kind, diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index c9ab63782..675f6ee8d 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -623,7 +623,7 @@ MatrixBase::operator*(const MatrixBase &other) const return Product(derived(), other.derived()); } -#else +#else // EIGEN_TEST_EVALUATORS template template inline const typename ProductReturnType::Type @@ -653,9 +653,10 @@ MatrixBase::operator*(const MatrixBase &other) const #endif return typename ProductReturnType::Type(derived(), other.derived()); } -#endif +#endif // EIGEN_TEST_EVALUATORS + +#endif // __CUDACC__ -#endif /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * * The returned product will behave like any other expressions: the coefficients of the product will be @@ -667,6 +668,31 @@ MatrixBase::operator*(const MatrixBase &other) const * * \sa operator*(const MatrixBase&) */ +#ifdef EIGEN_TEST_EVALUATORS +template +template +const Product +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 Product(derived(), other.derived()); +} +#else // EIGEN_TEST_EVALUATORS template template const typename LazyProductReturnType::Type @@ -690,6 +716,7 @@ MatrixBase::lazyProduct(const MatrixBase &other) const return typename LazyProductReturnType::Type(derived(), other.derived()); } +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 61798317e..37e7408a4 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -199,7 +199,11 @@ template class MatrixBase template EIGEN_DEVICE_FUNC +#ifdef EIGEN_TEST_EVALUATORS + const Product +#else const typename LazyProductReturnType::Type +#endif lazyProduct(const MatrixBase &other) const; template diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 65117a806..6ac525336 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -34,6 +34,33 @@ class NoAlias typedef typename ExpressionType::Scalar Scalar; NoAlias(ExpressionType& expression) : m_expression(expression) {} + +#ifdef EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) + { + call_assignment(*this, other.derived(), internal::assign_op()); + return m_expression; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) + { + call_assignment(*this, other.derived(), internal::add_assign_op()); + return m_expression; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) + { + call_assignment(*this, other.derived(), internal::sub_assign_op()); + return m_expression; + } + +#else /** Behaves like MatrixBase::lazyAssign(other) * \sa MatrixBase::lazyAssign() */ @@ -91,6 +118,8 @@ class NoAlias template ExpressionType& operator=(const ReturnByValue& func) { return m_expression = func; } +#endif + #endif EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 3b8fd7d9a..b37fd2ff7 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -79,6 +79,12 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, const LhsNestedCleaned& lhs() const { return m_lhs; } const RhsNestedCleaned& rhs() const { return m_rhs; } + + /** Convertion to scalar for inner-products */ + operator const Scalar() const { + EIGEN_STATIC_ASSERT(SizeAtCompileTime==1, IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY); + return typename internal::evaluator::type(*this).coeff(0,0); + } protected: diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index d0dba1644..5dd480cad 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -209,12 +209,12 @@ struct dense_product_impl : dense_product_impl_base::Scalar Scalar; - template - static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); - } +// template +// static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) +// { +// // TODO bypass GeneralProduct class +// GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); +// } }; template @@ -225,22 +225,28 @@ struct dense_product_impl template static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { - // TODO: use the following instead of calling call_assignment + // TODO: use the following instead of calling call_assignment, same for the other methods // dst = lazyprod(lhs,rhs); call_assignment(dst, lazyprod(lhs,rhs), internal::assign_op()); } template static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) - { dst += lazyprod(lhs,rhs); } + { + // dst += lazyprod(lhs,rhs); + call_assignment(dst, lazyprod(lhs,rhs), internal::add_assign_op()); + } template static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) - { dst -= lazyprod(lhs,rhs); } + { + // dst -= lazyprod(lhs,rhs); + call_assignment(dst, lazyprod(lhs,rhs), internal::sub_assign_op()); + } - template - static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - { dst += alpha * lazyprod(lhs,rhs); } +// template +// static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) +// { dst += alpha * lazyprod(lhs,rhs); } }; template @@ -286,7 +292,7 @@ struct product_evaluator, ProductTag, DenseShape, CoeffReadCost = traits::CoeffReadCost, Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, CanVectorizeInner = traits::CanVectorizeInner, - Flags = CoeffBasedProductType::Flags + Flags = traits::Flags }; typedef typename evaluator::type LhsEtorType; diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 637513132..c987a30b0 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -14,7 +14,7 @@ namespace Eigen { namespace internal { - + /********************************************************************************* * Coefficient based product implementation. * It is designed for the following use cases: @@ -110,6 +110,8 @@ struct traits > } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS + template class CoeffBasedProduct : internal::no_assignment_operator, @@ -447,6 +449,8 @@ struct product_packet_impl } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_COEFFBASED_PRODUCT_H diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 776eac587..3bc151229 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -36,6 +36,12 @@ template struct accessors_level }; }; +template struct evaluator_traits; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct evaluator; + } // end namespace internal template struct NumTraits; diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 8872c5b64..b9b1ee02a 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -90,7 +90,8 @@ YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED, THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE, THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH, - OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG + OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG, + IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY }; }; diff --git a/test/main.h b/test/main.h index 9dd8bc535..dda451a40 100644 --- a/test/main.h +++ b/test/main.h @@ -66,6 +66,8 @@ namespace Eigen static bool g_has_set_repeat, g_has_set_seed; } +#define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl + #define EI_PP_MAKE_STRING2(S) #S #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) -- cgit v1.2.3 From 8d8acc3ab4f0b3f45f2a8bc25c0b7f5f66a22024 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 4 Dec 2013 22:58:19 +0100 Subject: Move inner product special functions to a base class to avoid ambiguous calls --- Eigen/src/Core/Product.h | 50 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index b37fd2ff7..79d09fbb6 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -79,12 +79,6 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, const LhsNestedCleaned& lhs() const { return m_lhs; } const RhsNestedCleaned& rhs() const { return m_rhs; } - - /** Convertion to scalar for inner-products */ - operator const Scalar() const { - EIGEN_STATIC_ASSERT(SizeAtCompileTime==1, IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY); - return typename internal::evaluator::type(*this).coeff(0,0); - } protected: @@ -92,13 +86,51 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, RhsNested m_rhs; }; +namespace internal { + +template::ret> +class dense_product_base + : public internal::dense_xpr_base >::type +{}; + +/** Convertion to scalar for inner-products */ template -class ProductImpl : public internal::dense_xpr_base >::type +class dense_product_base + : public internal::dense_xpr_base >::type +{ + typedef Product ProductXpr; + typedef typename internal::dense_xpr_base::type Base; +public: + using Base::derived; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + + operator const Scalar() const + { + return typename internal::evaluator::type(derived()).coeff(0,0); + } + + Scalar coeff(Index row, Index col) const + { + return typename internal::evaluator::type(derived()).coeff(row,col); + } + + Scalar coeff(Index i) const + { + return typename internal::evaluator::type(derived()).coeff(i); + } +}; + +} // namespace internal + +template +class ProductImpl + : public internal::dense_product_base { typedef Product Derived; public: - - typedef typename internal::dense_xpr_base >::type Base; + + typedef typename internal::dense_product_base Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) }; -- cgit v1.2.3 From 2ca0ccd2f2a88e7bae3c502ec2082178506a3d81 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 7 Dec 2013 17:17:47 +0100 Subject: Add support for triangular products with evaluators --- Eigen/src/Core/NoAlias.h | 2 + Eigen/src/Core/ProductEvaluators.h | 126 +++++++++++++++++++++++----- Eigen/src/Core/TriangularMatrix.h | 24 ++++++ Eigen/src/Core/products/CoeffBasedProduct.h | 4 +- test/evaluators.cpp | 5 ++ 5 files changed, 137 insertions(+), 24 deletions(-) diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 6ac525336..3c9c951f0 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -40,6 +40,8 @@ class NoAlias EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { + // TODO either call resize here or call "call_assignment" through m_expression.lazyAssign() ?? + m_expression.resizeLike(other.derived()); call_assignment(*this, other.derived(), internal::assign_op()); return m_expression; } diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 5dd480cad..c3a9f0db4 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -17,7 +17,7 @@ namespace Eigen { namespace internal { -// Like more general binary expressions, products need they own evaluator: +// Like more general binary expressions, products need their own evaluator: template< typename T, int ProductTag = internal::product_tag::ret, typename LhsShape = typename evaluator_traits::Shape, @@ -39,11 +39,14 @@ struct evaluator > evaluator(const XprType& xpr) : Base(xpr) {} }; -// Helper class to perform a dense product with the destination at hand. +// Helper class to perform a matrix product with the destination at hand. // Depending on the sizes of the factors, there are different evaluation strategies // as controlled by internal::product_type. -template::value> -struct dense_product_impl; +template< typename Lhs, typename Rhs, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + int ProductType = internal::product_type::value> +struct generic_product_impl; template struct evaluator_traits > @@ -52,7 +55,7 @@ struct evaluator_traits > enum { AssumeAliasing = 1 }; }; -// The evaluator for default dense products creates a temporary and call dense_product_impl +// The evaluator for default dense products creates a temporary and call generic_product_impl template struct product_evaluator, ProductTag, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> : public evaluator::PlainObject>::type @@ -65,7 +68,7 @@ struct product_evaluator, ProductTag, DenseSha : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); - dense_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } protected: @@ -79,7 +82,7 @@ struct Assignment, internal::assign_ typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { - dense_product_impl::evalTo(dst, src.lhs(), src.rhs()); + generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); } }; @@ -90,7 +93,7 @@ struct Assignment, internal::add_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) { - dense_product_impl::addTo(dst, src.lhs(), src.rhs()); + generic_product_impl::addTo(dst, src.lhs(), src.rhs()); } }; @@ -101,12 +104,12 @@ struct Assignment, internal::sub_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) { - dense_product_impl::subTo(dst, src.lhs(), src.rhs()); + generic_product_impl::subTo(dst, src.lhs(), src.rhs()); } }; template -struct dense_product_impl +struct generic_product_impl { template static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) @@ -128,7 +131,7 @@ struct dense_product_impl template -struct dense_product_impl +struct generic_product_impl { typedef typename Product::Scalar Scalar; @@ -165,7 +168,7 @@ struct dense_product_impl // This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo template -struct dense_product_impl_base +struct generic_product_impl_base { typedef typename Product::Scalar Scalar; @@ -188,7 +191,8 @@ struct dense_product_impl_base }; template -struct dense_product_impl : dense_product_impl_base > +struct generic_product_impl + : generic_product_impl_base > { typedef typename Product::Scalar Scalar; enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; @@ -205,20 +209,21 @@ struct dense_product_impl : dense_product_impl_base -struct dense_product_impl : dense_product_impl_base > +struct generic_product_impl + : generic_product_impl_base > { typedef typename Product::Scalar Scalar; -// template -// static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) -// { -// // TODO bypass GeneralProduct class -// GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); -// } + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // TODO bypass GeneralProduct class + GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); + } }; template -struct dense_product_impl +struct generic_product_impl { typedef typename Product::Scalar Scalar; @@ -249,8 +254,10 @@ struct dense_product_impl // { dst += alpha * lazyprod(lhs,rhs); } }; +// This specialization enforces the use of a coefficient-based evaluation strategy template -struct dense_product_impl : dense_product_impl {}; +struct generic_product_impl + : generic_product_impl {}; // Case 2: Evaluate coeff by coeff // @@ -547,6 +554,81 @@ struct etor_product_packet_impl } }; + +/*************************************************************************** +* Triangular products +***************************************************************************/ + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // TODO bypass TriangularProduct class + TriangularProduct(lhs.nestedExpression(),rhs).scaleAndAddTo(dst, alpha); + } +}; + +template +struct product_evaluator, ProductTag, TriangularShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // TODO bypass TriangularProduct class + TriangularProduct(lhs,rhs.nestedExpression()).scaleAndAddTo(dst, alpha); + } +}; + +template +struct product_evaluator, ProductTag, DenseShape, TriangularShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + + + + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 602f0c5d1..28191694d 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -49,6 +49,7 @@ template class TriangularBase : public EigenBase typedef typename internal::traits::Index Index; typedef typename internal::traits::DenseMatrixType DenseMatrixType; typedef DenseMatrixType DenseType; + typedef Derived const& Nested; EIGEN_DEVICE_FUNC inline TriangularBase() { eigen_assert(!((Mode&UnitDiag) && (Mode&ZeroDiag))); } @@ -204,6 +205,7 @@ template class TriangularView enum { Mode = _Mode, + Flags = internal::traits::Flags, TransposeMode = (Mode & Upper ? Lower : 0) | (Mode & Lower ? Upper : 0) | (Mode & (UnitDiag)) @@ -326,6 +328,27 @@ template class TriangularView return m_matrix.transpose(); } +#ifdef EIGEN_TEST_EVALUATORS + + /** Efficient triangular matrix times vector/matrix product */ + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase& rhs) const + { + return Product(*this, rhs.derived()); + } + + /** Efficient vector/matrix times triangular matrix product */ + template friend + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase& lhs, const TriangularView& rhs) + { + return Product(lhs.derived(),rhs); + } + +#else // EIGEN_TEST_EVALUATORS /** Efficient triangular matrix times vector/matrix product */ template EIGEN_DEVICE_FUNC @@ -347,6 +370,7 @@ template class TriangularView (lhs.derived(),rhs.m_matrix); } +#endif #ifdef EIGEN2_SUPPORT template diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index c987a30b0..5f8182aa9 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -49,8 +49,8 @@ struct traits > enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, + LhsFlags = traits<_LhsNested>::Flags, + RhsFlags = traits<_RhsNested>::Flags, RowsAtCompileTime = _LhsNested::RowsAtCompileTime, ColsAtCompileTime = _RhsNested::ColsAtCompileTime, diff --git a/test/evaluators.cpp b/test/evaluators.cpp index c07146260..d4b737348 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -451,5 +451,10 @@ void test_evaluators() C.triangularView().swap(D.triangularView()); swap_using_evaluator(B.triangularView(), A.triangularView()); VERIFY(B.isApprox(C) && "swap_using_evaluator(B.triangularView(), A.triangularView())"); + + + VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.triangularView(),A), MatrixXd(A.triangularView()*A)); + + B.col(0).noalias() = prod( (2.1 * A.adjoint()).triangularView() , (A.row(0)).adjoint() ); } } -- cgit v1.2.3 From e94fe4cc3e371f37b39f7b5f824cd3acc74af823 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 13 Dec 2013 18:06:58 +0100 Subject: fix resizing in noalias for blocks, and make -=/+= use evaluators --- Eigen/src/Core/CwiseBinaryOp.h | 8 ++++++++ Eigen/src/Core/NoAlias.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index e20daacc8..5624a4718 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -213,8 +213,12 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { +#ifdef EIGEN_TEST_EVALUATORS + call_assignment(derived(), other.derived(), internal::sub_assign_op()); +#else SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); +#endif return derived(); } @@ -227,8 +231,12 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { +#ifdef EIGEN_TEST_EVALUATORS + call_assignment(derived(), other.derived(), internal::add_assign_op()); +#else SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); tmp = other.derived(); +#endif return derived(); } diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 3c9c951f0..412e37258 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -41,7 +41,7 @@ class NoAlias EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { // TODO either call resize here or call "call_assignment" through m_expression.lazyAssign() ?? - m_expression.resizeLike(other.derived()); + m_expression.resize(other.derived().rows(), other.derived().cols()); call_assignment(*this, other.derived(), internal::assign_op()); return m_expression; } -- cgit v1.2.3 From 27c068e9d6230398b74a1c7b7146d7842c509de7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 13 Dec 2013 18:09:07 +0100 Subject: Make selfqdjoint products use evaluators --- Eigen/src/Core/ProductEvaluators.h | 71 ++++++++++++++++++++++++++++++++++++++ Eigen/src/Core/SelfAdjointView.h | 43 +++++++++++++++++++++-- test/evaluators.cpp | 3 +- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index c3a9f0db4..f0eb57d67 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -628,6 +628,77 @@ protected: +/*************************************************************************** +* SelfAdjoint products +***************************************************************************/ + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + {// SelfadjointProductMatrix + // TODO bypass SelfadjointProductMatrix class + SelfadjointProductMatrix(lhs.nestedExpression(),rhs).scaleAndAddTo(dst, alpha); + } +}; + +template +struct product_evaluator, ProductTag, SelfAdjointShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + {//SelfadjointProductMatrix + // TODO bypass SelfadjointProductMatrix class + SelfadjointProductMatrix(lhs,rhs.nestedExpression()).scaleAndAddTo(dst, alpha); + } +}; + +template +struct product_evaluator, ProductTag, DenseShape, SelfAdjointShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + } // end namespace internal diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 8231e3f5c..079b987f8 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -50,11 +50,12 @@ template class SelfAdjointView - : public TriangularBase > +template class SelfAdjointView + : public TriangularBase > { public: + typedef _MatrixType MatrixType; typedef TriangularBase Base; typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; @@ -65,7 +66,8 @@ template class SelfAdjointView typedef typename MatrixType::Index Index; enum { - Mode = internal::traits::Mode + Mode = internal::traits::Mode, + Flags = internal::traits::Flags }; typedef typename MatrixType::PlainObject PlainObject; @@ -111,6 +113,28 @@ template class SelfAdjointView EIGEN_DEVICE_FUNC MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } +#ifdef EIGEN_TEST_EVALUATORS + + /** Efficient triangular matrix times vector/matrix product */ + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase& rhs) const + { + return Product(*this, rhs.derived()); + } + + /** Efficient vector/matrix times triangular matrix product */ + template friend + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase& lhs, const SelfAdjointView& rhs) + { + return Product(lhs.derived(),rhs); + } + +#else // EIGEN_TEST_EVALUATORS + /** Efficient self-adjoint matrix times vector/matrix product */ template EIGEN_DEVICE_FUNC @@ -132,6 +156,7 @@ template class SelfAdjointView (lhs.derived(),rhs.m_matrix); } +#endif /** Perform a symmetric rank 2 update of the selfadjoint matrix \c *this: * \f$ this = this + \alpha u v^* + conj(\alpha) v u^* \f$ @@ -311,6 +336,18 @@ struct triangular_assignment_selector +// in the future selfadjoint-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef SelfAdjointShape Shape; + + static const int AssumeAliasing = 0; +}; + } // end namespace internal /*************************************************************************** diff --git a/test/evaluators.cpp b/test/evaluators.cpp index d4b737348..69a45661f 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -455,6 +455,7 @@ void test_evaluators() VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.triangularView(),A), MatrixXd(A.triangularView()*A)); - B.col(0).noalias() = prod( (2.1 * A.adjoint()).triangularView() , (A.row(0)).adjoint() ); + VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.selfadjointView(),A), MatrixXd(A.selfadjointView()*A)); + } } -- cgit v1.2.3 From d357bbd9c06f4b6088de0a8e47b3e56fdd0b99b3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 14 Dec 2013 22:53:47 +0100 Subject: Fix a few regression regarding temporaries and products --- Eigen/src/Core/GeneralProduct.h | 53 ++++++++++++++-------------- Eigen/src/Core/Product.h | 2 +- Eigen/src/Core/ProductEvaluators.h | 72 +++++++++++++++++++++++++++++++++++--- Eigen/src/Core/SelfAdjointView.h | 2 ++ 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 675f6ee8d..f823ff251 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -82,7 +82,8 @@ private: public: enum { - value = selector::ret + value = selector::ret, + ret = selector::ret }; #ifdef EIGEN_DEBUG_PRODUCT static void debug() @@ -98,31 +99,31 @@ public: #endif }; -template struct product_tag -{ -private: - - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - enum { - Rows = _Lhs::RowsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, _Rhs::RowsAtCompileTime) - }; - - enum { - rows_select = Rows==1 ? int(Rows) : int(Large), - cols_select = Cols==1 ? int(Cols) : int(Large), - depth_select = Depth==1 ? int(Depth) : int(Large) - }; - typedef product_type_selector selector; - -public: - enum { - ret = selector::ret - }; - -}; +// template struct product_tag +// { +// private: +// +// typedef typename remove_all::type _Lhs; +// typedef typename remove_all::type _Rhs; +// enum { +// Rows = _Lhs::RowsAtCompileTime, +// Cols = _Rhs::ColsAtCompileTime, +// Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, _Rhs::RowsAtCompileTime) +// }; +// +// enum { +// rows_select = Rows==1 ? int(Rows) : int(Large), +// cols_select = Cols==1 ? int(Cols) : int(Large), +// depth_select = Depth==1 ? int(Depth) : int(Large) +// }; +// typedef product_type_selector selector; +// +// public: +// enum { +// ret = selector::ret +// }; +// +// }; /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 79d09fbb6..d64fbae35 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -88,7 +88,7 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, namespace internal { -template::ret> +template::ret> class dense_product_base : public internal::dense_xpr_base >::type {}; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index f0eb57d67..46048882b 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -19,7 +19,7 @@ namespace internal { // Like more general binary expressions, products need their own evaluator: template< typename T, - int ProductTag = internal::product_tag::ret, + int ProductTag = internal::product_type::ret, typename LhsShape = typename evaluator_traits::Shape, typename RhsShape = typename evaluator_traits::Shape, typename LhsScalar = typename T::Lhs::Scalar, @@ -38,7 +38,43 @@ struct evaluator > evaluator(const XprType& xpr) : Base(xpr) {} }; + +// Catch scalar * ( A * B ) and transform it to (A*scalar) * B +// TODO we should apply that rule if that's really helpful +template +struct evaluator, const Product > > + : public evaluator,const Lhs>, Rhs, DefaultProduct> > +{ + typedef CwiseUnaryOp, const Product > XprType; + typedef evaluator,const Lhs>, Rhs, DefaultProduct> > Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType& xpr) + : Base(xpr.functor().m_other * xpr.nestedExpression().lhs() * xpr.nestedExpression().rhs()) + {} +}; + + +template +struct evaluator, DiagIndex> > + : public evaluator, DiagIndex> > +{ + typedef Diagonal, DiagIndex> XprType; + typedef evaluator, DiagIndex> > Base; + typedef evaluator type; + typedef evaluator nestedType; +// + evaluator(const XprType& xpr) + : Base(Diagonal, DiagIndex>( + Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), + xpr.index() )) + {} +}; + + // Helper class to perform a matrix product with the destination at hand. // Depending on the sizes of the factors, there are different evaluation strategies // as controlled by internal::product_type. @@ -108,6 +144,23 @@ struct Assignment, internal::sub_ass } }; + +// Dense ?= scalar * Product +// TODO we should apply that rule if that's really helpful +// for instance, this is not good for inner products +template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis> +struct Assignment, + const Product >, AssignFunc, Dense2Dense, Scalar> +{ + typedef CwiseUnaryOp, + const Product > SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) + { + call_assignment(dst.noalias(), (src.functor().m_other * src.nestedExpression().lhs()) * src.nestedExpression().rhs(), func); + } +}; + + template struct generic_product_impl { @@ -255,9 +308,9 @@ struct generic_product_impl }; // This specialization enforces the use of a coefficient-based evaluation strategy -template -struct generic_product_impl - : generic_product_impl {}; +// template +// struct generic_product_impl +// : generic_product_impl {}; // Case 2: Evaluate coeff by coeff // @@ -347,6 +400,17 @@ protected: Index m_innerDim; }; +template +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar > + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar > +{ + typedef Product XprType; + typedef Product BaseProduct; + typedef product_evaluator Base; + product_evaluator(const XprType& xpr) + : Base(BaseProduct(xpr.lhs(),xpr.rhs())) + {} +}; /*************************************************************************** * Normal product .coeff() implementation (with meta-unrolling) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 079b987f8..a5c6d5ceb 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -336,6 +336,7 @@ struct triangular_assignment_selector // in the future selfadjoint-ness should be defined by the expression traits // such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) @@ -347,6 +348,7 @@ struct evaluator_traits > static const int AssumeAliasing = 0; }; +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace internal -- cgit v1.2.3 From fef534f52e403e24637209f1ad843111c81122bd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 25 Jan 2014 19:06:07 +0100 Subject: fix scalar * prod in evaluators unit test --- Eigen/src/Core/ProductEvaluators.h | 3 ++- Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 46048882b..2279ec33b 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -156,7 +156,8 @@ struct Assignment > SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) { - call_assignment(dst.noalias(), (src.functor().m_other * src.nestedExpression().lhs()) * src.nestedExpression().rhs(), func); + // TODO use operator* instead of prod() once we have made enough progress + call_assignment(dst.noalias(), prod(src.functor().m_other * src.nestedExpression().lhs(), src.nestedExpression().rhs()), func); } }; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 5c3763909..87bd36bc3 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -20,7 +20,7 @@ namespace internal { /********************************************************************** * This file implements a general A * B product while * evaluating only one triangular part of the product. -* This is more general version of self adjoint product (C += A A^T) +* This is a more general version of self adjoint product (C += A A^T) * as the level 3 SYRK Blas routine. **********************************************************************/ -- cgit v1.2.3 From 5fa7262e4c9fdbac2e5ddc4e2bb2241e04a10bef Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 25 Jan 2014 23:02:14 +0100 Subject: Refactor triangular assignment --- Eigen/src/Core/AssignEvaluator.h | 13 +- Eigen/src/Core/SelfAdjointView.h | 5 + Eigen/src/Core/Swap.h | 1 + Eigen/src/Core/TriangularMatrix.h | 301 ++++++++++++++++++++------------------ 4 files changed, 167 insertions(+), 153 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 6d3739407..86cd1cd68 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -140,6 +140,7 @@ public: template struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling { + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? typedef typename Kernel::DstEvaluatorType DstEvaluatorType; typedef typename DstEvaluatorType::XprType DstXprType; @@ -204,9 +205,10 @@ struct copy_using_evaluator_LinearTraversal_CompleteUnrolling struct copy_using_evaluator_innervec_CompleteUnrolling { + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? typedef typename Kernel::DstEvaluatorType DstEvaluatorType; typedef typename DstEvaluatorType::XprType DstXprType; - + enum { outer = Index / DstXprType::InnerSizeAtCompileTime, inner = Index % DstXprType::InnerSizeAtCompileTime, @@ -233,8 +235,7 @@ struct copy_using_evaluator_innervec_InnerUnrolling static EIGEN_STRONG_INLINE void run(Kernel &kernel, int outer) { kernel.template assignPacketByOuterInner(outer, Index); - typedef typename Kernel::DstEvaluatorType::XprType DstXprType; - enum { NextIndex = Index + packet_traits::size }; + enum { NextIndex = Index + packet_traits::size }; copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); } }; @@ -542,12 +543,6 @@ public: m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); } - /// This overload by-passes the source expression, i.e., dst(row,col) ?= value - void assignCoeff(Index row, Index col, const Scalar &value) - { - m_functor.assignCoeff(m_dst.coeffRef(row,col), value); - } - /// \sa assignCoeff(Index,Index) void assignCoeff(Index index) { diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index a5c6d5ceb..f34de8b39 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -244,6 +244,8 @@ template class SelfAdjointView namespace internal { +#ifndef EIGEN_TEST_EVALUATORS + template struct triangular_assignment_selector { @@ -336,6 +338,8 @@ struct triangular_assignment_selector // in the future selfadjoint-ness should be defined by the expression traits @@ -348,6 +352,7 @@ struct evaluator_traits > static const int AssumeAliasing = 0; }; + #endif // EIGEN_ENABLE_EVALUATORS } // end namespace internal diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 117f667f6..e7d525572 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -148,6 +148,7 @@ template class generic_dense_assignment_kernel, Specialized> : public generic_dense_assignment_kernel, BuiltIn> { +protected: typedef generic_dense_assignment_kernel, BuiltIn> Base; typedef typename DstEvaluatorTypeT::PacketScalar PacketScalar; using Base::m_dst; diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 28191694d..c658e2290 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -298,8 +298,8 @@ template class TriangularView template EIGEN_DEVICE_FUNC - void lazyAssign(const MatrixBase& other); - + void lazyAssign(const MatrixBase& other); + /** \sa MatrixBase::conjugate() */ EIGEN_DEVICE_FUNC inline TriangularView conjugate() @@ -469,6 +469,8 @@ template class TriangularView return m_matrix.diagonal().prod(); } +#ifndef EIGEN_TEST_EVALUATORS + // TODO simplify the following: template EIGEN_DEVICE_FUNC @@ -514,7 +516,9 @@ template class TriangularView { return assignProduct(other,-other.alpha()); } - + +#endif // EIGEN_TEST_EVALUATORS + protected: template @@ -530,6 +534,8 @@ template class TriangularView namespace internal { +#ifndef EIGEN_TEST_EVALUATORS + template struct triangular_assignment_selector { @@ -694,8 +700,52 @@ struct triangular_assignment_selector +template +inline TriangularView& +TriangularView::operator=(const MatrixBase& other) +{ + internal::call_assignment(*this, other.template triangularView(), internal::assign_op()); + return *this; +} + +// FIXME should we keep that possibility +template +template +void TriangularView::lazyAssign(const MatrixBase& other) +{ + internal::call_assignment(this->noalias(), other.template triangularView()); +} + + + +template +template +inline TriangularView& +TriangularView::operator=(const TriangularBase& other) +{ + eigen_assert(Mode == int(OtherDerived::Mode)); + internal::call_assignment(*this, other.derived()); + return *this; +} + +template +template +void TriangularView::lazyAssign(const TriangularBase& other) +{ + eigen_assert(Mode == int(OtherDerived::Mode)); + internal::call_assignment(this->noalias(), other.derived()); +} + +#else + // FIXME should we keep that possibility template template @@ -770,6 +820,8 @@ void TriangularView::lazyAssign(const TriangularBase::run(m_matrix.const_cast_derived(), other.derived().nestedExpression()); } +#endif // EIGEN_TEST_EVALUATORS + /*************************************************************************** * Implementation of TriangularBase methods ***************************************************************************/ @@ -790,6 +842,8 @@ void TriangularBase::evalTo(MatrixBase &other) const evalToLazy(other.derived()); } +#ifndef EIGEN_TEST_EVALUATORS + /** Assigns a triangular or selfadjoint matrix to a dense matrix. * If the matrix is triangular, the opposite part is set to zero. */ template @@ -811,6 +865,8 @@ void TriangularBase::evalToLazy(MatrixBase &other) const >::run(other.derived(), derived().nestedExpression()); } +#endif // EIGEN_TEST_EVALUATORS + /*************************************************************************** * Implementation of TriangularView methods ***************************************************************************/ @@ -962,15 +1018,15 @@ struct evaluator_traits > template struct evaluator, Kind, typename MatrixType::Scalar> - : evaluator + : evaluator::type> { typedef TriangularView XprType; - typedef evaluator Base; + typedef evaluator::type> Base; typedef evaluator type; evaluator(const XprType &xpr) : Base(xpr.nestedExpression()) {} }; -// Additional assignement kinds: +// Additional assignment kinds: struct Triangular2Triangular {}; struct Triangular2Dense {}; struct Dense2Triangular {}; @@ -978,6 +1034,59 @@ struct Dense2Triangular {}; template struct triangular_assignment_loop; + +// Specialization of the dense assignment kernel for triangular matrices. +// The main additions are: +// - An overload of assignCoeff(i, j, val) that by-passes the source expression. Needed to set the opposite triangular part to 0. +// - When calling assignCoeff(i,j...), we guarantee that i!=j +// - New assignDiagonalCoeff(i), and assignDiagonalCoeff(i, val) for assigning coefficients on the diagonal. +template +class triangular_dense_assignment_kernel : public generic_dense_assignment_kernel +{ +protected: + typedef generic_dense_assignment_kernel Base; + typedef typename Base::DstXprType DstXprType; + typedef typename Base::SrcXprType SrcXprType; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; +public: + + typedef typename Base::DstEvaluatorType DstEvaluatorType; + typedef typename Base::SrcEvaluatorType SrcEvaluatorType; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::AssignmentTraits AssignmentTraits; + + + triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + {} + +#ifdef EIGEN_INTERNAL_DEBUGGING + void assignCoeff(Index row, Index col) + { + eigen_internal_assert(row!=col); + Base::assignCoeff(row,col); + } +#else + using Base::assignCoeff; +#endif + + void assignDiagonalCoeff(Index id) + { + if((Mode&UnitDiag) && ClearOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(1)); + else if((Mode&ZeroDiag) && ClearOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(0)); + else if((Mode&(UnitDiag|ZeroDiag))==0) Base::assignCoeff(id,id); + } + + void assignOppositeCoeff(Index row, Index col) + { + eigen_internal_assert(row!=col); + if(ClearOpposite) + m_functor.assignCoeff(m_dst.coeffRef(row,col), Scalar(0)); + } +}; template void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) @@ -994,13 +1103,13 @@ void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& sr DstEvaluatorType dstEvaluator(dst); SrcEvaluatorType srcEvaluator(src); - typedef generic_dense_assignment_kernel Kernel; + typedef triangular_dense_assignment_kernel Kernel; Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); enum { unroll = DstXprType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT +// && internal::traits::CoeffReadCost != Dynamic +// && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT }; triangular_assignment_loop::run(kernel); @@ -1050,9 +1159,13 @@ struct Assignment template struct triangular_assignment_loop { + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + enum { - col = (UnrollCount-1) / Kernel::DstEvaluatorType::RowsAtCompileTime, - row = (UnrollCount-1) % Kernel::DstEvaluatorType::RowsAtCompileTime + col = (UnrollCount-1) / DstXprType::RowsAtCompileTime, + row = (UnrollCount-1) % DstXprType::RowsAtCompileTime }; typedef typename Kernel::Scalar Scalar; @@ -1061,24 +1174,13 @@ struct triangular_assignment_loop static inline void run(Kernel &kernel) { triangular_assignment_loop::run(kernel); - - // TODO should be a static assert - eigen_assert( Mode == Upper || Mode == Lower - || Mode == StrictlyUpper || Mode == StrictlyLower - || Mode == UnitUpper || Mode == UnitLower); - if((Mode == Upper && row <= col) - || (Mode == Lower && row >= col) - || (Mode == StrictlyUpper && row < col) - || (Mode == StrictlyLower && row > col) - || (Mode == UnitUpper && row < col) - || (Mode == UnitLower && row > col)) - kernel.assignCoeff(row, col); - else if(ClearOpposite) - { - if((Mode&UnitDiag) && row==col) kernel.assignCoeff(row, col, Scalar(1)); - else kernel.assignCoeff(row, col, Scalar(0)); - } + if(row==col) + kernel.assignDiagonalCoeff(row); + else if( ((Mode&Lower) && row>col) || ((Mode&Upper) && row static inline void run(Kernel &) {} }; -// TODO: merge the following 6 variants into a single one (or max two), -// and perhaps write them using sub-expressions -// TODO: expreiment with a recursive assignment procedure splitting the current -// triangular part into one rectangular and two triangular parts. -template -struct triangular_assignment_loop -{ - typedef typename Kernel::Index Index; - typedef typename Kernel::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Kernel &kernel) - { - for(Index j = 0; j < kernel.cols(); ++j) - { - Index maxi = (std::min)(j, kernel.rows()-1); - for(Index i = 0; i <= maxi; ++i) - kernel.assignCoeff(i, j); - if (ClearOpposite) - for(Index i = maxi+1; i < kernel.rows(); ++i) - kernel.assignCoeff(i, j, Scalar(0)); - } - } -}; - -template -struct triangular_assignment_loop -{ - typedef typename Kernel::Index Index; - typedef typename Kernel::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Kernel &kernel) - { - for(Index j = 0; j < kernel.cols(); ++j) - { - for(Index i = j; i < kernel.rows(); ++i) - kernel.assignCoeff(i, j); - Index maxi = (std::min)(j, kernel.rows()); - if (ClearOpposite) - for(Index i = 0; i < maxi; ++i) - kernel.assignCoeff(i, j, Scalar(0)); - } - } -}; - -template -struct triangular_assignment_loop -{ - typedef typename Kernel::Index Index; - typedef typename Kernel::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Kernel &kernel) - { - for(Index j = 0; j < kernel.cols(); ++j) - { - Index maxi = (std::min)(j, kernel.rows()); - for(Index i = 0; i < maxi; ++i) - kernel.assignCoeff(i, j); - if (ClearOpposite) - for(Index i = maxi; i < kernel.rows(); ++i) - kernel.assignCoeff(i, j, Scalar(0)); - } - } -}; +// TODO: experiment with a recursive assignment procedure splitting the current +// triangular part into one rectangular and two triangular parts. -template -struct triangular_assignment_loop -{ - typedef typename Kernel::Index Index; - typedef typename Kernel::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Kernel &kernel) - { - for(Index j = 0; j < kernel.cols(); ++j) - { - for(Index i = j+1; i < kernel.rows(); ++i) - kernel.assignCoeff(i, j); - Index maxi = (std::min)(j, kernel.rows()-1); - if (ClearOpposite) - for(Index i = 0; i <= maxi; ++i) - kernel.assignCoeff(i, j, Scalar(0)); - } - } -}; -template -struct triangular_assignment_loop -{ - typedef typename Kernel::Index Index; - typedef typename Kernel::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Kernel &kernel) - { - for(Index j = 0; j < kernel.cols(); ++j) - { - Index maxi = (std::min)(j, kernel.rows()); - Index i = 0; - for(; i < maxi; ++i) - kernel.assignCoeff(i, j); - - if(i -struct triangular_assignment_loop +template +struct triangular_assignment_loop { typedef typename Kernel::Index Index; typedef typename Kernel::Scalar Scalar; @@ -1214,24 +1210,41 @@ struct triangular_assignment_loop { Index maxi = (std::min)(j, kernel.rows()); Index i = 0; - if (ClearOpposite) + if (((Mode&Lower) && ClearOpposite) || (Mode&Upper)) { for(; i < maxi; ++i) - kernel.assignCoeff(i, j, Scalar(0)); + if(Mode&Upper) kernel.assignCoeff(i, j); + else kernel.assignOppositeCoeff(i, j); } + else + i = maxi; if(i +template +void TriangularBase::evalToLazy(MatrixBase &other) const +{ + other.derived().resize(this->rows(), this->cols()); + internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); +} + +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen -- cgit v1.2.3 From f54e62e4a941ad5d1a5daaa0cc1cd6835cb7dd72 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 26 Jan 2014 12:18:36 +0100 Subject: Port evaluation from selfadjoint to full to evaluators --- Eigen/src/Core/SelfAdjointView.h | 41 ++++++++++++++++++++++++++ Eigen/src/Core/TriangularMatrix.h | 61 ++++++++++++++++++++------------------- 2 files changed, 72 insertions(+), 30 deletions(-) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index f34de8b39..dd8eb25f8 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -353,6 +353,47 @@ struct evaluator_traits > static const int AssumeAliasing = 0; }; +template +class triangular_dense_assignment_kernel + : public generic_dense_assignment_kernel +{ +protected: + typedef generic_dense_assignment_kernel Base; + typedef typename Base::DstXprType DstXprType; + typedef typename Base::SrcXprType SrcXprType; + using Base::m_dst; + using Base::m_src; + using Base::m_functor; +public: + + typedef typename Base::DstEvaluatorType DstEvaluatorType; + typedef typename Base::SrcEvaluatorType SrcEvaluatorType; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::AssignmentTraits AssignmentTraits; + + + triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + {} + + void assignCoeff(Index row, Index col) + { + eigen_internal_assert(row!=col); + Scalar tmp = m_src.coeff(row,col); + m_functor.assignCoeff(m_dst.coeffRef(row,col), tmp); + m_functor.assignCoeff(m_dst.coeffRef(col,row), numext::conj(tmp)); + } + + void assignDiagonalCoeff(Index id) + { + Base::assignCoeff(id,id); + } + + void assignOppositeCoeff(Index, Index) + { eigen_internal_assert(false && "should never be called"); } +}; + #endif // EIGEN_ENABLE_EVALUATORS } // end namespace internal diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index c658e2290..d413ec2e9 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -1035,12 +1035,12 @@ struct Dense2Triangular {}; template struct triangular_assignment_loop; -// Specialization of the dense assignment kernel for triangular matrices. -// The main additions are: -// - An overload of assignCoeff(i, j, val) that by-passes the source expression. Needed to set the opposite triangular part to 0. -// - When calling assignCoeff(i,j...), we guarantee that i!=j -// - New assignDiagonalCoeff(i), and assignDiagonalCoeff(i, val) for assigning coefficients on the diagonal. -template +/** \internal Specialization of the dense assignment kernel for triangular matrices. + * The main difference is that the triangular, diagonal, and opposite parts are processed through three different functions. + * \tparam UpLo must be either Lower or Upper + * \tparam Mode must be either 0, UnitDiag, ZeroDiag, or SelfAdjoint + */ +template class triangular_dense_assignment_kernel : public generic_dense_assignment_kernel { protected: @@ -1075,20 +1075,20 @@ public: void assignDiagonalCoeff(Index id) { - if((Mode&UnitDiag) && ClearOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(1)); - else if((Mode&ZeroDiag) && ClearOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(0)); - else if((Mode&(UnitDiag|ZeroDiag))==0) Base::assignCoeff(id,id); + if(Mode==UnitDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(1)); + else if(Mode==ZeroDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(0)); + else if(Mode==0) Base::assignCoeff(id,id); } void assignOppositeCoeff(Index row, Index col) { eigen_internal_assert(row!=col); - if(ClearOpposite) + if(SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(row,col), Scalar(0)); } }; -template +template void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { #ifdef EIGEN_DEBUG_ASSIGN @@ -1103,22 +1103,23 @@ void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& sr DstEvaluatorType dstEvaluator(dst); SrcEvaluatorType srcEvaluator(src); - typedef triangular_dense_assignment_kernel Kernel; + typedef triangular_dense_assignment_kernel< Mode&(Lower|Upper),Mode&(UnitDiag|ZeroDiag|SelfAdjoint),SetOpposite, + DstEvaluatorType,SrcEvaluatorType,Functor> Kernel; Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); enum { unroll = DstXprType::SizeAtCompileTime != Dynamic -// && internal::traits::CoeffReadCost != Dynamic -// && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT + && internal::traits::CoeffReadCost != Dynamic + && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT }; - triangular_assignment_loop::run(kernel); + triangular_assignment_loop::run(kernel); } -template +template void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src) { - call_triangular_assignment_loop(dst, src, internal::assign_op()); + call_triangular_assignment_loop(dst, src, internal::assign_op()); } template<> struct AssignmentKind { typedef Triangular2Triangular Kind; }; @@ -1141,8 +1142,8 @@ template< typename DstXprType, typename SrcXprType, typename Functor, typename S struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) - { - call_triangular_assignment_loop(dst, src, func); + { + call_triangular_assignment_loop(dst, src, func); } }; @@ -1150,13 +1151,13 @@ template< typename DstXprType, typename SrcXprType, typename Functor, typename S struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) - { + { call_triangular_assignment_loop(dst, src, func); } }; -template +template struct triangular_assignment_loop { // FIXME: this is not very clean, perhaps this information should be provided by the kernel? @@ -1173,20 +1174,20 @@ struct triangular_assignment_loop EIGEN_DEVICE_FUNC static inline void run(Kernel &kernel) { - triangular_assignment_loop::run(kernel); + triangular_assignment_loop::run(kernel); if(row==col) kernel.assignDiagonalCoeff(row); else if( ((Mode&Lower) && row>col) || ((Mode&Upper) && row -struct triangular_assignment_loop +template +struct triangular_assignment_loop { EIGEN_DEVICE_FUNC static inline void run(Kernel &) {} @@ -1198,8 +1199,8 @@ struct triangular_assignment_loop // triangular part into one rectangular and two triangular parts. -template -struct triangular_assignment_loop +template +struct triangular_assignment_loop { typedef typename Kernel::Index Index; typedef typename Kernel::Scalar Scalar; @@ -1210,7 +1211,7 @@ struct triangular_assignment_loop { Index maxi = (std::min)(j, kernel.rows()); Index i = 0; - if (((Mode&Lower) && ClearOpposite) || (Mode&Upper)) + if (((Mode&Lower) && SetOpposite) || (Mode&Upper)) { for(; i < maxi; ++i) if(Mode&Upper) kernel.assignCoeff(i, j); @@ -1222,7 +1223,7 @@ struct triangular_assignment_loop if(i void TriangularBase::evalToLazy(MatrixBase &other) const { other.derived().resize(this->rows(), this->cols()); - internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); + internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); } #endif // EIGEN_ENABLE_EVALUATORS -- cgit v1.2.3 From ee1c55f9234a5782846035028ddfc22b92ee3732 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 26 Jan 2014 14:55:25 +0100 Subject: Add missing template keyword --- Eigen/src/Core/AssignEvaluator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 86cd1cd68..fe6fbdb9a 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -561,13 +561,13 @@ public: template void assignPacket(Index row, Index col) { - m_functor.assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); + m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); } template void assignPacket(Index index) { - m_functor.assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); + m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); } template -- cgit v1.2.3 From 34694d88285f69131eb96e9f496f35da5165c36d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 26 Jan 2014 15:34:26 +0100 Subject: Fix evaluator for fixed size objects --- Eigen/src/Core/CoreEvaluators.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index faf5aedb5..ef900e236 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -839,8 +839,8 @@ struct evaluator > protected: typename evaluator::nestedType m_argImpl; - const variable_if_dynamic m_rows; - const variable_if_dynamic m_cols; + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; }; -- cgit v1.2.3 From 94acccc126d430bf34587527d84ff9b389219c2f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 26 Jan 2014 15:35:44 +0100 Subject: Fix Random().normalized() by introducing a nested_eval helper (recall that the old nested<> class is deprecated) --- Eigen/src/Core/Dot.h | 7 ++++++- Eigen/src/Core/util/XprHelper.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index 718de5d1a..38f6fbf44 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -141,8 +141,13 @@ template inline const typename MatrixBase::PlainObject MatrixBase::normalized() const { - typedef typename internal::nested::type Nested; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename internal::nested::type Nested; typedef typename internal::remove_reference::type _Nested; +#else + typedef typename internal::nested_eval::type _Nested; +// typedef typename internal::remove_reference::type _Nested; +#endif // EIGEN_TEST_EVALUATORS _Nested n(derived()); return n / n.norm(); } diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 189928c8f..f210344d3 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -296,11 +296,40 @@ struct transfer_constness #ifdef EIGEN_TEST_EVALUATORS // When using evaluators, we never evaluate when assembling the expression!! +// TODO: get rid of this nested class since it's just an alias for ref_selector. template::type> struct nested { typedef typename ref_selector::type type; }; +// However, we still need a mechanism to detect whether an expression which is evaluated multiple time +// has to be evaluated into a temporary. +// That's the purpose of this new nested_eval helper: +template::type> struct nested_eval +{ + enum { + // For the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. + // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. + // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues + // (poor choice of temporaries). + // It's important that this value can still be squared without integer overflowing. + DynamicAsInteger = 10000, + ScalarReadCost = NumTraits::Scalar>::ReadCost, + ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), + CoeffReadCost = traits::CoeffReadCost, + CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), + NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, + CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, + CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger + }; + + typedef typename conditional< + int(CostEvalAsInteger) < int(CostNoEvalAsInteger), + PlainObject, + typename ref_selector::type + >::type type; +}; + #else /** \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 -- cgit v1.2.3 From bffa15142c4271313a70801e6bb7d01365a00bc9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 17 Feb 2014 16:10:55 +0100 Subject: Add evaluator support for diagonal products --- Eigen/src/Core/DiagonalMatrix.h | 36 ++++++++- Eigen/src/Core/ProductEvaluators.h | 146 ++++++++++++++++++++++++++++++++++++- test/evaluators.cpp | 17 ++++- 3 files changed, 192 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index f7ac22f8b..8df636928 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -66,6 +66,7 @@ class DiagonalBase : public EigenBase EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. */ template @@ -75,6 +76,15 @@ class DiagonalBase : public EigenBase { return DiagonalProduct(matrix.derived(), derived()); } +#else + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase &matrix) const + { + return Product(derived(),matrix.derived()); + } +#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline const DiagonalWrapper, const DiagonalVectorType> > @@ -270,7 +280,8 @@ struct traits > ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit + Flags = traits::Flags & LvalueBit, + CoeffReadCost = traits<_DiagonalVectorType>::CoeffReadCost }; }; } @@ -341,6 +352,29 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const return true; } +#ifdef EIGEN_ENABLE_EVALUATORS +namespace internal { + +// TODO currently a diagonal expression has the form DiagonalMatrix<> or DiagonalWrapper +// in the future diagonal-ness should be defined by the expression traits +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef DiagonalShape Shape; + static const int AssumeAliasing = 0; +}; +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef DiagonalShape Shape; + static const int AssumeAliasing = 0; +}; + +} // namespace internal +#endif // EIGEN_ENABLE_EVALUATORS + } // end namespace Eigen #endif // EIGEN_DIAGONALMATRIX_H diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 2279ec33b..d991ff8b5 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -309,9 +309,9 @@ struct generic_product_impl }; // This specialization enforces the use of a coefficient-based evaluation strategy -// template -// struct generic_product_impl -// : generic_product_impl {}; +template +struct generic_product_impl + : generic_product_impl {}; // Case 2: Evaluate coeff by coeff // @@ -764,6 +764,146 @@ protected: PlainObject m_result; }; +/*************************************************************************** +* Diagonal products +***************************************************************************/ + +template +struct diagonal_product_evaluator_base + : evaluator_base +{ + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::PacketScalar PacketScalar; +public: + diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) + : m_diagImpl(diag), m_matImpl(mat) + { + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); + } + +protected: + template + EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matImpl.template packet(row, col), + internal::pset1(m_diagImpl.coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) + }; + return internal::pmul(m_matImpl.template packet(row, col), + m_diagImpl.template packet(id)); + } + + typename evaluator::nestedType m_diagImpl; + typename evaluator::nestedType m_matImpl; +}; + +// diagonal * dense +template +struct product_evaluator, ProductTag, DiagonalShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : diagonal_product_evaluator_base > +{ + typedef diagonal_product_evaluator_base > Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + using Base::packet_impl; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::PacketScalar PacketScalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + product_evaluator(const XprType& xpr) + : Base(xpr.rhs(), xpr.lhs().diagonal()) + { + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const + { + enum { + StorageOrder = Rhs::Flags & RowMajorBit ? RowMajor : ColMajor + }; + return this->template packet_impl(row,col, row, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const + { + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + +}; + +// dense * diagonal +template +struct product_evaluator, ProductTag, DenseShape, DiagonalShape, typename Lhs::Scalar, typename Rhs::Scalar> + : diagonal_product_evaluator_base > +{ + typedef diagonal_product_evaluator_base > Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + using Base::packet_impl; + typedef typename Base::Scalar Scalar; + typedef typename Base::Index Index; + typedef typename Base::PacketScalar PacketScalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs().diagonal()) + { + } + + EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const + { + enum { + StorageOrder = Rhs::Flags & RowMajorBit ? RowMajor : ColMajor + }; + return this->template packet_impl(row,col, col, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const + { + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } + +}; } // end namespace internal diff --git a/test/evaluators.cpp b/test/evaluators.cpp index 69a45661f..305047a6a 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -151,19 +151,19 @@ void test_evaluators() c = a*a; copy_using_evaluator(a, prod(a,a)); VERIFY_IS_APPROX(a,c); - + // check compound assignment of products d = c; add_assign_using_evaluator(c.noalias(), prod(a,b)); d.noalias() += a*b; VERIFY_IS_APPROX(c, d); - + d = c; subtract_assign_using_evaluator(c.noalias(), prod(a,b)); d.noalias() -= a*b; VERIFY_IS_APPROX(c, d); } - + { // test product with all possible sizes int s = internal::random(1,100); @@ -458,4 +458,15 @@ void test_evaluators() VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.selfadjointView(),A), MatrixXd(A.selfadjointView()*A)); } + + { + // test diagonal shapes + VectorXd d = VectorXd::Random(6); + MatrixXd A = MatrixXd::Random(6,6), B(6,6); + A.setRandom();B.setRandom(); + + VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(d.asDiagonal(),A), MatrixXd(d.asDiagonal()*A)); + VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(A,d.asDiagonal()), MatrixXd(A*d.asDiagonal())); + + } } -- cgit v1.2.3 From d595fd31f544009e62a55d6ffc26e0b62f3147d5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 17 Feb 2014 16:11:55 +0100 Subject: Deal with automatic transposition in call_assignment, fix a few shortcomings --- Eigen/src/Core/Assign.h | 27 ++++++++++++- Eigen/src/Core/AssignEvaluator.h | 59 ++++++++++++++++++++++++++--- Eigen/src/Core/PlainObjectBase.h | 19 +++++++++- Eigen/src/Core/TriangularMatrix.h | 2 + Eigen/src/Core/products/CoeffBasedProduct.h | 4 +- 5 files changed, 101 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index cefa6f3cc..6080a83f6 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -531,6 +531,23 @@ EIGEN_STRONG_INLINE Derived& DenseBase namespace internal { +#ifdef EIGEN_TEST_EVALUATORS + +// TODO remove this class which is now useless + +template +struct assign_selector { + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { + call_assignment(dst, other.derived(), internal::assign_op()); + return dst; + } + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } +}; + +#else // EIGEN_TEST_EVALUATORS template::Flags) & EvalBeforeAssigningBit) != 0, bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) @@ -566,7 +583,7 @@ struct assign_selector { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } }; - +#endif // EIGEN_TEST_EVALUATORS } // end namespace internal template @@ -604,7 +621,11 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { +#ifdef EIGEN_TEST_EVALUATORS + return internal::assign_selector::evalTo(derived(), other.derived()); +#else return internal::assign_selector::evalTo(derived(), other.derived()); +#endif } template @@ -612,7 +633,11 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { +#ifdef EIGEN_TEST_EVALUATORS + return internal::assign_selector::evalTo(derived(), other.derived()); +#else return internal::assign_selector::evalTo(derived(), other.derived()); +#endif } } // end namespace Eigen diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index fe6fbdb9a..0a3475d83 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -656,28 +656,75 @@ template< typename DstXprType, typename SrcXprType, typename Functor, struct Assignment; -// The only purpose of this call_assignment() function is to deal with noalias() / AssumeAliasing. +// The only purpose of this call_assignment() function is to deal with noalias() / AssumeAliasing and automatic transposition. // Indeed, I (Gael) think that this concept of AssumeAliasing was a mistake, and it makes thing quite complicated. // So this intermediate function removes everything related to AssumeAliasing such that Assignment // does not has to bother about these annoying details. +template struct transpose_to_match +{ + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)) + && int(Dst::SizeAtCompileTime) != 1 + }; + + typedef typename internal::conditional, Dst>::type type; +}; + +template +void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} +template +void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} + +// Deal with AssumeAliasing +template +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) +{ + // The following initial implementation through an EvalToTemp object does not permit to + // perform deferred resizing as in 'A = A * B' when the size of 'A' as to be changed + // typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; + // Assignment::run(dst, src, func); + + // TODO we should simply do tmp(src); +#ifdef EIGEN_TEST_EVALUATORS + typename Src::PlainObject tmp(src); +#else + typename Src::PlainObject tmp(src.rows(), src.cols()); + call_assignment(tmp.noalias(), src); +#endif + + // resizing + dst.resize(tmp.rows(), tmp.cols()); + call_assignment(dst.noalias(), tmp, func); + TRACK; +} + template -void call_assignment(Dst& dst, const Src& src, const Func& func) +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) { - typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; - Assignment::run(dst, src, func); + Assignment::type,Src,Func>::run(dst, src, func); } // by-pass AssumeAliasing +// FIXME the const version should probably not be needed template class StorageBase, typename Src, typename Func> void call_assignment(const NoAlias& dst, const Src& src, const Func& func) { - Assignment::run(dst.expression(), src, func); + Assignment::type,Src,Func>::run(dst.expression(), src, func); } template class StorageBase, typename Src, typename Func> void call_assignment(NoAlias& dst, const Src& src, const Func& func) { - Assignment::run(dst.expression(), src, func); + Assignment::type,Src,Func>::run(dst.expression(), src, func); } // Generic Dense to Dense assignment diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 0305066ba..8eccbfbd0 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -639,6 +639,18 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \internal */ +#ifdef EIGEN_TEST_EVALUATORS + // aliasing is dealt once in internall::call_assignment + // so at this stage we have to assume aliasing... and resising has to be done later. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) + { + internal::call_assignment(this->derived(), other.derived()); + return this->derived(); + return this->derived(); + } +#else template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) @@ -654,7 +666,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } - +#endif /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * @@ -669,7 +681,12 @@ class PlainObjectBase : public internal::dense_xpr_base::type //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. +#ifdef EIGEN_TEST_EVALUATORS + internal::call_assignment(this->noalias(), other.derived()); + return this->derived(); +#else return internal::assign_selector::run(this->derived(), other.derived()); +#endif } template diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index d413ec2e9..2b1c236b9 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -1235,6 +1235,7 @@ struct triangular_assignment_loop } // end namespace internal +#ifdef EIGEN_TEST_EVALUATORS /** Assigns a triangular or selfadjoint matrix to a dense matrix. * If the matrix is triangular, the opposite part is set to zero. */ template @@ -1244,6 +1245,7 @@ void TriangularBase::evalToLazy(MatrixBase &other) const other.derived().resize(this->rows(), this->cols()); internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); } +#endif #endif // EIGEN_ENABLE_EVALUATORS diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 5f8182aa9..de06108da 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -47,8 +47,8 @@ struct traits > typename traits<_RhsNested>::Index>::type Index; enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, + LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, + RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, LhsFlags = traits<_LhsNested>::Flags, RhsFlags = traits<_RhsNested>::Flags, -- cgit v1.2.3 From 873401032bf91e092413cdd7b56848f7b485490a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 17 Feb 2014 19:00:45 +0100 Subject: Fix scalar * product optimization when 'product' includes a selfadjoint matrix --- Eigen/src/Core/SelfAdjointView.h | 7 +++++++ Eigen/src/Core/TriangularMatrix.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index dd8eb25f8..2cc1815fd 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -132,6 +132,13 @@ template class SelfAdjointView { return Product(lhs.derived(),rhs); } + + friend EIGEN_DEVICE_FUNC + const SelfAdjointView,MatrixType>,UpLo> + operator*(const Scalar& s, const SelfAdjointView& mat) + { + return (s*mat.nestedExpression()).template selfadjointView(); + } #else // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 2b1c236b9..c5f137ab8 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -62,6 +62,14 @@ template class TriangularBase : public EigenBase inline Index outerStride() const { return derived().outerStride(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); } + + // dummy resize function + void resize(Index nbRows, Index nbCols) + { + EIGEN_UNUSED_VARIABLE(nbRows); + EIGEN_UNUSED_VARIABLE(nbCols); + eigen_assert(nbRows==rows() && nbCols==nbCols); + } EIGEN_DEVICE_FUNC inline Scalar coeff(Index row, Index col) const { return derived().coeff(row,col); } -- cgit v1.2.3 From 2d136d3d7f0623189e42be44d45e1353d1cde93e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 10:52:00 +0100 Subject: Get rid of SeflCwiseBinaryOp --- Eigen/src/Core/ArrayBase.h | 54 ++++++++++++++++++++++++++++++++++++++ Eigen/src/Core/SelfCwiseBinaryOp.h | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index 2c9ace4a7..c528de733 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -177,6 +177,59 @@ template class ArrayBase {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; +#ifdef EIGEN_TEST_EVALUATORS +/** replaces \c *this by \c *this - \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator-=(const ArrayBase &other) +{ + call_assignment(derived(), other.derived(), internal::sub_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this + \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator+=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator*=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::mul_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this / \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_STRONG_INLINE Derived & +ArrayBase::operator/=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::div_assign_op()); + return derived(); +} +#else // EIGEN_TEST_EVALUATORS /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this @@ -232,6 +285,7 @@ ArrayBase::operator/=(const ArrayBase& other) tmp = other.derived(); return derived(); } +#endif } // end namespace Eigen diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 65864adf8..ae7f9b887 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -12,6 +12,8 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS + /** \class SelfCwiseBinaryOp * \ingroup Core_Module * @@ -179,6 +181,51 @@ template class SelfCwiseBinaryOp SelfCwiseBinaryOp& operator=(const SelfCwiseBinaryOp&); }; +#endif // EIGEN_TEST_EVALUATORS + +#ifdef EIGEN_TEST_EVALUATORS +template +inline Derived& DenseBase::operator*=(const Scalar& other) +{ + typedef typename Derived::PlainObject PlainObject; + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::mul_assign_op()); + return derived(); +} + +template +inline Derived& ArrayBase::operator+=(const Scalar& other) +{ + typedef typename Derived::PlainObject PlainObject; + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::add_assign_op()); + return derived(); +} + +template +inline Derived& ArrayBase::operator-=(const Scalar& other) +{ + typedef typename Derived::PlainObject PlainObject; + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::sub_assign_op()); + return derived(); +} + +template +inline Derived& DenseBase::operator/=(const Scalar& other) +{ + typedef typename Derived::PlainObject PlainObject; + + typedef typename internal::conditional::IsInteger, + internal::div_assign_op, + internal::mul_assign_op >::type AssignOp; + + Scalar actual_other; + if(NumTraits::IsInteger) actual_other = other; + else actual_other = Scalar(1)/other; + + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),actual_other), AssignOp()); + + return derived(); +} +#else template inline Derived& DenseBase::operator*=(const Scalar& other) { @@ -220,6 +267,7 @@ inline Derived& DenseBase::operator/=(const Scalar& other) tmp = PlainObject::Constant(rows(),cols(), actual_other); return derived(); } +#endif } // end namespace Eigen -- cgit v1.2.3 From 551bf5c66a3f29c8ac1f24f8439a6b85d0da79ac Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 10:52:26 +0100 Subject: Get rid of DiagonalProduct --- Eigen/src/Core/DiagonalProduct.h | 12 ++++++++++++ Eigen/src/Core/MatrixBase.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index c03a0c2e1..f5539df13 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -13,6 +13,7 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template struct traits > @@ -124,6 +125,17 @@ MatrixBase::operator*(const DiagonalBase &a_diagonal) { return DiagonalProduct(derived(), a_diagonal.derived()); } +#else // EIGEN_TEST_EVALUATORS +/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. + */ +template +template +inline const Product +MatrixBase::operator*(const DiagonalBase &a_diagonal) const +{ + return Product(derived(),a_diagonal.derived()); +} +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 37e7408a4..6453145d0 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -215,10 +215,17 @@ template class MatrixBase template void applyOnTheRight(const EigenBase& other); +#ifndef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC const DiagonalProduct operator*(const DiagonalBase &diagonal) const; +#else // EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + const Product + operator*(const DiagonalBase &diagonal) const; +#endif // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC -- cgit v1.2.3 From 573c587e3d66c8151f6523433d853664e1fa7667 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 10:53:14 +0100 Subject: New design for handling automatic transposition --- Eigen/src/Core/AssignEvaluator.h | 61 +++++++++++++++++++++++----------------- Eigen/src/Core/PlainObjectBase.h | 2 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 0a3475d83..d5745f20c 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -661,34 +661,21 @@ struct Assignment; // So this intermediate function removes everything related to AssumeAliasing such that Assignment // does not has to bother about these annoying details. -template struct transpose_to_match -{ - enum { - NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)) - && int(Dst::SizeAtCompileTime) != 1 - }; - - typedef typename internal::conditional, Dst>::type type; -}; - template void call_assignment(Dst& dst, const Src& src) -{ +{TRACK; call_assignment(dst, src, internal::assign_op()); } template void call_assignment(const Dst& dst, const Src& src) -{ +{TRACK; call_assignment(dst, src, internal::assign_op()); } // Deal with AssumeAliasing template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) -{ +{TRACK; // The following initial implementation through an EvalToTemp object does not permit to // perform deferred resizing as in 'A = A * B' when the size of 'A' as to be changed // typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; @@ -699,40 +686,62 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable typename Src::PlainObject tmp(src); #else typename Src::PlainObject tmp(src.rows(), src.cols()); - call_assignment(tmp.noalias(), src); + call_assignment_no_alias(tmp, src, internal::assign_op()); #endif // resizing dst.resize(tmp.rows(), tmp.cols()); - call_assignment(dst.noalias(), tmp, func); - TRACK; + call_assignment_no_alias(dst, tmp, func); } template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) -{ - Assignment::type,Src,Func>::run(dst, src, func); +{TRACK; + // There is no explicit no-aliasing, so we must resize here: + dst.resize(src.rows(), src.cols()); + call_assignment_no_alias(dst, src, func); } // by-pass AssumeAliasing // FIXME the const version should probably not be needed +// When there is no aliasing, we require that 'dst' has been properly resized template class StorageBase, typename Src, typename Func> void call_assignment(const NoAlias& dst, const Src& src, const Func& func) -{ - Assignment::type,Src,Func>::run(dst.expression(), src, func); +{TRACK; + call_assignment_no_alias(dst.expression(), src, func); } template class StorageBase, typename Src, typename Func> void call_assignment(NoAlias& dst, const Src& src, const Func& func) -{ - Assignment::type,Src,Func>::run(dst.expression(), src, func); +{TRACK; + call_assignment_no_alias(dst.expression(), src, func); +} + + +template +void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{TRACK; + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)) + && int(Dst::SizeAtCompileTime) != 1 + }; + + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; + typedef typename internal::conditional, Dst&>::type ActualDstType; + ActualDstType actualDst(dst); + + Assignment::run(actualDst, src, func); } + // Generic Dense to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) - { + {TRACK; // TODO check whether this is the right place to perform these checks: enum{ SameType = internal::is_same::value diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 8eccbfbd0..4f456804c 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -682,7 +682,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. #ifdef EIGEN_TEST_EVALUATORS - internal::call_assignment(this->noalias(), other.derived()); + internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); return this->derived(); #else return internal::assign_selector::run(this->derived(), other.derived()); -- cgit v1.2.3 From a08cba6b5f51db2338da58d54cda7e04cc24e372 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 11:03:59 +0100 Subject: Move is_diagonal to XprHelper, forward declare Ref --- Eigen/Core | 6 +++--- Eigen/src/Core/Ref.h | 4 ---- Eigen/src/Core/Stride.h | 4 ++-- Eigen/src/Core/util/ForwardDeclarations.h | 5 +++++ Eigen/src/Core/util/Meta.h | 12 ------------ Eigen/src/Core/util/XprHelper.h | 12 ++++++++++++ 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index cdc2f2d46..c1d168ec4 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -277,8 +277,8 @@ using std::ptrdiff_t; */ #include "src/Core/util/Constants.h" -#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" +#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" @@ -340,12 +340,12 @@ using std::ptrdiff_t; #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" -#include "src/Core/MapBase.h" #include "src/Core/Stride.h" +#include "src/Core/MapBase.h" #include "src/Core/Map.h" +#include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" -#include "src/Core/Ref.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 00d9e6d2b..ce9e82913 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -12,10 +12,6 @@ namespace Eigen { -template class RefBase; -template,OuterStride<> >::type > class Ref; - /** \class Ref * \ingroup Core_Module * diff --git a/Eigen/src/Core/Stride.h b/Eigen/src/Core/Stride.h index d3d454e4e..187774978 100644 --- a/Eigen/src/Core/Stride.h +++ b/Eigen/src/Core/Stride.h @@ -86,7 +86,7 @@ class Stride /** \brief Convenience specialization of Stride to specify only an inner stride * See class Map for some examples */ -template +template class InnerStride : public Stride<0, Value> { typedef Stride<0, Value> Base; @@ -98,7 +98,7 @@ class InnerStride : public Stride<0, Value> /** \brief Convenience specialization of Stride to specify only an outer stride * See class Map for some examples */ -template +template class OuterStride : public Stride { typedef Stride Base; diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 3bc151229..db0e2b033 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -121,7 +121,12 @@ template::has_write_access ? WriteAccessors : ReadOnlyAccessors > class MapBase; template class Stride; +template class InnerStride; +template class OuterStride; template > class Map; +template class RefBase; +template,OuterStride<> >::type > class Ref; template class TriangularBase; template class TriangularView; diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index e4e4d4a87..559928a92 100644 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -246,18 +246,6 @@ template struct scalar_product_traits, T> // typedef typename scalar_product_traits::type, typename remove_all::type>::ReturnType type; // }; -template struct is_diagonal -{ enum { ret = false }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - -template struct is_diagonal > -{ enum { ret = true }; }; - } // end namespace internal namespace numext { diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index f210344d3..7ea70450f 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -502,6 +502,18 @@ struct is_lvalue bool(traits::Flags & LvalueBit) }; }; +template struct is_diagonal +{ enum { ret = false }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + +template struct is_diagonal > +{ enum { ret = true }; }; + } // end namespace internal } // end namespace Eigen -- cgit v1.2.3 From 1b5de5a37b47ef2738e5bdf4135777f00ac5967d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 13:30:16 +0100 Subject: Add evaluator for Ref --- Eigen/src/Core/CoreEvaluators.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index ef900e236..d02bac0a8 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -587,7 +587,7 @@ struct evaluator > CoeffReturnType coeff(Index index) const { return coeff(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + RowsAtCompileTime == 1 ? index : 0); } Scalar& coeffRef(Index row, Index col) @@ -598,7 +598,7 @@ struct evaluator > Scalar& coeffRef(Index index) { return coeffRef(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + RowsAtCompileTime == 1 ? index : 0); } template @@ -612,7 +612,7 @@ struct evaluator > PacketReturnType packet(Index index) const { return packet(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + RowsAtCompileTime == 1 ? index : 0); } template @@ -626,8 +626,8 @@ struct evaluator > void writePacket(Index index, const PacketScalar& x) { return writePacket(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0, - x); + RowsAtCompileTime == 1 ? index : 0, + x); } protected: @@ -647,6 +647,19 @@ struct evaluator > { } }; +// -------------------- Ref -------------------- + +template +struct evaluator > + : public evaluator > > +{ + typedef Ref XprType; + + evaluator(const XprType& map) + : evaluator >(map) + { } +}; + // -------------------- Block -------------------- template Date: Tue, 18 Feb 2014 13:31:44 +0100 Subject: Finally, the simplest remains to deffer resizing at the latest --- Eigen/src/Core/AssignEvaluator.h | 10 +++------- Eigen/src/Core/NoAlias.h | 8 +++----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index d5745f20c..f6e1abccd 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -676,12 +676,7 @@ void call_assignment(const Dst& dst, const Src& src) template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) {TRACK; - // The following initial implementation through an EvalToTemp object does not permit to - // perform deferred resizing as in 'A = A * B' when the size of 'A' as to be changed - // typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; - // Assignment::run(dst, src, func); - // TODO we should simply do tmp(src); #ifdef EIGEN_TEST_EVALUATORS typename Src::PlainObject tmp(src); #else @@ -697,8 +692,6 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) {TRACK; - // There is no explicit no-aliasing, so we must resize here: - dst.resize(src.rows(), src.cols()); call_assignment_no_alias(dst, src, func); } @@ -728,6 +721,9 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) && int(Dst::SizeAtCompileTime) != 1 }; + dst.resize(NeedToTranspose ? src.cols() : src.rows(), + NeedToTranspose ? src.rows() : src.cols()); + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; typedef typename internal::conditional, Dst&>::type ActualDstType; ActualDstType actualDst(dst); diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 412e37258..fe6dded60 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -40,9 +40,7 @@ class NoAlias EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { - // TODO either call resize here or call "call_assignment" through m_expression.lazyAssign() ?? - m_expression.resize(other.derived().rows(), other.derived().cols()); - call_assignment(*this, other.derived(), internal::assign_op()); + call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); return m_expression; } @@ -50,7 +48,7 @@ class NoAlias EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { - call_assignment(*this, other.derived(), internal::add_assign_op()); + call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); return m_expression; } @@ -58,7 +56,7 @@ class NoAlias EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { - call_assignment(*this, other.derived(), internal::sub_assign_op()); + call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } -- cgit v1.2.3 From 7002aa858f3bd42e98ae1c2317aefe39338fab3e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 13:32:30 +0100 Subject: Support Product::coeff(0,0) even for dynamic matrices --- Eigen/src/Core/Product.h | 26 ++++++++++++++++---------- Eigen/src/Core/ProductEvaluators.h | 22 +++++++--------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index d64fbae35..12726ed12 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -109,16 +109,6 @@ public: { return typename internal::evaluator::type(derived()).coeff(0,0); } - - Scalar coeff(Index row, Index col) const - { - return typename internal::evaluator::type(derived()).coeff(row,col); - } - - Scalar coeff(Index i) const - { - return typename internal::evaluator::type(derived()).coeff(i); - } }; } // namespace internal @@ -132,6 +122,22 @@ class ProductImpl typedef typename internal::dense_product_base Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + + Scalar coeff(Index row, Index col) const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + + return typename internal::evaluator::type(derived()).coeff(row,col); + } + + Scalar coeff(Index i) const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + + return typename internal::evaluator::type(derived()).coeff(i); + } }; /*************************************************************************** diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index d991ff8b5..e0cfb56bb 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -270,7 +270,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - { + {TRACK; // TODO bypass GeneralProduct class GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); } @@ -705,7 +705,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - {// SelfadjointProductMatrix + { // TODO bypass SelfadjointProductMatrix class SelfadjointProductMatrix(lhs.nestedExpression(),rhs).scaleAndAddTo(dst, alpha); } @@ -739,7 +739,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - {//SelfadjointProductMatrix + { // TODO bypass SelfadjointProductMatrix class SelfadjointProductMatrix(lhs,rhs.nestedExpression()).scaleAndAddTo(dst, alpha); } @@ -825,6 +825,8 @@ struct product_evaluator, ProductTag, DiagonalSha typedef Product XprType; typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) @@ -839,9 +841,6 @@ struct product_evaluator, ProductTag, DiagonalSha template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { - enum { - StorageOrder = Rhs::Flags & RowMajorBit ? RowMajor : ColMajor - }; return this->template packet_impl(row,col, row, typename internal::conditional::type()); } @@ -849,9 +848,6 @@ struct product_evaluator, ProductTag, DiagonalSha template EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const { - enum { - StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor - }; return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } @@ -873,6 +869,8 @@ struct product_evaluator, ProductTag, DenseShape, typedef Product XprType; typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) @@ -887,9 +885,6 @@ struct product_evaluator, ProductTag, DenseShape, template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { - enum { - StorageOrder = Rhs::Flags & RowMajorBit ? RowMajor : ColMajor - }; return this->template packet_impl(row,col, col, typename internal::conditional::type()); } @@ -897,9 +892,6 @@ struct product_evaluator, ProductTag, DenseShape, template EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const { - enum { - StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor - }; return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } -- cgit v1.2.3 From 06545058bbdeec4713b9b31c5018335660796076 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 13:33:04 +0100 Subject: Temporary workaround for permutations --- Eigen/src/Core/PermutationMatrix.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 1297b8413..6a26af3a5 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -532,6 +532,7 @@ namespace internal { template struct traits > + : traits { typedef typename MatrixType::PlainObject ReturnType; }; -- cgit v1.2.3 From 99e27916cfd1381aab50850611905335c288ee40 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 14:26:25 +0100 Subject: Fix all()/any() for evaluators --- Eigen/src/Core/BooleanRedux.h | 46 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/BooleanRedux.h b/Eigen/src/Core/BooleanRedux.h index be9f48a8c..f0b68f470 100644 --- a/Eigen/src/Core/BooleanRedux.h +++ b/Eigen/src/Core/BooleanRedux.h @@ -17,10 +17,18 @@ namespace internal { template struct all_unroller { +#ifdef EIGEN_TEST_EVALUATORS + typedef typename Derived::ExpressionTraits Traits; + enum { + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime + }; +#else enum { col = (UnrollCount-1) / Derived::RowsAtCompileTime, row = (UnrollCount-1) % Derived::RowsAtCompileTime }; +#endif static inline bool run(const Derived &mat) { @@ -43,11 +51,19 @@ struct all_unroller template struct any_unroller { +#ifdef EIGEN_TEST_EVALUATORS + typedef typename Derived::ExpressionTraits Traits; + enum { + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime + }; +#else enum { col = (UnrollCount-1) / Derived::RowsAtCompileTime, row = (UnrollCount-1) % Derived::RowsAtCompileTime }; - +#endif + static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); @@ -84,6 +100,19 @@ inline bool DenseBase::all() const && NumTraits::AddCost != Dynamic && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::evaluator::type Evaluator; + Evaluator evaluator(derived()); + if(unroll) + return internal::all_unroller::run(evaluator); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (!evaluator.coeff(i, j)) return false; + return true; + } +#else if(unroll) return internal::all_unroller::run(derived()); else @@ -93,6 +122,7 @@ inline bool DenseBase::all() const if (!coeff(i, j)) return false; return true; } +#endif } /** \returns true if at least one coefficient is true @@ -108,6 +138,19 @@ inline bool DenseBase::any() const && NumTraits::AddCost != Dynamic && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::evaluator::type Evaluator; + Evaluator evaluator(derived()); + if(unroll) + return internal::any_unroller::run(evaluator); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (evaluator.coeff(i, j)) return true; + return false; + } +#else if(unroll) return internal::any_unroller::run(derived()); else @@ -117,6 +160,7 @@ inline bool DenseBase::any() const if (coeff(i, j)) return true; return false; } +#endif } /** \returns the number of coefficients which evaluate to true -- cgit v1.2.3 From 0543cb51b58bfc5130bcb0b83969f2854f30d58e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 14:51:41 +0100 Subject: Product::coeff method are also OK for lazy products (including diagonal products) --- Eigen/src/Core/Product.h | 21 ++++++++++++++++----- Eigen/src/Core/util/StaticAssert.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 12726ed12..31730983f 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -117,27 +117,38 @@ template class ProductImpl : public internal::dense_product_base { - typedef Product Derived; + typedef Product Derived; + public: typedef typename internal::dense_product_base Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + protected: + enum { + IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && + (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), + EnableCoeff = IsOneByOne || Option==LazyProduct + }; + public: + Scalar coeff(Index row, Index col) const { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); return typename internal::evaluator::type(derived()).coeff(row,col); } Scalar coeff(Index i) const { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); return typename internal::evaluator::type(derived()).coeff(i); } + + }; /*************************************************************************** diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index b9b1ee02a..f5691826e 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -84,6 +84,7 @@ THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY, YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT, THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS, + THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS, THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL, THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES, YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED, -- cgit v1.2.3 From 82c066b3c4a0d64962ad0bf268bf7a4a28b2704b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 15:44:32 +0100 Subject: Cleaning --- Eigen/src/Core/AssignEvaluator.h | 16 ++++++++-------- Eigen/src/Core/ProductEvaluators.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index f6e1abccd..cf4db8de5 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -663,19 +663,19 @@ struct Assignment; template void call_assignment(Dst& dst, const Src& src) -{TRACK; +{ call_assignment(dst, src, internal::assign_op()); } template void call_assignment(const Dst& dst, const Src& src) -{TRACK; +{ call_assignment(dst, src, internal::assign_op()); } // Deal with AssumeAliasing template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) -{TRACK; +{ #ifdef EIGEN_TEST_EVALUATORS typename Src::PlainObject tmp(src); @@ -691,7 +691,7 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) -{TRACK; +{ call_assignment_no_alias(dst, src, func); } @@ -700,19 +700,19 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable // When there is no aliasing, we require that 'dst' has been properly resized template class StorageBase, typename Src, typename Func> void call_assignment(const NoAlias& dst, const Src& src, const Func& func) -{TRACK; +{ call_assignment_no_alias(dst.expression(), src, func); } template class StorageBase, typename Src, typename Func> void call_assignment(NoAlias& dst, const Src& src, const Func& func) -{TRACK; +{ call_assignment_no_alias(dst.expression(), src, func); } template void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) -{TRACK; +{ enum { NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". @@ -737,7 +737,7 @@ template< typename DstXprType, typename SrcXprType, typename Functor, typename S struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) - {TRACK; + { // TODO check whether this is the right place to perform these checks: enum{ SameType = internal::is_same::value diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index e0cfb56bb..113bcd618 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -270,7 +270,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - {TRACK; + { // TODO bypass GeneralProduct class GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); } -- cgit v1.2.3 From 8169c6ac59ce78a7340ebae40f8eabe9df1c8f62 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 16:57:25 +0100 Subject: Simplify implementation of coeff-based products to fully exploit our reduxion mechanisms. If this results in performance regressions, then we should optimize reduxion rather than somehow duplicate the code. --- Eigen/src/Core/ProductEvaluators.h | 180 ++++++------------------------------- 1 file changed, 27 insertions(+), 153 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 113bcd618..67d0dc80c 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -333,8 +333,11 @@ struct product_evaluator, ProductTag, DenseShape, typedef CoeffBasedProduct CoeffBasedProductType; product_evaluator(const XprType& xpr) - : m_lhsImpl(xpr.lhs()), - m_rhsImpl(xpr.rhs()), + : m_lhs(xpr.lhs()), + m_rhs(xpr.rhs()), + m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! + m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, + // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. m_innerDim(xpr.lhs().cols()) { } @@ -355,31 +358,32 @@ struct product_evaluator, ProductTag, DenseShape, CanVectorizeInner = traits::CanVectorizeInner, Flags = traits::Flags }; - - typedef typename evaluator::type LhsEtorType; - typedef typename evaluator::type RhsEtorType; - typedef etor_product_coeff_impl CoeffImpl; + typedef typename internal::nested_eval::type LhsNested; + typedef typename internal::nested_eval::type RhsNested; + + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + typedef typename evaluator::type LhsEtorType; + typedef typename evaluator::type RhsEtorType; + const CoeffReturnType coeff(Index row, Index col) const { - Scalar res; - CoeffImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); - return res; + // TODO check performance regression wrt to Eigen 3.2 which has special handling of this function + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); } /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, * which is why we don't set the LinearAccessBit. + * TODO: this seems possible when the result is a vector */ const CoeffReturnType coeff(Index index) const { - Scalar res; const Index row = RowsAtCompileTime == 1 ? 0 : index; const Index col = RowsAtCompileTime == 1 ? index : 0; - CoeffImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); - return res; + // TODO check performance regression wrt to Eigen 3.2 which has special handling of this function + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); } template @@ -389,13 +393,17 @@ struct product_evaluator, ProductTag, DenseShape, typedef etor_product_packet_impl PacketImpl; + PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); return res; } protected: - typename evaluator::type m_lhsImpl; - typename evaluator::type m_rhsImpl; + const LhsNested m_lhs; + const RhsNested m_rhs; + + LhsEtorType m_lhsImpl; + RhsEtorType m_rhsImpl; // TODO: Get rid of m_innerDim if known at compile time Index m_innerDim; @@ -413,143 +421,9 @@ struct product_evaluator, LazyCoeffBasedProduc {} }; -/*************************************************************************** -* Normal product .coeff() implementation (with meta-unrolling) -***************************************************************************/ - -/************************************** -*** Scalar path - no vectorization *** -**************************************/ - -template -struct etor_product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, RetScalar &res) - { - etor_product_coeff_impl::run(row, col, lhs, rhs, innerDim, res); - res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); - } -}; - -template -struct etor_product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, RetScalar &res) - { - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - } -}; - -template -struct etor_product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, RetScalar& res) - { - eigen_assert(innerDim>0 && "you are using a non initialized matrix"); - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - for(Index i = 1; i < innerDim; ++i) - res += lhs.coeff(row, i) * rhs.coeff(i, col); - } -}; - -/******************************************* -*** Scalar path with inner vectorization *** -*******************************************/ - -template -struct etor_product_coeff_vectorized_unroller -{ - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, typename Lhs::PacketScalar &pres) - { - etor_product_coeff_vectorized_unroller::run(row, col, lhs, rhs, innerDim, pres); - pres = padd(pres, pmul( lhs.template packet(row, UnrollingIndex) , rhs.template packet(UnrollingIndex, col) )); - } -}; - -template -struct etor_product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, typename Lhs::PacketScalar &pres) - { - pres = pmul(lhs.template packet(row, 0) , rhs.template packet(0, col)); - } -}; - -template -struct etor_product_coeff_impl -{ - typedef typename Lhs::PacketScalar Packet; - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, RetScalar &res) - { - Packet pres; - etor_product_coeff_vectorized_unroller::run(row, col, lhs, rhs, innerDim, pres); - res = predux(pres); - } -}; - -template -struct etor_product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -// NOTE the 3 following specializations are because taking .col(0) on a vector is a bit slower -// NOTE maybe they are now useless since we have a specialization for Block -template -struct etor_product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -template -struct etor_product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct etor_product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct etor_product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, typename Lhs::Scalar &res) - { - etor_product_coeff_vectorized_dyn_selector::run(row, col, lhs, rhs, innerDim, res); - } -}; - -/******************* -*** Packet path *** -*******************/ +/**************************************** +*** Coeff based product, Packet path *** +****************************************/ template struct etor_product_packet_impl -- cgit v1.2.3 From 5b78780deffd4a5728cfc6ae5371f56e038e2ac0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 18 Feb 2014 17:43:16 +0100 Subject: Add evaluator shortcut for triangular ?= product --- Eigen/src/Core/TriangularMatrix.h | 70 +++++++++++++++++++++- .../Core/products/GeneralMatrixMatrixTriangular.h | 12 +++- test/product_notemporary.cpp | 3 +- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index c5f137ab8..ffa2faeaa 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -233,6 +233,24 @@ template class TriangularView EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.innerStride(); } +#ifdef EIGEN_TEST_EVALUATORS + + /** \sa MatrixBase::operator+=() */ + template + EIGEN_DEVICE_FUNC + TriangularView& operator+=(const DenseBase& other) { + internal::call_assignment_no_alias(*this, other.derived(), internal::add_assign_op()); + return *this; + } + /** \sa MatrixBase::operator-=() */ + template + EIGEN_DEVICE_FUNC + TriangularView& operator-=(const DenseBase& other) { + internal::call_assignment_no_alias(*this, other.derived(), internal::sub_assign_op()); + return *this; + } + +#else /** \sa MatrixBase::operator+=() */ template EIGEN_DEVICE_FUNC @@ -241,6 +259,7 @@ template class TriangularView template EIGEN_DEVICE_FUNC TriangularView& operator-=(const DenseBase& other) { return *this = m_matrix - other.derived(); } +#endif /** \sa MatrixBase::operator*=() */ EIGEN_DEVICE_FUNC TriangularView& operator*=(const typename internal::traits::Scalar& other) { return *this = m_matrix * other; } @@ -527,12 +546,18 @@ template class TriangularView #endif // EIGEN_TEST_EVALUATORS - protected: +#ifdef EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TriangularView& _assignProduct(const ProductType& prod, const Scalar& alpha); + protected: +#else + protected: template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase& prod, const Scalar& alpha); - +#endif MatrixTypeNested m_matrix; }; @@ -720,7 +745,7 @@ template inline TriangularView& TriangularView::operator=(const MatrixBase& other) { - internal::call_assignment(*this, other.template triangularView(), internal::assign_op()); + internal::call_assignment_no_alias(*this, other.derived(), internal::assign_op()); return *this; } @@ -1253,6 +1278,45 @@ void TriangularBase::evalToLazy(MatrixBase &other) const other.derived().resize(this->rows(), this->cols()); internal::call_triangular_assignment_loop(other.derived(), derived().nestedExpression()); } + +namespace internal { + +// Triangular = Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::assign_op, Dense2Triangular, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst.setZero(); + dst._assignProduct(src, 1); + } +}; + +// Triangular += Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Triangular, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + dst._assignProduct(src, 1); + } +}; + +// Triangular -= Product +template< typename DstXprType, typename Lhs, typename Rhs, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Triangular, Scalar> +{ + typedef Product SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + dst._assignProduct(src, -1); + } +}; + + +} // end namespace internal #endif #endif // EIGEN_ENABLE_EVALUATORS diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 87bd36bc3..46be46f85 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -264,6 +264,16 @@ struct general_product_to_triangular_selector } }; +#ifdef EIGEN_TEST_EVALUATORS +template +template +TriangularView& TriangularView::_assignProduct(const ProductType& prod, const Scalar& alpha) +{ + general_product_to_triangular_selector::InnerSize==1>::run(m_matrix.const_cast_derived(), prod, alpha); + + return *this; +} +#else template template TriangularView& TriangularView::assignProduct(const ProductBase& prod, const Scalar& alpha) @@ -272,7 +282,7 @@ TriangularView& TriangularView::assignProduct( return *this; } - +#endif } // end namespace Eigen #endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index 258d238e2..deb494c96 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -114,8 +114,7 @@ template void product_notemporary(const MatrixType& m) 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 ... - //VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 ); + VERIFY_EVALUATION_COUNT( m3.col(0).template head<5>() * m3.col(0).transpose() + m3.col(0).template head<5>() * m3.col(0).transpose(), 0 ); // Check matrix * vectors VERIFY_EVALUATION_COUNT( cvres.noalias() = m1 * cv1, 0 ); -- cgit v1.2.3 From c16b80746aaa0bb865d55b2d1cefac0f54f7cd3e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 11:30:58 +0100 Subject: isApprox must honors nested_eval --- Eigen/src/Core/Fuzzy.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index f9a88dd3c..9c8d10683 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -23,8 +23,13 @@ struct isApprox_selector static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { EIGEN_USING_STD_MATH(min); +#ifdef EIGEN_TEST_EVALUATORS + typename internal::nested_eval::type nested(x); + typename internal::nested_eval::type otherNested(y); +#else typename internal::nested::type nested(x); typename internal::nested::type otherNested(y); +#endif return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; -- cgit v1.2.3 From b3a07eecc5ad19f418f15d70d1517f8b7e07dc1b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 11:32:04 +0100 Subject: Fix CoeffReadCost of products to handle Dynamic costs --- Eigen/src/Core/products/CoeffBasedProduct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index de06108da..77f291ab9 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -90,7 +90,7 @@ struct traits > // TODO enable vectorization for mixed types | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), - CoeffReadCost = InnerSize == Dynamic ? Dynamic + CoeffReadCost = (InnerSize == Dynamic || LhsCoeffReadCost==Dynamic || RhsCoeffReadCost==Dynamic || NumTraits::AddCost==Dynamic || NumTraits::MulCost==Dynamic) ? Dynamic : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + (InnerSize - 1) * NumTraits::AddCost, -- cgit v1.2.3 From ccc41128fb936563651a3c5b25bfc80f303710bf Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 11:33:29 +0100 Subject: Add a Solve expression for uniform treatment of solve() methods. --- Eigen/Core | 3 + Eigen/src/Core/CoreEvaluators.h | 4 +- Eigen/src/Core/Solve.h | 145 ++++++++++++++++++++++++++++++ Eigen/src/Core/TriangularMatrix.h | 17 ++++ Eigen/src/Core/util/ForwardDeclarations.h | 3 +- 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 Eigen/src/Core/Solve.h diff --git a/Eigen/Core b/Eigen/Core index c1d168ec4..e00cd7a16 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -361,6 +361,9 @@ using std::ptrdiff_t; #include "src/Core/Flagged.h" #include "src/Core/ProductBase.h" #include "src/Core/GeneralProduct.h" +#ifdef EIGEN_ENABLE_EVALUATORS +#include "src/Core/Solve.h" +#endif #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index d02bac0a8..726a6854a 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -495,14 +495,14 @@ struct evaluator > PacketScalar packet(Index row, Index col) const { return m_functor.packetOp(m_lhsImpl.template packet(row, col), - m_rhsImpl.template packet(row, col)); + m_rhsImpl.template packet(row, col)); } template PacketScalar packet(Index index) const { return m_functor.packetOp(m_lhsImpl.template packet(index), - m_rhsImpl.template packet(index)); + m_rhsImpl.template packet(index)); } protected: diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h new file mode 100644 index 000000000..2da2aff56 --- /dev/null +++ b/Eigen/src/Core/Solve.h @@ -0,0 +1,145 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +template class SolveImpl; + +/** \class Solve + * \ingroup Core_Module + * + * \brief Pseudo expression representing a solving operation + * + * \tparam Decomposition the type of the matrix or decomposion object + * \tparam Rhstype the type of the right-hand side + * + * This class represents an expression of A.solve(B) + * and most of the time this is the only way it is used. + * + */ +namespace internal { + +// this solve_traits class permits to determine the evaluation type with respect to storage kind (Dense vs Sparse) +template struct solve_traits; + +template +struct solve_traits +{ + typedef typename Decomposition::MatrixType MatrixType; + typedef Matrix PlainObject; +}; + +template +struct traits > + : traits::StorageKind>::PlainObject> +{ + typedef typename solve_traits::StorageKind>::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = Dynamic + }; +}; + +} + + +template +class Solve : public SolveImpl::StorageKind> +{ +public: + typedef typename RhsType::Index Index; + typedef typename internal::traits::PlainObject PlainObject; + + Solve(const Decomposition &dec, const RhsType &rhs) + : m_dec(dec), m_rhs(rhs) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_dec.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const Decomposition& dec() const { return m_dec; } + EIGEN_DEVICE_FUNC const RhsType& rhs() const { return m_rhs; } + +protected: + const Decomposition &m_dec; + const RhsType &m_rhs; +}; + + +// Specilaization of the Solve expression for dense results +template +class SolveImpl + : public MatrixBase > +{ + typedef Solve Derived; + +public: + + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + + +namespace internal { + +// Evaluator of Solve -> eval into a temporary +template +struct evaluator > + : public evaluator::PlainObject>::type +{ + typedef Solve SolveType; + typedef typename SolveType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const SolveType& solve) + : m_result(solve.rows(), solve.cols()) + { + ::new (static_cast(this)) Base(m_result); + solve.dec()._solve_impl(solve.rhs(), m_result); + } + +protected: + PlainObject m_result; +}; + +// Specialization for "dst = dec.solve(rhs)" +// NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere +template +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Solve SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + // FIXME shall we resize dst here? + src.dec()._solve_impl(src.rhs(), dst); + } +}; + +} // end namepsace internal + +} // end namespace Eigen + +#endif // EIGEN_SOLVE_H diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index ffa2faeaa..76ba76d5f 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -437,11 +437,19 @@ template class TriangularView EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const; +#ifdef EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + inline const Solve + solve(const MatrixBase& other) const + { return Solve(*this, other.derived()); } +#else // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC inline const internal::triangular_solve_retval solve(const MatrixBase& other) const { return solve(other); } +#endif // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC @@ -547,6 +555,15 @@ template class TriangularView #endif // EIGEN_TEST_EVALUATORS #ifdef EIGEN_TEST_EVALUATORS + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { + if(!(internal::is_same::value && internal::extract_data(dst) == internal::extract_data(rhs))) + dst = rhs; + this->template solveInPlace(dst); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TriangularView& _assignProduct(const ProductType& prod, const Scalar& alpha); diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index db0e2b033..8cf13abd9 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -94,7 +94,8 @@ template class CwiseUnaryOp; template class CwiseUnaryView; template class CwiseBinaryOp; template class SelfCwiseBinaryOp; // TODO deprecated -template class ProductBase; +template class ProductBase; // TODO deprecated +template class Solve; namespace internal { template struct product_tag; -- cgit v1.2.3 From 3a735a6cf17db3f7aab0eee34412d3b711e64044 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 13:17:41 +0100 Subject: Fix lazy evaluation in Ref --- Eigen/src/Core/Ref.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index ce9e82913..665b7497a 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -239,7 +239,11 @@ template class Ref< template void construct(const Expression& expr, internal::false_type) { +#ifdef EIGEN_TEST_EVALUATORS + internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); +#else m_object.lazyAssign(expr); +#endif Base::construct(m_object); } -- cgit v1.2.3 From 68e8ddaf94035827f9865ed0e402682f0292d53f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 13:26:07 +0100 Subject: Fix vectorization logic wrt assignment functors --- Eigen/src/Core/AssignEvaluator.h | 11 ++++++----- Eigen/src/Core/functors/AssignmentFunctors.h | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index cf4db8de5..8c6e31500 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -24,7 +24,7 @@ namespace internal { // copy_using_evaluator_traits is based on assign_traits -template +template struct copy_using_evaluator_traits { public: @@ -50,7 +50,8 @@ private: enum { StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), + && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit) + && (functor_traits::PacketAccess), MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 && int(DstIsAligned) && int(SrcIsAligned), MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), @@ -517,7 +518,7 @@ public: typedef SrcEvaluatorTypeT SrcEvaluatorType; typedef typename DstEvaluatorType::Scalar Scalar; typedef typename DstEvaluatorType::Index Index; - typedef copy_using_evaluator_traits AssignmentTraits; + typedef copy_using_evaluator_traits AssignmentTraits; generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) @@ -613,7 +614,7 @@ void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, co { #ifdef EIGEN_DEBUG_ASSIGN // TODO these traits should be computed from information provided by the evaluators - internal::copy_using_evaluator_traits::debug(); + internal::copy_using_evaluator_traits::debug(); #endif eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); @@ -750,7 +751,7 @@ struct Assignment eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); #ifdef EIGEN_DEBUG_ASSIGN - internal::copy_using_evaluator_traits::debug(); + internal::copy_using_evaluator_traits::debug(); #endif call_dense_assignment_loop(dst, src, func); diff --git a/Eigen/src/Core/functors/AssignmentFunctors.h b/Eigen/src/Core/functors/AssignmentFunctors.h index ae264aa64..1ff0eac29 100644 --- a/Eigen/src/Core/functors/AssignmentFunctors.h +++ b/Eigen/src/Core/functors/AssignmentFunctors.h @@ -31,7 +31,7 @@ template struct functor_traits > { enum { Cost = NumTraits::ReadCost, - PacketAccess = packet_traits::IsVectorized + PacketAccess = packet_traits::Vectorizable }; }; @@ -73,7 +73,7 @@ template struct functor_traits > { enum { Cost = NumTraits::ReadCost + NumTraits::AddCost, - PacketAccess = packet_traits::HasAdd + PacketAccess = packet_traits::HasSub }; }; @@ -115,7 +115,7 @@ template struct functor_traits > { enum { Cost = NumTraits::ReadCost + NumTraits::MulCost, - PacketAccess = packet_traits::HasMul + PacketAccess = packet_traits::HasDiv }; }; @@ -156,7 +156,7 @@ template struct functor_traits > { enum { Cost = 3 * NumTraits::ReadCost, - PacketAccess = packet_traits::IsVectorized + PacketAccess = packet_traits::Vectorizable }; }; -- cgit v1.2.3 From 61cff286189144e4dc84631c04db2a3b8fd43fad Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 14:05:56 +0100 Subject: Disable Flagged and ForceAlignedAccess --- Eigen/Core | 4 +++- Eigen/src/Core/DenseBase.h | 7 +++++++ Eigen/src/Core/MatrixBase.h | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Eigen/Core b/Eigen/Core index e00cd7a16..bcf354a48 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -327,7 +327,10 @@ using std::ptrdiff_t; #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" +#ifndef EIGEN_ENABLE_EVALUATORS #include "src/Core/ForceAlignedAccess.h" +#include "src/Core/Flagged.h" +#endif #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" @@ -358,7 +361,6 @@ using std::ptrdiff_t; #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/GeneralProduct.h" #ifdef EIGEN_ENABLE_EVALUATORS diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 9bbfacbcf..bd7c6d6a0 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -287,8 +287,15 @@ template class DenseBase EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); +#ifndef EIGEN_TEST_EVALUATORS template const Flagged flagged() const; +#else + // TODO flagged is temporarly disabled. It seems useless now + template + const Derived& flagged() const + { return derived(); } +#endif template EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 851fa28d5..5a3675a20 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -360,10 +360,19 @@ template class MatrixBase NoAlias noalias(); +#ifndef EIGEN_TEST_EVALUATORS inline const ForceAlignedAccess forceAlignedAccess() const; inline ForceAlignedAccess forceAlignedAccess(); template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); +#else + // TODO forceAlignedAccess is temporarly disabled + // Need to find a nicer workaround. + inline const Derived& forceAlignedAccess() const { return derived(); } + inline Derived& forceAlignedAccess() { return derived(); } + template inline const Derived& forceAlignedAccessIf() const { return derived(); } + template inline Derived& forceAlignedAccessIf() { return derived(); } +#endif Scalar trace() const; -- cgit v1.2.3 From b1ab6a8e0b1f1ecaffb6257fe41aecf46709348c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 14:06:35 +0100 Subject: Add missing assertion in swap() --- Eigen/src/Core/DenseBase.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index bd7c6d6a0..2fea574dd 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -404,6 +404,7 @@ template class DenseBase void swap(const DenseBase& other, int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) { + eigen_assert(rows()==other.rows() && cols()==other.cols()); call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } @@ -414,6 +415,7 @@ template class DenseBase EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { + eigen_assert(rows()==other.rows() && cols()==other.cols()); call_assignment(derived(), other.derived(), internal::swap_assign_op()); } #else // EIGEN_TEST_EVALUATORS -- cgit v1.2.3 From 95b0a6707b45b78bad11fa7a090cd6439072c554 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 14:51:46 +0100 Subject: evaluator must evaluate its argument to avoid redundant evaluations --- Eigen/src/Core/CoreEvaluators.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 726a6854a..92b50d190 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -815,7 +815,8 @@ struct evaluator > typedef Replicate XprType; evaluator(const XprType& replicate) - : m_argImpl(replicate.nestedExpression()), + : m_arg(replicate.nestedExpression()), + m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), m_cols(replicate.nestedExpression().cols()) { } @@ -851,7 +852,14 @@ struct evaluator > } protected: - typename evaluator::nestedType m_argImpl; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + const ArgTypeNested m_arg; // FIXME is it OK to store both the argument and its evaluator?? (we have the same situation in evalautor_product) + typename evaluator::nestedType m_argImpl; const variable_if_dynamic m_rows; const variable_if_dynamic m_cols; }; -- cgit v1.2.3 From 8af02d19b2441024823e261dc71125b9d42fe909 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 15:16:11 +0100 Subject: ExprType::Nested has a new meaning now... --- test/nesting_ops.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 1e8523283..114dd5e41 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -11,7 +11,12 @@ template void run_nesting_ops(const MatrixType& _m) { +#ifndef EIGEN_TEST_EVALUATORS + // TODO, with evaluator, the following is not correct anymore: typename MatrixType::Nested m(_m); +#else + typename internal::nested_eval::type m(_m); +#endif // Make really sure that we are in debug mode! VERIFY_RAISES_ASSERT(eigen_assert(false)); -- cgit v1.2.3 From 2eee6eaf3c073fabb214e4e524a58148f4013c2c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 19 Feb 2014 16:30:17 +0100 Subject: Fix mixing scalar types with evaluators --- Eigen/src/Core/ArrayBase.h | 2 +- Eigen/src/Core/AssignEvaluator.h | 14 +++++--------- Eigen/src/Core/CwiseBinaryOp.h | 13 ------------- Eigen/src/Core/ProductEvaluators.h | 4 ++-- Eigen/src/Core/functors/AssignmentFunctors.h | 18 ++++++++++-------- Eigen/src/Core/util/XprHelper.h | 13 +++++++++++++ test/mixingtypes.cpp | 5 ++++- 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index c528de733..e67ca34cd 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -213,7 +213,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { - call_assignment(derived(), other.derived(), internal::mul_assign_op()); + call_assignment(derived(), other.derived(), internal::mul_assign_op()); return derived(); } diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 8c6e31500..084d650d8 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -729,6 +729,11 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) typedef typename internal::conditional, Dst&>::type ActualDstType; ActualDstType actualDst(dst); + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + Assignment::run(actualDst, src, func); } @@ -739,15 +744,6 @@ struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { - // TODO check whether this is the right place to perform these checks: - enum{ - SameType = internal::is_same::value - }; - - EIGEN_STATIC_ASSERT_LVALUE(DstXprType) - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(DstXprType,SrcXprType) - EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); #ifdef EIGEN_DEBUG_ASSIGN diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 5624a4718..c78067a88 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -86,19 +86,6 @@ struct traits > }; } // end namespace internal -// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor -// that would take two operands of different types. If there were such an example, then this check should be -// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as -// currently they take only one typename Scalar template parameter. -// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. -// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to -// add together a float matrix and a double matrix. -#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ - EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ - ? int(internal::scalar_product_traits::Defined) \ - : int(internal::is_same::value)), \ - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - template class CwiseBinaryOpImpl; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 67d0dc80c..cf612d58a 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -647,8 +647,8 @@ struct diagonal_product_evaluator_base : evaluator_base { typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::PacketScalar PacketScalar; + typedef typename scalar_product_traits::ReturnType Scalar; + typedef typename internal::packet_traits::type PacketScalar; public: diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) : m_diagImpl(diag), m_matImpl(mat) diff --git a/Eigen/src/Core/functors/AssignmentFunctors.h b/Eigen/src/Core/functors/AssignmentFunctors.h index 1ff0eac29..d4d85a1ca 100644 --- a/Eigen/src/Core/functors/AssignmentFunctors.h +++ b/Eigen/src/Core/functors/AssignmentFunctors.h @@ -81,22 +81,24 @@ struct functor_traits > { * \brief Template functor for scalar/packet assignment with multiplication * */ -template struct mul_assign_op { +template +struct mul_assign_op { EIGEN_EMPTY_STRUCT_CTOR(mul_assign_op) - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Scalar& a, const Scalar& b) const { a *= b; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a *= b; } template - EIGEN_STRONG_INLINE void assignPacket(Scalar* a, const Packet& b) const - { internal::pstoret(a,internal::pmul(internal::ploadt(a),b)); } + EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const + { internal::pstoret(a,internal::pmul(internal::ploadt(a),b)); } }; -template -struct functor_traits > { +template +struct functor_traits > { enum { - Cost = NumTraits::ReadCost + NumTraits::MulCost, - PacketAccess = packet_traits::HasMul + Cost = NumTraits::ReadCost + NumTraits::MulCost, + PacketAccess = is_same::value && packet_traits::HasMul }; }; +template struct functor_is_product_like > { enum { ret = 1 }; }; /** \internal * \brief Template functor for scalar/packet assignment with diviving diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 7ea70450f..76e979ba0 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -516,6 +516,19 @@ template struct is_diagonal > } // end namespace internal +// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor +// that would take two operands of different types. If there were such an example, then this check should be +// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as +// currently they take only one typename Scalar template parameter. +// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. +// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to +// add together a float matrix and a double matrix. +#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ + EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ + ? int(internal::scalar_product_traits::Defined) \ + : int(internal::is_same::value)), \ + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + } // end namespace Eigen #endif // EIGEN_XPRHELPER_H diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 6c2f74875..ffedfb1f4 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -53,10 +53,13 @@ template void mixingtypes(int size = SizeAtCompileType) mf+mf; VERIFY_RAISES_ASSERT(mf+md); VERIFY_RAISES_ASSERT(mf+mcf); +#ifndef EIGEN_TEST_EVALUATORS + // they do not even compile when using evaluators VERIFY_RAISES_ASSERT(vf=vd); VERIFY_RAISES_ASSERT(vf+=vd); VERIFY_RAISES_ASSERT(mcd=md); - +#endif + // check scalar products VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); VERIFY_IS_APPROX(sd * vcd, complex(sd) * vcd); -- cgit v1.2.3 From ecd2c8f37b8023b56d00cec4aebec7d2f3157e3f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 20 Feb 2014 14:18:24 +0100 Subject: Add general Inverse<> expression with evaluator --- Eigen/src/Core/MatrixBase.h | 5 + Eigen/src/Core/Solve.h | 6 +- Eigen/src/Core/util/ForwardDeclarations.h | 1 + Eigen/src/LU/Determinant.h | 4 + Eigen/src/LU/Inverse.h | 152 +++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 5a3675a20..72aa75da8 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -412,8 +412,13 @@ template class MatrixBase } #endif + #ifdef EIGEN_TEST_EVALUATORS + EIGEN_DEVICE_FUNC + const Inverse inverse() const; + #else EIGEN_DEVICE_FUNC const internal::inverse_impl inverse() const; + #endif template void computeInverseAndDetWithCheck( ResultType& inverse, diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index 2da2aff56..cab0e916e 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -7,8 +7,8 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef EIGEN_INVERSE_H -#define EIGEN_INVERSE_H +#ifndef EIGEN_SOLVE_H +#define EIGEN_SOLVE_H namespace Eigen { @@ -81,7 +81,7 @@ protected: }; -// Specilaization of the Solve expression for dense results +// Specialization of the Solve expression for dense results template class SolveImpl : public MatrixBase > diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 8cf13abd9..ecb811910 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -96,6 +96,7 @@ template class CwiseBinaryOp; template class SelfCwiseBinaryOp; // TODO deprecated template class ProductBase; // TODO deprecated template class Solve; +template class Inverse; namespace internal { template struct product_tag; diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h index bb8e78a8a..9726bd96a 100644 --- a/Eigen/src/LU/Determinant.h +++ b/Eigen/src/LU/Determinant.h @@ -92,7 +92,11 @@ template inline typename internal::traits::Scalar MatrixBase::determinant() const { eigen_assert(rows() == cols()); +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::nested_eval::type Nested; +#else typedef typename internal::nested::type Nested; +#endif return internal::determinant_impl::type>::run(derived()); } diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 8d1364e0a..593ce6f8f 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -42,7 +42,12 @@ struct compute_inverse static inline void run(const MatrixType& matrix, ResultType& result) { typedef typename MatrixType::Scalar Scalar; +#ifdef EIGEN_TEST_EVALUATORS + typename internal::evaluator::type matrixEval(matrix); + result.coeffRef(0,0) = Scalar(1) / matrixEval.coeff(0,0); +#else result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); +#endif } }; @@ -75,10 +80,10 @@ inline void compute_inverse_size2_helper( const MatrixType& matrix, const typename ResultType::Scalar& invdet, ResultType& result) { - result.coeffRef(0,0) = matrix.coeff(1,1) * invdet; + result.coeffRef(0,0) = matrix.coeff(1,1) * invdet; result.coeffRef(1,0) = -matrix.coeff(1,0) * invdet; result.coeffRef(0,1) = -matrix.coeff(0,1) * invdet; - result.coeffRef(1,1) = matrix.coeff(0,0) * invdet; + result.coeffRef(1,1) = matrix.coeff(0,0) * invdet; } template @@ -279,6 +284,7 @@ struct compute_inverse_and_det_with_check *** MatrixBase methods *** *************************/ +#ifndef EIGEN_TEST_EVALUATORS template struct traits > { @@ -313,9 +319,141 @@ struct inverse_impl : public ReturnByValue > compute_inverse::run(m_matrix, dst); } }; +#endif +} // end namespace internal + +#ifdef EIGEN_TEST_EVALUATORS + +// TODO move the general declaration in Core, and rename this file DenseInverseImpl.h, or something like this... + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = Dynamic + }; +}; + +} // end namespace internal + +/** \class Inverse + * \ingroup LU_Module + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::Index Index; + typedef typename XprType::PlainObject PlainObject; + typedef typename internal::nested::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + + Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested &m_xpr; +}; +// Specialization of the Inverse expression for dense expressions +template +class InverseImpl + : public MatrixBase > +{ + typedef Inverse Derived; + +public: + + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +// Evaluator of Inverse -> eval into a temporary +template +struct evaluator > + : public evaluator::PlainObject>::type +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + + typedef typename internal::nested_eval::type ActualXprType; + typedef typename internal::remove_all::type ActualXprTypeCleanded; + + ActualXprType actual_xpr(inv_xpr.nestedExpression()); + + compute_inverse::run(actual_xpr, m_result); + } + +protected: + PlainObject m_result; +}; + +// Specialization for "dst = xpr.inverse()" +// NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere +template +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + // FIXME shall we resize dst here? + const int Size = EIGEN_PLAIN_ENUM_MIN(XprType::ColsAtCompileTime,DstXprType::ColsAtCompileTime); + EIGEN_ONLY_USED_FOR_DEBUG(Size); + eigen_assert(( (Size<=1) || (Size>4) || (extract_data(src.nestedExpression())!=extract_data(dst))) + && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + + typedef typename internal::nested_eval::type ActualXprType; + typedef typename internal::remove_all::type ActualXprTypeCleanded; + + ActualXprType actual_xpr(src.nestedExpression()); + + compute_inverse::run(actual_xpr, dst); + } +}; + + } // end namespace internal +#endif + /** \lu_module * * \returns the matrix inverse of this matrix. @@ -333,6 +471,15 @@ struct inverse_impl : public ReturnByValue > * * \sa computeInverseAndDetWithCheck() */ +#ifdef EIGEN_TEST_EVALUATORS +template +inline const Inverse MatrixBase::inverse() const +{ + EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) + eigen_assert(rows() == cols()); + return Inverse(derived()); +} +#else template inline const internal::inverse_impl MatrixBase::inverse() const { @@ -340,6 +487,7 @@ inline const internal::inverse_impl MatrixBase::inverse() cons eigen_assert(rows() == cols()); return internal::inverse_impl(derived()); } +#endif /** \lu_module * -- cgit v1.2.3 From 5f6ec95291a7adfe990854469d7697cc65642c8c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 20 Feb 2014 15:24:00 +0100 Subject: Propagate LvalueBit flag to TriangularView --- Eigen/src/Core/TriangularMatrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 76ba76d5f..96c81f933 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -174,7 +174,7 @@ struct traits > : traits typedef typename MatrixType::PlainObject DenseMatrixType; enum { Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, + Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost }; }; -- cgit v1.2.3 From 96213335451c821f1b969ffbce5b6e73e5e55ca3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 20 Feb 2014 15:24:21 +0100 Subject: Fix dimension of Solve expression --- Eigen/src/Core/Solve.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index cab0e916e..c28789968 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -69,7 +69,7 @@ public: : m_dec(dec), m_rhs(rhs) {} - EIGEN_DEVICE_FUNC Index rows() const { return m_dec.rows(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_dec.cols(); } EIGEN_DEVICE_FUNC Index cols() const { return m_rhs.cols(); } EIGEN_DEVICE_FUNC const Decomposition& dec() const { return m_dec; } -- cgit v1.2.3 From b2e1453e1e81132381bfb5cd46ec5a66ec55b3c6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 20 Feb 2014 15:25:06 +0100 Subject: Some bit flags and internal structures are deprecated --- Eigen/src/Core/util/Constants.h | 8 ++++---- Eigen/src/Core/util/ForwardDeclarations.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 14449eb6c..d9e51ffea 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -53,14 +53,14 @@ const int Infinity = -1; const unsigned int RowMajorBit = 0x1; /** \ingroup flags - * + * \deprecated * means the expression should be evaluated by the calling expression */ -const unsigned int EvalBeforeNestingBit = 0x2; +const unsigned int EvalBeforeNestingBit = 0x2; // FIXME deprecated /** \ingroup flags - * + * \deprecated * means the expression should be evaluated before any assignment */ -const unsigned int EvalBeforeAssigningBit = 0x4; +const unsigned int EvalBeforeAssigningBit = 0x4; // FIXME deprecated /** \ingroup flags * diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index ecb811910..975fdbf2a 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -141,8 +141,10 @@ template class ArrayWrapper; template class MatrixWrapper; namespace internal { +#ifndef EIGEN_TEST_EVALUATROS template struct solve_retval_base; template struct solve_retval; +#endif template struct kernel_retval_base; template struct kernel_retval; template struct image_retval_base; -- cgit v1.2.3 From 93125e372df80f07bb7d74abdebb592425ddba7b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 20 Feb 2014 15:26:15 +0100 Subject: Port LU module to evaluators (except image() and kernel()) --- Eigen/src/Core/AssignEvaluator.h | 2 +- Eigen/src/LU/FullPivLU.h | 152 +++++++++++++++++++++++++++------------ Eigen/src/LU/PartialPivLU.h | 85 ++++++++++++++++++---- 3 files changed, 178 insertions(+), 61 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 084d650d8..73f20c1a1 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -721,7 +721,7 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)) && int(Dst::SizeAtCompileTime) != 1 }; - + dst.resize(NeedToTranspose ? src.cols() : src.rows(), NeedToTranspose ? src.rows() : src.cols()); diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 44699b763..86de91ccb 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -12,6 +12,19 @@ namespace Eigen { +namespace internal { +template struct traits > + : traits<_MatrixType> +{ + typedef traits<_MatrixType> BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = Dynamic + }; +}; + +} // end namespace internal + /** \ingroup LU_Module * * \class FullPivLU @@ -61,6 +74,7 @@ template class FullPivLU typedef typename internal::plain_col_type::type IntColVectorType; typedef PermutationMatrix PermutationQType; typedef PermutationMatrix PermutationPType; + typedef typename MatrixType::PlainObject PlainObject; /** * \brief Default Constructor. @@ -209,6 +223,15 @@ template class FullPivLU * * \sa TriangularView::solve(), kernel(), inverse() */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "LU is not initialized."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -216,6 +239,7 @@ template class FullPivLU eigen_assert(m_isInitialized && "LU is not initialized."); return internal::solve_retval(*this, b.derived()); } +#endif /** \returns the determinant of the matrix of which * *this is the LU decomposition. It has only linear complexity @@ -359,6 +383,14 @@ template class FullPivLU * * \sa MatrixBase::inverse() */ +#ifdef EIGEN_TEST_EVALUATORS + inline const Inverse inverse() const + { + eigen_assert(m_isInitialized && "LU is not initialized."); + eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); + return Inverse(*this); + } +#else inline const internal::solve_retval inverse() const { eigen_assert(m_isInitialized && "LU is not initialized."); @@ -366,11 +398,18 @@ template class FullPivLU return internal::solve_retval (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols())); } +#endif MatrixType reconstructedMatrix() const; inline Index rows() const { return m_lu.rows(); } inline Index cols() const { return m_lu.cols(); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: MatrixType m_lu; @@ -662,6 +701,61 @@ struct image_retval > /***** Implementation of solve() *****************************************************/ +} // end namespace internal + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const { + + /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. + * So we proceed as follows: + * Step 1: compute c = P * rhs. + * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible. + * Step 3: replace c by the solution x to Ux = c. May or may not exist. + * Step 4: result = Q * c; + */ + + const Index rows = this->rows(), + cols = this->cols(), + nonzero_pivots = this->nonzeroPivots(); + eigen_assert(rhs.rows() == rows); + const Index smalldim = (std::min)(rows, cols); + + if(nonzero_pivots == 0) + { + dst.setZero(); + return; + } + + typename RhsType::PlainObject c(rhs.rows(), rhs.cols()); + + // Step 1 + c = permutationP() * rhs; + + // Step 2 + m_lu.topLeftCorner(smalldim,smalldim) + .template triangularView() + .solveInPlace(c.topRows(smalldim)); + if(rows>cols) + c.bottomRows(rows-cols) -= m_lu.bottomRows(rows-cols) * c.topRows(cols); + + // Step 3 + m_lu.topLeftCorner(nonzero_pivots, nonzero_pivots) + .template triangularView() + .solveInPlace(c.topRows(nonzero_pivots)); + + // Step 4 + for(Index i = 0; i < nonzero_pivots; ++i) + dst.row(permutationQ().indices().coeff(i)) = c.row(i); + for(Index i = nonzero_pivots; i < m_lu.cols(); ++i) + dst.row(permutationQ().indices().coeff(i)).setZero(); +} +#endif + +namespace internal { + +#ifdef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -670,53 +764,21 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. - * So we proceed as follows: - * Step 1: compute c = P * rhs. - * Step 2: replace c by the solution x to Lx = c. Exists because L is invertible. - * Step 3: replace c by the solution x to Ux = c. May or may not exist. - * Step 4: result = Q * c; - */ - - const Index rows = dec().rows(), cols = dec().cols(), - nonzero_pivots = dec().nonzeroPivots(); - eigen_assert(rhs().rows() == rows); - const Index smalldim = (std::min)(rows, cols); - - if(nonzero_pivots == 0) - { - dst.setZero(); - return; - } - - typename Rhs::PlainObject c(rhs().rows(), rhs().cols()); - - // Step 1 - c = dec().permutationP() * rhs(); + dec()._solve_impl(rhs(), dst); + } +}; +#endif - // Step 2 - dec().matrixLU() - .topLeftCorner(smalldim,smalldim) - .template triangularView() - .solveInPlace(c.topRows(smalldim)); - if(rows>cols) - { - c.bottomRows(rows-cols) - -= dec().matrixLU().bottomRows(rows-cols) - * c.topRows(cols); - } +/***** Implementation of inverse() *****************************************************/ - // Step 3 - dec().matrixLU() - .topLeftCorner(nonzero_pivots, nonzero_pivots) - .template triangularView() - .solveInPlace(c.topRows(nonzero_pivots)); - - // Step 4 - for(Index i = 0; i < nonzero_pivots; ++i) - dst.row(dec().permutationQ().indices().coeff(i)) = c.row(i); - for(Index i = nonzero_pivots; i < dec().matrixLU().cols(); ++i) - dst.row(dec().permutationQ().indices().coeff(i)).setZero(); +template +struct Assignment >, internal::assign_op, Dense2Dense, Scalar> +{ + typedef FullPivLU LuType; + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 1d389ecac..ac53f7ab5 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -13,6 +13,19 @@ namespace Eigen { +namespace internal { +template struct traits > + : traits<_MatrixType> +{ + typedef traits<_MatrixType> BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = Dynamic + }; +}; + +} // end namespace internal + /** \ingroup LU_Module * * \class PartialPivLU @@ -62,6 +75,7 @@ template class PartialPivLU typedef typename MatrixType::Index Index; typedef PermutationMatrix PermutationType; typedef Transpositions TranspositionType; + typedef typename MatrixType::PlainObject PlainObject; /** @@ -128,6 +142,15 @@ template class PartialPivLU * * \sa TriangularView::solve(), inverse(), computeInverse() */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -135,6 +158,7 @@ template class PartialPivLU eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); return internal::solve_retval(*this, b.derived()); } +#endif /** \returns the inverse of the matrix of which *this is the LU decomposition. * @@ -143,12 +167,20 @@ template class PartialPivLU * * \sa MatrixBase::inverse(), LU::inverse() */ +#ifdef EIGEN_TEST_EVALUATORS + inline const Inverse inverse() const + { + eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); + return Inverse(*this); + } +#else inline const internal::solve_retval inverse() const { eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); return internal::solve_retval (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols())); } +#endif /** \returns the determinant of the matrix of which * *this is the LU decomposition. It has only linear complexity @@ -169,6 +201,30 @@ template class PartialPivLU inline Index rows() const { return m_lu.rows(); } inline Index cols() const { return m_lu.cols(); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const { + /* The decomposition PA = LU can be rewritten as A = P^{-1} L U. + * So we proceed as follows: + * Step 1: compute c = Pb. + * Step 2: replace c by the solution x to Lx = c. + * Step 3: replace c by the solution x to Ux = c. + */ + + eigen_assert(rhs.rows() == m_lu.rows()); + + // Step 1 + dst = permutationP() * rhs; + + // Step 2 + m_lu.template triangularView().solveInPlace(dst); + + // Step 3 + m_lu.template triangularView().solveInPlace(dst); + } + #endif protected: MatrixType m_lu; @@ -434,6 +490,7 @@ MatrixType PartialPivLU::reconstructedMatrix() const namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -442,23 +499,21 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - /* The decomposition PA = LU can be rewritten as A = P^{-1} L U. - * So we proceed as follows: - * Step 1: compute c = Pb. - * Step 2: replace c by the solution x to Lx = c. - * Step 3: replace c by the solution x to Ux = c. - */ - - eigen_assert(rhs().rows() == dec().matrixLU().rows()); - - // Step 1 - dst = dec().permutationP() * rhs(); + dec()._solve_impl(rhs(), dst); + } +}; +#endif - // Step 2 - dec().matrixLU().template triangularView().solveInPlace(dst); +/***** Implementation of inverse() *****************************************************/ - // Step 3 - dec().matrixLU().template triangularView().solveInPlace(dst); +template +struct Assignment >, internal::assign_op, Dense2Dense, Scalar> +{ + typedef PartialPivLU LuType; + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; -- cgit v1.2.3 From af31b6c37a3b4b32c8075d94b39a78108f12fd31 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 21 Feb 2014 15:22:08 +0100 Subject: Generalize evaluator> such that there is no need to specialize it --- Eigen/src/Core/AssignEvaluator.h | 6 +++++- Eigen/src/LU/Inverse.h | 27 +++++++++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 73f20c1a1..14effd1f2 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -736,7 +736,11 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) Assignment::run(actualDst, src, func); } - +template +void call_assignment_no_alias(Dst& dst, const Src& src) +{ + call_assignment_no_alias(dst, src, internal::assign_op()); +} // Generic Dense to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 593ce6f8f..db053406e 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -351,7 +351,7 @@ struct traits > * * \tparam XprType the type of the expression we are taking the inverse * - * This class represents an expression of A.inverse() + * This class represents an abstract expression of A.inverse() * and most of the time this is the only way it is used. * */ @@ -377,7 +377,11 @@ protected: XprTypeNested &m_xpr; }; -// Specialization of the Inverse expression for dense expressions +/** \internal + * Specialization of the Inverse expression for dense expressions. + * Direct access to the coefficients are discared. + * FIXME this intermediate class is probably not needed anymore. + */ template class InverseImpl : public MatrixBase > @@ -397,7 +401,16 @@ private: namespace internal { -// Evaluator of Inverse -> eval into a temporary +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ template struct evaluator > : public evaluator::PlainObject>::type @@ -413,13 +426,7 @@ struct evaluator > : m_result(inv_xpr.rows(), inv_xpr.cols()) { ::new (static_cast(this)) Base(m_result); - - typedef typename internal::nested_eval::type ActualXprType; - typedef typename internal::remove_all::type ActualXprTypeCleanded; - - ActualXprType actual_xpr(inv_xpr.nestedExpression()); - - compute_inverse::run(actual_xpr, m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); } protected: -- cgit v1.2.3 From 728c3d2cb955a255cae5515197ae65dc83209509 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 21 Feb 2014 16:27:24 +0100 Subject: Get rid of GeneralProduct for outer-products, and get rid of ScaledProduct --- Eigen/src/Core/GeneralProduct.h | 3 ++ Eigen/src/Core/ProductBase.h | 3 ++ Eigen/src/Core/ProductEvaluators.h | 71 ++++++++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index f823ff251..4c0fc7f63 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -247,6 +247,7 @@ class GeneralProduct * Implementation of Outer Vector Vector Product ***********************************************************************/ +#ifndef EIGEN_TEST_EVALUATORS namespace internal { // Column major @@ -326,6 +327,8 @@ class GeneralProduct } }; +#endif // EIGEN_TEST_EVALUATORS + /*********************************************************************** * Implementation of General Matrix Vector Product ***********************************************************************/ diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index a494b5f87..f6b719d19 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -174,6 +174,7 @@ class ProductBase : public MatrixBase mutable PlainObject m_result; }; +#ifndef EIGEN_TEST_EVALUATORS // here we need to overload the nested rule for products // such that the nested type is a const reference to a plain matrix namespace internal { @@ -263,6 +264,8 @@ class ScaledProduct Scalar m_alpha; }; +#endif // EIGEN_TEST_EVALUATORS + /** \internal * Overloaded to perform an efficient C = (A*B).lazy() */ template diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index cf612d58a..93ae5f5f5 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -17,7 +17,11 @@ namespace Eigen { namespace internal { -// Like more general binary expressions, products need their own evaluator: +/** \internal + * \class product_evaluator + * Products need their own evaluator with more template arguments allowing for + * easier partial template specializations. + */ template< typename T, int ProductTag = internal::product_type::ret, typename LhsShape = typename evaluator_traits::Shape, @@ -26,6 +30,14 @@ template< typename T, typename RhsScalar = typename T::Rhs::Scalar > struct product_evaluator; +/** \internal + * Evaluator of a product expression. + * Since products require special treatments to handle all possible cases, + * we simply deffer the evaluation logic to a product_evaluator class + * which offers more partial specialization possibilities. + * + * \sa class product_evaluator + */ template struct evaluator > : public product_evaluator > @@ -40,7 +52,7 @@ struct evaluator > }; // Catch scalar * ( A * B ) and transform it to (A*scalar) * B -// TODO we should apply that rule if that's really helpful +// TODO we should apply that rule only if that's really helpful template struct evaluator, const Product > > : public evaluator,const Lhs>, Rhs, DefaultProduct> > @@ -66,7 +78,7 @@ struct evaluator, DiagIndex> > typedef evaluator type; typedef evaluator nestedType; -// + evaluator(const XprType& xpr) : Base(Diagonal, DiagIndex>( Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), @@ -183,38 +195,75 @@ struct generic_product_impl }; +/*********************************************************************** +* Implementation of outer dense * dense vector product +***********************************************************************/ + +// Column major result +template +EIGEN_DONT_INLINE void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) +{ + typedef typename Dst::Index Index; + // FIXME make sure lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + // FIXME we should probably build an evaluator for dst and rhs + const Index cols = dst.cols(); + for (Index j=0; j +EIGEN_DONT_INLINE void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) { + typedef typename Dst::Index Index; + // FIXME make sure rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + // FIXME we should probably build an evaluator for dst and lhs + const Index rows = dst.rows(); + for (Index i=0; i struct generic_product_impl { + template struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; typedef typename Product::Scalar Scalar; + // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose + struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + adds(const Scalar& s) : m_scale(s) {} + template void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + template static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).evalTo(dst); + internal::outer_product_selector_run(dst, lhs, rhs, set(), IsRowMajor()); } template static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).addTo(dst); + internal::outer_product_selector_run(dst, lhs, rhs, add(), IsRowMajor()); } template static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).subTo(dst); + internal::outer_product_selector_run(dst, lhs, rhs, sub(), IsRowMajor()); } template static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); + internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), IsRowMajor()); } }; -- cgit v1.2.3 From 6c7ab508117d84671054808c921980a4908efb20 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 21 Feb 2014 16:43:03 +0100 Subject: Get rid of GeneralProduct<> for GemmProduct --- Eigen/Core | 7 ++-- Eigen/src/Core/ProductEvaluators.h | 14 ------- Eigen/src/Core/products/GeneralMatrixMatrix.h | 57 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index bcf354a48..245604465 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -371,6 +371,9 @@ using std::ptrdiff_t; #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" #include "src/Core/products/CoeffBasedProduct.h" +#ifdef EIGEN_ENABLE_EVALUATORS +#include "src/Core/ProductEvaluators.h" +#endif #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" @@ -386,10 +389,6 @@ using std::ptrdiff_t; #include "src/Core/BandMatrix.h" #include "src/Core/CoreIterators.h" -#ifdef EIGEN_ENABLE_EVALUATORS -#include "src/Core/ProductEvaluators.h" -#endif - #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" #include "src/Core/VectorwiseOp.h" diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 93ae5f5f5..99c48ae52 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -311,20 +311,6 @@ struct generic_product_impl } }; -template -struct generic_product_impl - : generic_product_impl_base > -{ - typedef typename Product::Scalar Scalar; - - template - static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) - { - // TODO bypass GeneralProduct class - GeneralProduct(lhs,rhs).scaleAndAddTo(dst, alpha); - } -}; - template struct generic_product_impl { diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 3f5ffcf51..1c8940e1c 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -374,6 +374,7 @@ class gemm_blocking_space class GeneralProduct : public ProductBase, Lhs, Rhs> @@ -421,6 +422,62 @@ class GeneralProduct internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>(GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), this->rows(), this->cols(), Dest::Flags&RowMajorBit); } }; +#else // EIGEN_TEST_EVALUATORS +namespace internal { + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + typedef typename Product::Index Index; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; + + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + enum { + MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) + }; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha) + { + eigen_assert(dst.rows()==a_lhs.rows() && dst.cols()==a_rhs.cols()); + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,LhsScalar,RhsScalar, + Dest::MaxRowsAtCompileTime,Dest::MaxColsAtCompileTime,MaxDepthAtCompileTime> BlockingType; + + typedef internal::gemm_functor< + Scalar, Index, + internal::general_matrix_matrix_product< + Index, + LhsScalar, (ActualLhsTypeCleaned::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), + RhsScalar, (ActualRhsTypeCleaned::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), + (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, + ActualLhsTypeCleaned, ActualRhsTypeCleaned, Dest, BlockingType> GemmFunctor; + + BlockingType blocking(dst.rows(), dst.cols(), lhs.cols()); + + internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)> + (GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), a_lhs.rows(), a_rhs.cols(), Dest::Flags&RowMajorBit); + } +}; + +} // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen -- cgit v1.2.3 From d67548f345d01c69d9dbba5869d8cc0159e96464 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 21 Feb 2014 17:13:28 +0100 Subject: Get rid of GeneralProduct<> for GemvProduct --- Eigen/src/Core/GeneralProduct.h | 208 ++++++++++++++++++++++++++++++++++--- Eigen/src/Core/ProductBase.h | 3 +- Eigen/src/Core/ProductEvaluators.h | 2 +- 3 files changed, 196 insertions(+), 17 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 4c0fc7f63..57d5d3c38 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -342,16 +342,19 @@ class GeneralProduct */ namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct traits > : traits, Lhs, Rhs> > {}; +#endif template struct gemv_selector; } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS template class GeneralProduct : public ProductBase, Lhs, Rhs> @@ -378,24 +381,10 @@ class GeneralProduct bool(internal::blas_traits::HasUsableDirectAccess)>::run(*this, dst, alpha); } }; +#endif namespace internal { -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - template struct gemv_static_vector_if; template @@ -432,6 +421,23 @@ struct gemv_static_vector_if #endif }; +#ifndef EIGEN_TEST_EVALUATORS + +// The vector is on the left => transposition +template +struct gemv_selector +{ + template + static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_selector + ::run(GeneralProduct,Transpose, GemvProduct> + (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); + } +}; + template<> struct gemv_selector { template @@ -582,6 +588,178 @@ template<> struct gemv_selector } }; +#else // EIGEN_TEST_EVALUATORS + +// The vector is on the left => transposition +template +struct gemv_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_selector + ::run(rhs.transpose(), lhs.transpose(), destT, alpha); + } +}; + +template<> struct gemv_selector +{ + template + static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Dest::Index Index; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + typedef Map, Aligned> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); + ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, + ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), + MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal + }; + + gemv_static_vector_if static_dest; + + bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhs.data(), actualRhs.innerStride(), + actualDestPtr, 1, + compatibleAlpha); + + if (!evalToDest) + { + if(!alphaIsCompatible) + dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } + } +}; + +template<> struct gemv_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Dest::Index Index; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 + }; + + gemv_static_vector_if static_rhs; + + ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), + DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); + + if(!DirectlyUseRhs) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = actualRhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, actualRhs.size()) = actualRhs; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + actualLhs.data(), actualLhs.outerStride(), + actualRhsPtr, 1, + dest.data(), dest.innerStride(), + actualAlpha); + } +}; + +template<> struct gemv_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure dest is sequentially stored in memory, otherwise use a temp + const Index size = rhs.rows(); + for(Index k=0; k struct gemv_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Dest::Index Index; + // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp + const Index rows = dest.rows(); + for(Index i=0; i }; #ifndef EIGEN_TEST_EVALUATORS + // here we need to overload the nested rule for products // such that the nested type is a const reference to a plain matrix namespace internal { diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 99c48ae52..5f9cf69a2 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -307,7 +307,7 @@ struct generic_product_impl internal::gemv_selector::HasUsableDirectAccess) - >::run(GeneralProduct(lhs,rhs), dst, alpha); + >::run(lhs, rhs, dst, alpha); } }; -- cgit v1.2.3 From c98881e1306c94c53ad3de77f9e9036d98dbcf2a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 23 Feb 2014 22:51:13 +0100 Subject: By-pass ProductBase for triangular and selfadjoint products and get rid of ProductBase --- Eigen/src/Core/GeneralProduct.h | 1 - Eigen/src/Core/ProductBase.h | 4 +- Eigen/src/Core/ProductEvaluators.h | 20 ++-- Eigen/src/Core/SelfAdjointView.h | 2 + Eigen/src/Core/products/SelfadjointMatrixMatrix.h | 52 ++++++++++ Eigen/src/Core/products/SelfadjointMatrixVector.h | 104 +++++++++++++++++++ Eigen/src/Core/products/TriangularMatrixMatrix.h | 53 +++++++++- Eigen/src/Core/products/TriangularMatrixVector.h | 121 ++++++++++++++-------- 8 files changed, 301 insertions(+), 56 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 57d5d3c38..06aa05ee6 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -688,7 +688,6 @@ template<> struct gemv_selector typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; typedef typename Dest::Scalar ResScalar; - typedef typename Dest::RealScalar RealScalar; typedef internal::blas_traits LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index f7cef9a9e..3b2246fd8 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -11,6 +11,8 @@ #define EIGEN_PRODUCTBASE_H namespace Eigen { + +#ifndef EIGEN_TEST_EVALUATORS /** \class ProductBase * \ingroup Core_Module @@ -174,8 +176,6 @@ class ProductBase : public MatrixBase mutable PlainObject m_result; }; -#ifndef EIGEN_TEST_EVALUATORS - // here we need to overload the nested rule for products // such that the nested type is a const reference to a plain matrix namespace internal { diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 5f9cf69a2..186ae4a34 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -532,6 +532,10 @@ struct etor_product_packet_impl /*************************************************************************** * Triangular products ***************************************************************************/ +template +struct triangular_product_impl; template struct generic_product_impl @@ -542,8 +546,8 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - // TODO bypass TriangularProduct class - TriangularProduct(lhs.nestedExpression(),rhs).scaleAndAddTo(dst, alpha); + triangular_product_impl + ::run(dst, lhs.nestedExpression(), rhs, alpha); } }; @@ -576,8 +580,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - // TODO bypass TriangularProduct class - TriangularProduct(lhs,rhs.nestedExpression()).scaleAndAddTo(dst, alpha); + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); } }; @@ -605,6 +608,9 @@ protected: /*************************************************************************** * SelfAdjoint products ***************************************************************************/ +template +struct selfadjoint_product_impl; template struct generic_product_impl @@ -615,8 +621,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - // TODO bypass SelfadjointProductMatrix class - SelfadjointProductMatrix(lhs.nestedExpression(),rhs).scaleAndAddTo(dst, alpha); + selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); } }; @@ -649,8 +654,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - // TODO bypass SelfadjointProductMatrix class - SelfadjointProductMatrix(lhs,rhs.nestedExpression()).scaleAndAddTo(dst, alpha); + selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); } }; diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 2cc1815fd..f7f512cf4 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -45,9 +45,11 @@ struct traits > : traits }; } +#ifndef EIGEN_TEST_EVALUATORS template struct SelfadjointProductMatrix; +#endif // FIXME could also be called SelfAdjointWrapper to be consistent with DiagonalWrapper ?? template class SelfAdjointView diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h index 99cf9e0ae..f252aef85 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h @@ -381,6 +381,7 @@ EIGEN_DONT_INLINE void product_selfadjoint_matrix struct traits > @@ -430,6 +431,57 @@ struct SelfadjointProductMatrix ); } }; +#else // EIGEN_TEST_EVALUATORS +namespace internal { + +template +struct selfadjoint_product_impl +{ + typedef typename Product::Scalar Scalar; + typedef typename Product::Index Index; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + enum { + LhsIsUpper = (LhsMode&(Upper|Lower))==Upper, + LhsIsSelfAdjoint = (LhsMode&SelfAdjoint)==SelfAdjoint, + RhsIsUpper = (RhsMode&(Upper|Lower))==Upper, + RhsIsSelfAdjoint = (RhsMode&SelfAdjoint)==SelfAdjoint + }; + + template + static void run(Dest &dst, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) + { + eigen_assert(dst.rows()==a_lhs.rows() && dst.cols()==a_rhs.cols()); + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + internal::product_selfadjoint_matrix::Flags &RowMajorBit) ? RowMajor : ColMajor, LhsIsSelfAdjoint, + NumTraits::IsComplex && EIGEN_LOGICAL_XOR(LhsIsUpper,bool(LhsBlasTraits::NeedToConjugate)), + EIGEN_LOGICAL_XOR(RhsIsUpper,internal::traits::Flags &RowMajorBit) ? RowMajor : ColMajor, RhsIsSelfAdjoint, + NumTraits::IsComplex && EIGEN_LOGICAL_XOR(RhsIsUpper,bool(RhsBlasTraits::NeedToConjugate)), + internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor> + ::run( + lhs.rows(), rhs.cols(), // sizes + &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info + &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info + &dst.coeffRef(0,0), dst.outerStride(), // result info + actualAlpha // alpha + ); + } +}; + +} // end namespace internal + +#endif } // end namespace Eigen diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index f698f67f9..ddc07d535 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -168,6 +168,7 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product struct traits > @@ -276,6 +277,109 @@ struct SelfadjointProductMatrix } }; +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +template +struct selfadjoint_product_impl +{ + typedef typename Product::Scalar Scalar; + typedef typename Product::Index Index; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; + + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + enum { LhsUpLo = LhsMode&(Upper|Lower) }; + + template + static void run(Dest& dest, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) + { + typedef typename Dest::Scalar ResScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef Map, Aligned> MappedDest; + + eigen_assert(dest.rows()==a_lhs.rows() && dest.cols()==a_rhs.cols()); + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + enum { + EvalToDest = (Dest::InnerStrideAtCompileTime==1), + UseRhs = (ActualRhsTypeCleaned::InnerStrideAtCompileTime==1) + }; + + internal::gemv_static_vector_if static_dest; + internal::gemv_static_vector_if static_rhs; + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + EvalToDest ? dest.data() : static_dest.data()); + + ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,rhs.size(), + UseRhs ? const_cast(rhs.data()) : static_rhs.data()); + + if(!EvalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + MappedDest(actualDestPtr, dest.size()) = dest; + } + + if(!UseRhs) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + int size = rhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, rhs.size()) = rhs; + } + + + internal::selfadjoint_matrix_vector_product::Flags&RowMajorBit) ? RowMajor : ColMajor, + int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run + ( + lhs.rows(), // size + &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info + actualRhsPtr, 1, // rhs info + actualDestPtr, // result info + actualAlpha // scale factor + ); + + if(!EvalToDest) + dest = MappedDest(actualDestPtr, dest.size()); + } +}; + +template +struct selfadjoint_product_impl +{ + typedef typename Product::Scalar Scalar; + enum { RhsUpLo = RhsMode&(Upper|Lower) }; + + template + static void run(Dest& dest, const Lhs &a_lhs, const Rhs &a_rhs, const Scalar& alpha) + { + // let's simply transpose the product + Transpose destT(dest); + selfadjoint_product_impl, int(RhsUpLo)==Upper ? Lower : Upper, false, + Transpose, 0, true>::run(destT, a_rhs.transpose(), a_lhs.transpose(), alpha); + } +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_H diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix.h b/Eigen/src/Core/products/TriangularMatrixMatrix.h index 8110507b5..e654b45b1 100644 --- a/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -372,7 +372,6 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix struct traits > : traits, Lhs, Rhs> > @@ -380,6 +379,7 @@ struct traits > } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS template struct TriangularProduct : public ProductBase, Lhs, Rhs > @@ -421,6 +421,57 @@ struct TriangularProduct ); } }; +#else // EIGEN_TEST_EVALUATORS +namespace internal { +template +struct triangular_product_impl +{ + template static void run(Dest& dst, const Lhs &a_lhs, const Rhs &a_rhs, const typename Dest::Scalar& alpha) + { + typedef typename Dest::Index Index; + typedef typename Dest::Scalar Scalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef typename internal::remove_all::type ActualLhsTypeCleaned; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(a_lhs); + typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(a_rhs); + + Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs) + * RhsBlasTraits::extractScalarFactor(a_rhs); + + typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, + Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType; + + enum { IsLower = (Mode&Lower) == Lower }; + Index stripedRows = ((!LhsIsTriangular) || (IsLower)) ? lhs.rows() : (std::min)(lhs.rows(),lhs.cols()); + Index stripedCols = ((LhsIsTriangular) || (!IsLower)) ? rhs.cols() : (std::min)(rhs.cols(),rhs.rows()); + Index stripedDepth = LhsIsTriangular ? ((!IsLower) ? lhs.cols() : (std::min)(lhs.cols(),lhs.rows())) + : ((IsLower) ? rhs.rows() : (std::min)(rhs.rows(),rhs.cols())); + + BlockingType blocking(stripedRows, stripedCols, stripedDepth); + + internal::product_triangular_matrix_matrix::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, + (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, + (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor> + ::run( + stripedRows, stripedCols, stripedDepth, // sizes + &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info + &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info + &dst.coeffRef(0,0), dst.outerStride(), // result info + actualAlpha, blocking + ); + } +}; + +} // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index 6117d5a82..eed7f4258 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h @@ -168,11 +168,12 @@ struct traits > {}; -template +template struct trmv_selector; } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS template struct TriangularProduct : public ProductBase, Lhs, Rhs > @@ -185,7 +186,7 @@ struct TriangularProduct { eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - internal::trmv_selector<(int(internal::traits::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dst, alpha); + internal::trmv_selector::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(m_lhs, m_rhs, dst, alpha); } }; @@ -201,39 +202,71 @@ struct TriangularProduct { eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - typedef TriangularProduct<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower),true,Transpose,false,Transpose,true> TriangularProductTranspose; Transpose dstT(dst); - internal::trmv_selector<(int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor>::run( - TriangularProductTranspose(m_rhs.transpose(),m_lhs.transpose()), dstT, alpha); + internal::trmv_selector<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower), + (int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor> + ::run(m_rhs.transpose(),m_lhs.transpose(), dstT, alpha); } }; +#else // EIGEN_TEST_EVALUATORS +namespace internal { + +template +struct triangular_product_impl +{ + template static void run(Dest& dst, const Lhs &lhs, const Rhs &rhs, const typename Dest::Scalar& alpha) + { + eigen_assert(dst.rows()==lhs.rows() && dst.cols()==rhs.cols()); + + internal::trmv_selector::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(lhs, rhs, dst, alpha); + } +}; + +template +struct triangular_product_impl +{ + template static void run(Dest& dst, const Lhs &lhs, const Rhs &rhs, const typename Dest::Scalar& alpha) + { + eigen_assert(dst.rows()==lhs.rows() && dst.cols()==rhs.cols()); + + Transpose dstT(dst); + internal::trmv_selector<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower), + (int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor> + ::run(rhs.transpose(),lhs.transpose(), dstT, alpha); + } +}; + +} // end namespace internal +#endif // EIGEN_TEST_EVALUATORS + namespace internal { // TODO: find a way to factorize this piece of code with gemv_selector since the logic is exactly the same. -template<> struct trmv_selector +template struct trmv_selector { - template - static void run(const TriangularProduct& prod, Dest& dest, const typename TriangularProduct::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef TriangularProduct ProductType; - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; + typedef typename Dest::Index Index; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef Map, Aligned> MappedDest; - typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(prod.rhs()); + typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(lhs); + typename internal::add_const_on_value_type::type actualRhs = RhsBlasTraits::extract(rhs); - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 @@ -288,33 +321,33 @@ template<> struct trmv_selector } }; -template<> struct trmv_selector +template struct trmv_selector { - template - static void run(const TriangularProduct& prod, Dest& dest, const typename TriangularProduct::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef TriangularProduct ProductType; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Dest::Index Index; + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 }; - gemv_static_vector_if static_rhs; + gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); @@ -325,7 +358,7 @@ template<> struct trmv_selector int size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; + Map(actualRhsPtr, actualRhs.size()) = actualRhs; } internal::triangular_matrix_vector_product -- cgit v1.2.3 From 1e0c2f6ddb60c85440fceb3503769bbee80452c2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 24 Feb 2014 11:41:19 +0100 Subject: Hide some deprecated classes. --- Eigen/src/Core/GeneralProduct.h | 8 +++++++- Eigen/src/Core/Swap.h | 4 ++-- Eigen/src/LU/FullPivLU.h | 4 ++-- Eigen/src/LU/PartialPivLU.h | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 06aa05ee6..c37526b72 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -13,6 +13,7 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS /** \class GeneralProduct * \ingroup Core_Module * @@ -34,6 +35,8 @@ namespace Eigen { */ template::value> class GeneralProduct; +#endif // EIGEN_TEST_EVALUATORS + enum { Large = 2, @@ -154,6 +157,7 @@ template<> struct product_type_selector { enum } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS /** \class ProductReturnType * \ingroup Core_Module * @@ -201,6 +205,7 @@ struct ProductReturnType template struct LazyProductReturnType : public ProductReturnType {}; +#endif /*********************************************************************** * Implementation of Inner Vector Vector Product @@ -212,6 +217,7 @@ struct LazyProductReturnType : public ProductReturnType with: operator=(Scalar x); +#ifndef EIGEN_TEST_EVALUATORS namespace internal { @@ -242,7 +248,7 @@ class GeneralProduct return Base::coeff(0,0); } }; - +#endif // EIGEN_TEST_EVALUATORS /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index e7d525572..9a1c5f4f8 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -12,7 +12,7 @@ namespace Eigen { -// #ifndef EIGEN_TEST_EVALUATORS +#ifndef EIGEN_TEST_EVALUATORS /** \class SwapWrapper * \ingroup Core_Module @@ -137,7 +137,7 @@ template class SwapWrapper ExpressionType& m_expression; }; -// #endif +#endif #ifdef EIGEN_ENABLE_EVALUATORS diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 86de91ccb..e0236fd9e 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -770,7 +770,7 @@ struct solve_retval, Rhs> #endif /***** Implementation of inverse() *****************************************************/ - +#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -781,7 +781,7 @@ struct Assignment >, internal::assign_ dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; - +#endif } // end namespace internal /******* MatrixBase methods *****************************************************************/ diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index ac53f7ab5..65312f7d1 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -505,7 +505,7 @@ struct solve_retval, Rhs> #endif /***** Implementation of inverse() *****************************************************/ - +#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -516,7 +516,7 @@ struct Assignment >, internal::assi dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; - +#endif } // end namespace internal /******** MatrixBase methods *******/ -- cgit v1.2.3 From cbc572caf7c01854076d6ff84e5ae864b490458a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 24 Feb 2014 11:49:30 +0100 Subject: Split LU/Inverse.h to Core/Inverse.h for the generic Inverse expression, and LU/InverseImpl.h for the dense implementation of dense.inverse() --- Eigen/Core | 1 + Eigen/LU | 2 +- Eigen/src/Core/Inverse.h | 131 +++++++++++ Eigen/src/LU/Inverse.h | 572 --------------------------------------------- Eigen/src/LU/InverseImpl.h | 465 ++++++++++++++++++++++++++++++++++++ 5 files changed, 598 insertions(+), 573 deletions(-) create mode 100644 Eigen/src/Core/Inverse.h delete mode 100644 Eigen/src/LU/Inverse.h create mode 100644 Eigen/src/LU/InverseImpl.h diff --git a/Eigen/Core b/Eigen/Core index 245604465..474ef5f8f 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -365,6 +365,7 @@ using std::ptrdiff_t; #include "src/Core/GeneralProduct.h" #ifdef EIGEN_ENABLE_EVALUATORS #include "src/Core/Solve.h" +#include "src/Core/Inverse.h" #endif #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" diff --git a/Eigen/LU b/Eigen/LU index db5795504..fac80024f 100644 --- a/Eigen/LU +++ b/Eigen/LU @@ -25,7 +25,7 @@ #include "src/LU/PartialPivLU_MKL.h" #endif #include "src/LU/Determinant.h" -#include "src/LU/Inverse.h" +#include "src/LU/InverseImpl.h" #if defined EIGEN_VECTORIZE_SSE #include "src/LU/arch/Inverse_SSE.h" diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h new file mode 100644 index 000000000..0cfc71d34 --- /dev/null +++ b/Eigen/src/Core/Inverse.h @@ -0,0 +1,131 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +#ifdef EIGEN_TEST_EVALUATORS + +// TODO move the general declaration in Core, and rename this file DenseInverseImpl.h, or something like this... + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit, + CoeffReadCost = Dynamic + }; +}; + +} // end namespace internal + +/** \class Inverse + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an abstract expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::Index Index; + typedef typename XprType::PlainObject PlainObject; + typedef typename internal::nested::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + + Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested &m_xpr; +}; + +/** \internal + * Specialization of the Inverse expression for dense expressions. + * Direct access to the coefficients are discared. + * FIXME this intermediate class is probably not needed anymore. + */ +template +class InverseImpl + : public MatrixBase > +{ + typedef Inverse Derived; + +public: + + typedef MatrixBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ +template +struct evaluator > + : public evaluator::PlainObject>::type +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +#endif + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_H diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h deleted file mode 100644 index db053406e..000000000 --- a/Eigen/src/LU/Inverse.h +++ /dev/null @@ -1,572 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_INVERSE_H -#define EIGEN_INVERSE_H - -namespace Eigen { - -namespace internal { - -/********************************** -*** General case implementation *** -**********************************/ - -template -struct compute_inverse -{ - EIGEN_DEVICE_FUNC - static inline void run(const MatrixType& matrix, ResultType& result) - { - result = matrix.partialPivLu().inverse(); - } -}; - -template -struct compute_inverse_and_det_with_check { /* nothing! general case not supported. */ }; - -/**************************** -*** Size 1 implementation *** -****************************/ - -template -struct compute_inverse -{ - EIGEN_DEVICE_FUNC - static inline void run(const MatrixType& matrix, ResultType& result) - { - typedef typename MatrixType::Scalar Scalar; -#ifdef EIGEN_TEST_EVALUATORS - typename internal::evaluator::type matrixEval(matrix); - result.coeffRef(0,0) = Scalar(1) / matrixEval.coeff(0,0); -#else - result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); -#endif - } -}; - -template -struct compute_inverse_and_det_with_check -{ - EIGEN_DEVICE_FUNC - static inline void run( - const MatrixType& matrix, - const typename MatrixType::RealScalar& absDeterminantThreshold, - ResultType& result, - typename ResultType::Scalar& determinant, - bool& invertible - ) - { - using std::abs; - determinant = matrix.coeff(0,0); - invertible = abs(determinant) > absDeterminantThreshold; - if(invertible) result.coeffRef(0,0) = typename ResultType::Scalar(1) / determinant; - } -}; - -/**************************** -*** Size 2 implementation *** -****************************/ - -template -EIGEN_DEVICE_FUNC -inline void compute_inverse_size2_helper( - const MatrixType& matrix, const typename ResultType::Scalar& invdet, - ResultType& result) -{ - result.coeffRef(0,0) = matrix.coeff(1,1) * invdet; - result.coeffRef(1,0) = -matrix.coeff(1,0) * invdet; - result.coeffRef(0,1) = -matrix.coeff(0,1) * invdet; - result.coeffRef(1,1) = matrix.coeff(0,0) * invdet; -} - -template -struct compute_inverse -{ - EIGEN_DEVICE_FUNC - static inline void run(const MatrixType& matrix, ResultType& result) - { - typedef typename ResultType::Scalar Scalar; - const Scalar invdet = typename MatrixType::Scalar(1) / matrix.determinant(); - compute_inverse_size2_helper(matrix, invdet, result); - } -}; - -template -struct compute_inverse_and_det_with_check -{ - EIGEN_DEVICE_FUNC - static inline void run( - const MatrixType& matrix, - const typename MatrixType::RealScalar& absDeterminantThreshold, - ResultType& inverse, - typename ResultType::Scalar& determinant, - bool& invertible - ) - { - using std::abs; - typedef typename ResultType::Scalar Scalar; - determinant = matrix.determinant(); - invertible = abs(determinant) > absDeterminantThreshold; - if(!invertible) return; - const Scalar invdet = Scalar(1) / determinant; - compute_inverse_size2_helper(matrix, invdet, inverse); - } -}; - -/**************************** -*** Size 3 implementation *** -****************************/ - -template -EIGEN_DEVICE_FUNC -inline typename MatrixType::Scalar cofactor_3x3(const MatrixType& m) -{ - enum { - i1 = (i+1) % 3, - i2 = (i+2) % 3, - j1 = (j+1) % 3, - j2 = (j+2) % 3 - }; - return m.coeff(i1, j1) * m.coeff(i2, j2) - - m.coeff(i1, j2) * m.coeff(i2, j1); -} - -template -EIGEN_DEVICE_FUNC -inline void compute_inverse_size3_helper( - const MatrixType& matrix, - const typename ResultType::Scalar& invdet, - const Matrix& cofactors_col0, - ResultType& result) -{ - result.row(0) = cofactors_col0 * invdet; - result.coeffRef(1,0) = cofactor_3x3(matrix) * invdet; - result.coeffRef(1,1) = cofactor_3x3(matrix) * invdet; - result.coeffRef(1,2) = cofactor_3x3(matrix) * invdet; - result.coeffRef(2,0) = cofactor_3x3(matrix) * invdet; - result.coeffRef(2,1) = cofactor_3x3(matrix) * invdet; - result.coeffRef(2,2) = cofactor_3x3(matrix) * invdet; -} - -template -struct compute_inverse -{ - EIGEN_DEVICE_FUNC - static inline void run(const MatrixType& matrix, ResultType& result) - { - typedef typename ResultType::Scalar Scalar; - Matrix cofactors_col0; - cofactors_col0.coeffRef(0) = cofactor_3x3(matrix); - cofactors_col0.coeffRef(1) = cofactor_3x3(matrix); - cofactors_col0.coeffRef(2) = cofactor_3x3(matrix); - const Scalar det = (cofactors_col0.cwiseProduct(matrix.col(0))).sum(); - const Scalar invdet = Scalar(1) / det; - compute_inverse_size3_helper(matrix, invdet, cofactors_col0, result); - } -}; - -template -struct compute_inverse_and_det_with_check -{ - EIGEN_DEVICE_FUNC - static inline void run( - const MatrixType& matrix, - const typename MatrixType::RealScalar& absDeterminantThreshold, - ResultType& inverse, - typename ResultType::Scalar& determinant, - bool& invertible - ) - { - using std::abs; - typedef typename ResultType::Scalar Scalar; - Matrix cofactors_col0; - cofactors_col0.coeffRef(0) = cofactor_3x3(matrix); - cofactors_col0.coeffRef(1) = cofactor_3x3(matrix); - cofactors_col0.coeffRef(2) = cofactor_3x3(matrix); - determinant = (cofactors_col0.cwiseProduct(matrix.col(0))).sum(); - invertible = abs(determinant) > absDeterminantThreshold; - if(!invertible) return; - const Scalar invdet = Scalar(1) / determinant; - compute_inverse_size3_helper(matrix, invdet, cofactors_col0, inverse); - } -}; - -/**************************** -*** Size 4 implementation *** -****************************/ - -template -EIGEN_DEVICE_FUNC -inline const typename Derived::Scalar general_det3_helper -(const MatrixBase& matrix, int i1, int i2, int i3, int j1, int j2, int j3) -{ - return matrix.coeff(i1,j1) - * (matrix.coeff(i2,j2) * matrix.coeff(i3,j3) - matrix.coeff(i2,j3) * matrix.coeff(i3,j2)); -} - -template -EIGEN_DEVICE_FUNC -inline typename MatrixType::Scalar cofactor_4x4(const MatrixType& matrix) -{ - enum { - i1 = (i+1) % 4, - i2 = (i+2) % 4, - i3 = (i+3) % 4, - j1 = (j+1) % 4, - j2 = (j+2) % 4, - j3 = (j+3) % 4 - }; - return general_det3_helper(matrix, i1, i2, i3, j1, j2, j3) - + general_det3_helper(matrix, i2, i3, i1, j1, j2, j3) - + general_det3_helper(matrix, i3, i1, i2, j1, j2, j3); -} - -template -struct compute_inverse_size4 -{ - EIGEN_DEVICE_FUNC - static void run(const MatrixType& matrix, ResultType& result) - { - result.coeffRef(0,0) = cofactor_4x4(matrix); - result.coeffRef(1,0) = -cofactor_4x4(matrix); - result.coeffRef(2,0) = cofactor_4x4(matrix); - result.coeffRef(3,0) = -cofactor_4x4(matrix); - result.coeffRef(0,2) = cofactor_4x4(matrix); - result.coeffRef(1,2) = -cofactor_4x4(matrix); - result.coeffRef(2,2) = cofactor_4x4(matrix); - result.coeffRef(3,2) = -cofactor_4x4(matrix); - result.coeffRef(0,1) = -cofactor_4x4(matrix); - result.coeffRef(1,1) = cofactor_4x4(matrix); - result.coeffRef(2,1) = -cofactor_4x4(matrix); - result.coeffRef(3,1) = cofactor_4x4(matrix); - result.coeffRef(0,3) = -cofactor_4x4(matrix); - result.coeffRef(1,3) = cofactor_4x4(matrix); - result.coeffRef(2,3) = -cofactor_4x4(matrix); - result.coeffRef(3,3) = cofactor_4x4(matrix); - result /= (matrix.col(0).cwiseProduct(result.row(0).transpose())).sum(); - } -}; - -template -struct compute_inverse - : compute_inverse_size4 -{ -}; - -template -struct compute_inverse_and_det_with_check -{ - EIGEN_DEVICE_FUNC - static inline void run( - const MatrixType& matrix, - const typename MatrixType::RealScalar& absDeterminantThreshold, - ResultType& inverse, - typename ResultType::Scalar& determinant, - bool& invertible - ) - { - using std::abs; - determinant = matrix.determinant(); - invertible = abs(determinant) > absDeterminantThreshold; - if(invertible) compute_inverse::run(matrix, inverse); - } -}; - -/************************* -*** MatrixBase methods *** -*************************/ - -#ifndef EIGEN_TEST_EVALUATORS -template -struct traits > -{ - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct inverse_impl : public ReturnByValue > -{ - typedef typename MatrixType::Index Index; - typedef typename internal::eval::type MatrixTypeNested; - typedef typename remove_all::type MatrixTypeNestedCleaned; - MatrixTypeNested m_matrix; - - EIGEN_DEVICE_FUNC - inverse_impl(const MatrixType& matrix) - : m_matrix(matrix) - {} - - EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } - EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - - template - EIGEN_DEVICE_FUNC - inline void evalTo(Dest& dst) const - { - const int Size = EIGEN_PLAIN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime); - EIGEN_ONLY_USED_FOR_DEBUG(Size); - eigen_assert(( (Size<=1) || (Size>4) || (extract_data(m_matrix)!=extract_data(dst))) - && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); - - compute_inverse::run(m_matrix, dst); - } -}; -#endif -} // end namespace internal - -#ifdef EIGEN_TEST_EVALUATORS - -// TODO move the general declaration in Core, and rename this file DenseInverseImpl.h, or something like this... - -template class InverseImpl; - -namespace internal { - -template -struct traits > - : traits -{ - typedef typename XprType::PlainObject PlainObject; - typedef traits BaseTraits; - enum { - Flags = BaseTraits::Flags & RowMajorBit, - CoeffReadCost = Dynamic - }; -}; - -} // end namespace internal - -/** \class Inverse - * \ingroup LU_Module - * - * \brief Expression of the inverse of another expression - * - * \tparam XprType the type of the expression we are taking the inverse - * - * This class represents an abstract expression of A.inverse() - * and most of the time this is the only way it is used. - * - */ -template -class Inverse : public InverseImpl::StorageKind> -{ -public: - typedef typename XprType::Index Index; - typedef typename XprType::PlainObject PlainObject; - typedef typename internal::nested::type XprTypeNested; - typedef typename internal::remove_all::type XprTypeNestedCleaned; - - Inverse(const XprType &xpr) - : m_xpr(xpr) - {} - - EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } - EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } - - EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } - -protected: - XprTypeNested &m_xpr; -}; - -/** \internal - * Specialization of the Inverse expression for dense expressions. - * Direct access to the coefficients are discared. - * FIXME this intermediate class is probably not needed anymore. - */ -template -class InverseImpl - : public MatrixBase > -{ - typedef Inverse Derived; - -public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - -private: - - Scalar coeff(Index row, Index col) const; - Scalar coeff(Index i) const; -}; - -namespace internal { - -/** \internal - * \brief Default evaluator for Inverse expression. - * - * This default evaluator for Inverse expression simply evaluate the inverse into a temporary - * by a call to internal::call_assignment_no_alias. - * Therefore, inverse implementers only have to specialize Assignment, ...> for - * there own nested expression. - * - * \sa class Inverse - */ -template -struct evaluator > - : public evaluator::PlainObject>::type -{ - typedef Inverse InverseType; - typedef typename InverseType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - typedef evaluator type; - typedef evaluator nestedType; - - evaluator(const InverseType& inv_xpr) - : m_result(inv_xpr.rows(), inv_xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - internal::call_assignment_no_alias(m_result, inv_xpr); - } - -protected: - PlainObject m_result; -}; - -// Specialization for "dst = xpr.inverse()" -// NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere -template -struct Assignment, internal::assign_op, Dense2Dense, Scalar> -{ - typedef Inverse SrcXprType; - static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) - { - // FIXME shall we resize dst here? - const int Size = EIGEN_PLAIN_ENUM_MIN(XprType::ColsAtCompileTime,DstXprType::ColsAtCompileTime); - EIGEN_ONLY_USED_FOR_DEBUG(Size); - eigen_assert(( (Size<=1) || (Size>4) || (extract_data(src.nestedExpression())!=extract_data(dst))) - && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); - - typedef typename internal::nested_eval::type ActualXprType; - typedef typename internal::remove_all::type ActualXprTypeCleanded; - - ActualXprType actual_xpr(src.nestedExpression()); - - compute_inverse::run(actual_xpr, dst); - } -}; - - -} // end namespace internal - -#endif - -/** \lu_module - * - * \returns the matrix inverse of this matrix. - * - * For small fixed sizes up to 4x4, this method uses cofactors. - * In the general case, this method uses class PartialPivLU. - * - * \note This matrix must be invertible, otherwise the result is undefined. If you need an - * invertibility check, do the following: - * \li for fixed sizes up to 4x4, use computeInverseAndDetWithCheck(). - * \li for the general case, use class FullPivLU. - * - * Example: \include MatrixBase_inverse.cpp - * Output: \verbinclude MatrixBase_inverse.out - * - * \sa computeInverseAndDetWithCheck() - */ -#ifdef EIGEN_TEST_EVALUATORS -template -inline const Inverse MatrixBase::inverse() const -{ - EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) - eigen_assert(rows() == cols()); - return Inverse(derived()); -} -#else -template -inline const internal::inverse_impl MatrixBase::inverse() const -{ - EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) - eigen_assert(rows() == cols()); - return internal::inverse_impl(derived()); -} -#endif - -/** \lu_module - * - * Computation of matrix inverse and determinant, with invertibility check. - * - * This is only for fixed-size square matrices of size up to 4x4. - * - * \param inverse Reference to the matrix in which to store the inverse. - * \param determinant Reference to the variable in which to store the determinant. - * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. - * \param absDeterminantThreshold Optional parameter controlling the invertibility check. - * The matrix will be declared invertible if the absolute value of its - * determinant is greater than this threshold. - * - * Example: \include MatrixBase_computeInverseAndDetWithCheck.cpp - * Output: \verbinclude MatrixBase_computeInverseAndDetWithCheck.out - * - * \sa inverse(), computeInverseWithCheck() - */ -template -template -inline void MatrixBase::computeInverseAndDetWithCheck( - ResultType& inverse, - typename ResultType::Scalar& determinant, - bool& invertible, - const RealScalar& absDeterminantThreshold - ) const -{ - // i'd love to put some static assertions there, but SFINAE means that they have no effect... - eigen_assert(rows() == cols()); - // for 2x2, it's worth giving a chance to avoid evaluating. - // for larger sizes, evaluating has negligible cost and limits code size. - typedef typename internal::conditional< - RowsAtCompileTime == 2, - typename internal::remove_all::type>::type, - PlainObject - >::type MatrixType; - internal::compute_inverse_and_det_with_check::run - (derived(), absDeterminantThreshold, inverse, determinant, invertible); -} - -/** \lu_module - * - * Computation of matrix inverse, with invertibility check. - * - * This is only for fixed-size square matrices of size up to 4x4. - * - * \param inverse Reference to the matrix in which to store the inverse. - * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. - * \param absDeterminantThreshold Optional parameter controlling the invertibility check. - * The matrix will be declared invertible if the absolute value of its - * determinant is greater than this threshold. - * - * Example: \include MatrixBase_computeInverseWithCheck.cpp - * Output: \verbinclude MatrixBase_computeInverseWithCheck.out - * - * \sa inverse(), computeInverseAndDetWithCheck() - */ -template -template -inline void MatrixBase::computeInverseWithCheck( - ResultType& inverse, - bool& invertible, - const RealScalar& absDeterminantThreshold - ) const -{ - RealScalar determinant; - // i'd love to put some static assertions there, but SFINAE means that they have no effect... - eigen_assert(rows() == cols()); - computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold); -} - -} // end namespace Eigen - -#endif // EIGEN_INVERSE_H diff --git a/Eigen/src/LU/InverseImpl.h b/Eigen/src/LU/InverseImpl.h new file mode 100644 index 000000000..174dfbac5 --- /dev/null +++ b/Eigen/src/LU/InverseImpl.h @@ -0,0 +1,465 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Benoit Jacob +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_IMPL_H +#define EIGEN_INVERSE_IMPL_H + +namespace Eigen { + +namespace internal { + +/********************************** +*** General case implementation *** +**********************************/ + +template +struct compute_inverse +{ + EIGEN_DEVICE_FUNC + static inline void run(const MatrixType& matrix, ResultType& result) + { + result = matrix.partialPivLu().inverse(); + } +}; + +template +struct compute_inverse_and_det_with_check { /* nothing! general case not supported. */ }; + +/**************************** +*** Size 1 implementation *** +****************************/ + +template +struct compute_inverse +{ + EIGEN_DEVICE_FUNC + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename MatrixType::Scalar Scalar; +#ifdef EIGEN_TEST_EVALUATORS + typename internal::evaluator::type matrixEval(matrix); + result.coeffRef(0,0) = Scalar(1) / matrixEval.coeff(0,0); +#else + result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); +#endif + } +}; + +template +struct compute_inverse_and_det_with_check +{ + EIGEN_DEVICE_FUNC + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& result, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + using std::abs; + determinant = matrix.coeff(0,0); + invertible = abs(determinant) > absDeterminantThreshold; + if(invertible) result.coeffRef(0,0) = typename ResultType::Scalar(1) / determinant; + } +}; + +/**************************** +*** Size 2 implementation *** +****************************/ + +template +EIGEN_DEVICE_FUNC +inline void compute_inverse_size2_helper( + const MatrixType& matrix, const typename ResultType::Scalar& invdet, + ResultType& result) +{ + result.coeffRef(0,0) = matrix.coeff(1,1) * invdet; + result.coeffRef(1,0) = -matrix.coeff(1,0) * invdet; + result.coeffRef(0,1) = -matrix.coeff(0,1) * invdet; + result.coeffRef(1,1) = matrix.coeff(0,0) * invdet; +} + +template +struct compute_inverse +{ + EIGEN_DEVICE_FUNC + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename ResultType::Scalar Scalar; + const Scalar invdet = typename MatrixType::Scalar(1) / matrix.determinant(); + compute_inverse_size2_helper(matrix, invdet, result); + } +}; + +template +struct compute_inverse_and_det_with_check +{ + EIGEN_DEVICE_FUNC + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + using std::abs; + typedef typename ResultType::Scalar Scalar; + determinant = matrix.determinant(); + invertible = abs(determinant) > absDeterminantThreshold; + if(!invertible) return; + const Scalar invdet = Scalar(1) / determinant; + compute_inverse_size2_helper(matrix, invdet, inverse); + } +}; + +/**************************** +*** Size 3 implementation *** +****************************/ + +template +EIGEN_DEVICE_FUNC +inline typename MatrixType::Scalar cofactor_3x3(const MatrixType& m) +{ + enum { + i1 = (i+1) % 3, + i2 = (i+2) % 3, + j1 = (j+1) % 3, + j2 = (j+2) % 3 + }; + return m.coeff(i1, j1) * m.coeff(i2, j2) + - m.coeff(i1, j2) * m.coeff(i2, j1); +} + +template +EIGEN_DEVICE_FUNC +inline void compute_inverse_size3_helper( + const MatrixType& matrix, + const typename ResultType::Scalar& invdet, + const Matrix& cofactors_col0, + ResultType& result) +{ + result.row(0) = cofactors_col0 * invdet; + result.coeffRef(1,0) = cofactor_3x3(matrix) * invdet; + result.coeffRef(1,1) = cofactor_3x3(matrix) * invdet; + result.coeffRef(1,2) = cofactor_3x3(matrix) * invdet; + result.coeffRef(2,0) = cofactor_3x3(matrix) * invdet; + result.coeffRef(2,1) = cofactor_3x3(matrix) * invdet; + result.coeffRef(2,2) = cofactor_3x3(matrix) * invdet; +} + +template +struct compute_inverse +{ + EIGEN_DEVICE_FUNC + static inline void run(const MatrixType& matrix, ResultType& result) + { + typedef typename ResultType::Scalar Scalar; + Matrix cofactors_col0; + cofactors_col0.coeffRef(0) = cofactor_3x3(matrix); + cofactors_col0.coeffRef(1) = cofactor_3x3(matrix); + cofactors_col0.coeffRef(2) = cofactor_3x3(matrix); + const Scalar det = (cofactors_col0.cwiseProduct(matrix.col(0))).sum(); + const Scalar invdet = Scalar(1) / det; + compute_inverse_size3_helper(matrix, invdet, cofactors_col0, result); + } +}; + +template +struct compute_inverse_and_det_with_check +{ + EIGEN_DEVICE_FUNC + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + using std::abs; + typedef typename ResultType::Scalar Scalar; + Matrix cofactors_col0; + cofactors_col0.coeffRef(0) = cofactor_3x3(matrix); + cofactors_col0.coeffRef(1) = cofactor_3x3(matrix); + cofactors_col0.coeffRef(2) = cofactor_3x3(matrix); + determinant = (cofactors_col0.cwiseProduct(matrix.col(0))).sum(); + invertible = abs(determinant) > absDeterminantThreshold; + if(!invertible) return; + const Scalar invdet = Scalar(1) / determinant; + compute_inverse_size3_helper(matrix, invdet, cofactors_col0, inverse); + } +}; + +/**************************** +*** Size 4 implementation *** +****************************/ + +template +EIGEN_DEVICE_FUNC +inline const typename Derived::Scalar general_det3_helper +(const MatrixBase& matrix, int i1, int i2, int i3, int j1, int j2, int j3) +{ + return matrix.coeff(i1,j1) + * (matrix.coeff(i2,j2) * matrix.coeff(i3,j3) - matrix.coeff(i2,j3) * matrix.coeff(i3,j2)); +} + +template +EIGEN_DEVICE_FUNC +inline typename MatrixType::Scalar cofactor_4x4(const MatrixType& matrix) +{ + enum { + i1 = (i+1) % 4, + i2 = (i+2) % 4, + i3 = (i+3) % 4, + j1 = (j+1) % 4, + j2 = (j+2) % 4, + j3 = (j+3) % 4 + }; + return general_det3_helper(matrix, i1, i2, i3, j1, j2, j3) + + general_det3_helper(matrix, i2, i3, i1, j1, j2, j3) + + general_det3_helper(matrix, i3, i1, i2, j1, j2, j3); +} + +template +struct compute_inverse_size4 +{ + EIGEN_DEVICE_FUNC + static void run(const MatrixType& matrix, ResultType& result) + { + result.coeffRef(0,0) = cofactor_4x4(matrix); + result.coeffRef(1,0) = -cofactor_4x4(matrix); + result.coeffRef(2,0) = cofactor_4x4(matrix); + result.coeffRef(3,0) = -cofactor_4x4(matrix); + result.coeffRef(0,2) = cofactor_4x4(matrix); + result.coeffRef(1,2) = -cofactor_4x4(matrix); + result.coeffRef(2,2) = cofactor_4x4(matrix); + result.coeffRef(3,2) = -cofactor_4x4(matrix); + result.coeffRef(0,1) = -cofactor_4x4(matrix); + result.coeffRef(1,1) = cofactor_4x4(matrix); + result.coeffRef(2,1) = -cofactor_4x4(matrix); + result.coeffRef(3,1) = cofactor_4x4(matrix); + result.coeffRef(0,3) = -cofactor_4x4(matrix); + result.coeffRef(1,3) = cofactor_4x4(matrix); + result.coeffRef(2,3) = -cofactor_4x4(matrix); + result.coeffRef(3,3) = cofactor_4x4(matrix); + result /= (matrix.col(0).cwiseProduct(result.row(0).transpose())).sum(); + } +}; + +template +struct compute_inverse + : compute_inverse_size4 +{ +}; + +template +struct compute_inverse_and_det_with_check +{ + EIGEN_DEVICE_FUNC + static inline void run( + const MatrixType& matrix, + const typename MatrixType::RealScalar& absDeterminantThreshold, + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible + ) + { + using std::abs; + determinant = matrix.determinant(); + invertible = abs(determinant) > absDeterminantThreshold; + if(invertible) compute_inverse::run(matrix, inverse); + } +}; + +/************************* +*** MatrixBase methods *** +*************************/ + +#ifndef EIGEN_TEST_EVALUATORS +template +struct traits > +{ + typedef typename MatrixType::PlainObject ReturnType; +}; + +template +struct inverse_impl : public ReturnByValue > +{ + typedef typename MatrixType::Index Index; + typedef typename internal::eval::type MatrixTypeNested; + typedef typename remove_all::type MatrixTypeNestedCleaned; + MatrixTypeNested m_matrix; + + EIGEN_DEVICE_FUNC + inverse_impl(const MatrixType& matrix) + : m_matrix(matrix) + {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } + + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const + { + const int Size = EIGEN_PLAIN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime); + EIGEN_ONLY_USED_FOR_DEBUG(Size); + eigen_assert(( (Size<=1) || (Size>4) || (extract_data(m_matrix)!=extract_data(dst))) + && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + + compute_inverse::run(m_matrix, dst); + } +}; +#endif +} // end namespace internal + +#ifdef EIGEN_TEST_EVALUATORS + +namespace internal { + +// Specialization for "dense = dense_xpr.inverse()" +template +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + // FIXME shall we resize dst here? + const int Size = EIGEN_PLAIN_ENUM_MIN(XprType::ColsAtCompileTime,DstXprType::ColsAtCompileTime); + EIGEN_ONLY_USED_FOR_DEBUG(Size); + eigen_assert(( (Size<=1) || (Size>4) || (extract_data(src.nestedExpression())!=extract_data(dst))) + && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + + typedef typename internal::nested_eval::type ActualXprType; + typedef typename internal::remove_all::type ActualXprTypeCleanded; + + ActualXprType actual_xpr(src.nestedExpression()); + + compute_inverse::run(actual_xpr, dst); + } +}; + + +} // end namespace internal + +#endif + +/** \lu_module + * + * \returns the matrix inverse of this matrix. + * + * For small fixed sizes up to 4x4, this method uses cofactors. + * In the general case, this method uses class PartialPivLU. + * + * \note This matrix must be invertible, otherwise the result is undefined. If you need an + * invertibility check, do the following: + * \li for fixed sizes up to 4x4, use computeInverseAndDetWithCheck(). + * \li for the general case, use class FullPivLU. + * + * Example: \include MatrixBase_inverse.cpp + * Output: \verbinclude MatrixBase_inverse.out + * + * \sa computeInverseAndDetWithCheck() + */ +#ifdef EIGEN_TEST_EVALUATORS +template +inline const Inverse MatrixBase::inverse() const +{ + EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) + eigen_assert(rows() == cols()); + return Inverse(derived()); +} +#else +template +inline const internal::inverse_impl MatrixBase::inverse() const +{ + EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) + eigen_assert(rows() == cols()); + return internal::inverse_impl(derived()); +} +#endif + +/** \lu_module + * + * Computation of matrix inverse and determinant, with invertibility check. + * + * This is only for fixed-size square matrices of size up to 4x4. + * + * \param inverse Reference to the matrix in which to store the inverse. + * \param determinant Reference to the variable in which to store the determinant. + * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. + * \param absDeterminantThreshold Optional parameter controlling the invertibility check. + * The matrix will be declared invertible if the absolute value of its + * determinant is greater than this threshold. + * + * Example: \include MatrixBase_computeInverseAndDetWithCheck.cpp + * Output: \verbinclude MatrixBase_computeInverseAndDetWithCheck.out + * + * \sa inverse(), computeInverseWithCheck() + */ +template +template +inline void MatrixBase::computeInverseAndDetWithCheck( + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible, + const RealScalar& absDeterminantThreshold + ) const +{ + // i'd love to put some static assertions there, but SFINAE means that they have no effect... + eigen_assert(rows() == cols()); + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost and limits code size. + typedef typename internal::conditional< + RowsAtCompileTime == 2, + typename internal::remove_all::type>::type, + PlainObject + >::type MatrixType; + internal::compute_inverse_and_det_with_check::run + (derived(), absDeterminantThreshold, inverse, determinant, invertible); +} + +/** \lu_module + * + * Computation of matrix inverse, with invertibility check. + * + * This is only for fixed-size square matrices of size up to 4x4. + * + * \param inverse Reference to the matrix in which to store the inverse. + * \param invertible Reference to the bool variable in which to store whether the matrix is invertible. + * \param absDeterminantThreshold Optional parameter controlling the invertibility check. + * The matrix will be declared invertible if the absolute value of its + * determinant is greater than this threshold. + * + * Example: \include MatrixBase_computeInverseWithCheck.cpp + * Output: \verbinclude MatrixBase_computeInverseWithCheck.out + * + * \sa inverse(), computeInverseAndDetWithCheck() + */ +template +template +inline void MatrixBase::computeInverseWithCheck( + ResultType& inverse, + bool& invertible, + const RealScalar& absDeterminantThreshold + ) const +{ + RealScalar determinant; + // i'd love to put some static assertions there, but SFINAE means that they have no effect... + eigen_assert(rows() == cols()); + computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold); +} + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_IMPL_H -- cgit v1.2.3 From 5c0f294098f628439cf9341edb286d92f7fa138b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 10 Mar 2014 09:28:00 +0100 Subject: Fix evaluators unit test (i.e., when only EIGEN_ENABLE_EVALUATORS is defined --- Eigen/src/Core/GeneralProduct.h | 25 +++++--- Eigen/src/Core/ProductEvaluators.h | 2 +- Eigen/src/Core/products/GeneralMatrixMatrix.h | 6 +- Eigen/src/Core/products/SelfadjointMatrixMatrix.h | 5 +- Eigen/src/Core/products/TriangularMatrixMatrix.h | 5 +- Eigen/src/Core/util/XprHelper.h | 76 ++++++++++++----------- 6 files changed, 67 insertions(+), 52 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index c37526b72..f28d2e46c 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -353,10 +353,13 @@ template struct traits > : traits, Lhs, Rhs> > {}; -#endif - template struct gemv_selector; +#endif +#ifdef EIGEN_ENABLE_EVALUATORS +template +struct gemv_dense_sense_selector; +#endif } // end namespace internal @@ -594,23 +597,25 @@ template<> struct gemv_selector } }; -#else // EIGEN_TEST_EVALUATORS +#endif // EIGEN_TEST_EVALUATORS + +#ifdef EIGEN_ENABLE_EVALUATORS // The vector is on the left => transposition template -struct gemv_selector +struct gemv_dense_sense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { Transpose destT(dest); enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector + gemv_dense_sense_selector ::run(rhs.transpose(), lhs.transpose(), destT, alpha); } }; -template<> struct gemv_selector +template<> struct gemv_dense_sense_selector { template static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) @@ -685,7 +690,7 @@ template<> struct gemv_selector } }; -template<> struct gemv_selector +template<> struct gemv_dense_sense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) @@ -737,7 +742,7 @@ template<> struct gemv_selector } }; -template<> struct gemv_selector +template<> struct gemv_dense_sense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) @@ -750,7 +755,7 @@ template<> struct gemv_selector } }; -template<> struct gemv_selector +template<> struct gemv_dense_sense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) @@ -763,7 +768,7 @@ template<> struct gemv_selector } }; -#endif // EIGEN_TEST_EVALUATORS +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace internal diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 186ae4a34..b16b86d8f 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -304,7 +304,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - internal::gemv_selector::HasUsableDirectAccess) >::run(lhs, rhs, dst, alpha); diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 1c8940e1c..1726f98ed 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -422,7 +422,9 @@ class GeneralProduct internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>(GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), this->rows(), this->cols(), Dest::Flags&RowMajorBit); } }; -#else // EIGEN_TEST_EVALUATORS +#endif // EIGEN_TEST_EVALUATORS + +#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -477,7 +479,7 @@ struct generic_product_impl }; } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h index f252aef85..afa8af43c 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h @@ -431,7 +431,8 @@ struct SelfadjointProductMatrix ); } }; -#else // EIGEN_TEST_EVALUATORS +#endif // EIGEN_TEST_EVALUATORS +#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -481,7 +482,7 @@ struct selfadjoint_product_impl } // end namespace internal -#endif +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix.h b/Eigen/src/Core/products/TriangularMatrixMatrix.h index e654b45b1..3f0618410 100644 --- a/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -421,7 +421,8 @@ struct TriangularProduct ); } }; -#else // EIGEN_TEST_EVALUATORS +#endif // EIGEN_TEST_EVALUATORS +#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template struct triangular_product_impl @@ -471,7 +472,7 @@ struct triangular_product_impl }; } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS +#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 76e979ba0..a4baa921c 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -293,44 +293,10 @@ struct transfer_constness >::type type; }; -#ifdef EIGEN_TEST_EVALUATORS -// When using evaluators, we never evaluate when assembling the expression!! -// TODO: get rid of this nested class since it's just an alias for ref_selector. -template::type> struct nested -{ - typedef typename ref_selector::type type; -}; -// However, we still need a mechanism to detect whether an expression which is evaluated multiple time -// has to be evaluated into a temporary. -// That's the purpose of this new nested_eval helper: -template::type> struct nested_eval -{ - enum { - // For the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. - // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. - // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues - // (poor choice of temporaries). - // It's important that this value can still be squared without integer overflowing. - DynamicAsInteger = 10000, - ScalarReadCost = NumTraits::Scalar>::ReadCost, - ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), - CoeffReadCost = traits::CoeffReadCost, - CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), - NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, - CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, - CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger - }; - - typedef typename conditional< - int(CostEvalAsInteger) < int(CostNoEvalAsInteger), - PlainObject, - typename ref_selector::type - >::type type; -}; +#ifndef EIGEN_TEST_EVALUATORS -#else /** \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 @@ -377,8 +343,48 @@ template::type> str typename ref_selector::type >::type type; }; + +#else + +// When using evaluators, we never evaluate when assembling the expression!! +// TODO: get rid of this nested class since it's just an alias for ref_selector. +template::type> struct nested +{ + typedef typename ref_selector::type type; +}; + #endif // EIGEN_TEST_EVALUATORS +#ifdef EIGEN_ENABLE_EVALUATORS +// However, we still need a mechanism to detect whether an expression which is evaluated multiple time +// has to be evaluated into a temporary. +// That's the purpose of this new nested_eval helper: +template::type> struct nested_eval +{ + enum { + // For the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. + // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. + // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues + // (poor choice of temporaries). + // It's important that this value can still be squared without integer overflowing. + DynamicAsInteger = 10000, + ScalarReadCost = NumTraits::Scalar>::ReadCost, + ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), + CoeffReadCost = traits::CoeffReadCost, + CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), + NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, + CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, + CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger + }; + + typedef typename conditional< + int(CostEvalAsInteger) < int(CostNoEvalAsInteger), + PlainObject, + typename ref_selector::type + >::type type; +}; +#endif + template EIGEN_DEVICE_FUNC T* const_cast_ptr(const T* ptr) -- cgit v1.2.3 From 354bd8a42837ac405a142281fca2c4ac59ff701f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 10 Mar 2014 09:30:58 +0100 Subject: Hide legacy dense assignment routines with EIGEN_TEST_EVALUATORS --- Eigen/src/Core/Assign.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 6080a83f6..95306a9a7 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -13,7 +13,7 @@ #define EIGEN_ASSIGN_H namespace Eigen { - +#ifndef EIGEN_TEST_EVALUATORS namespace internal { /*************************************************************************** @@ -487,6 +487,8 @@ struct assign_impl Date: Mon, 10 Mar 2014 23:24:40 +0100 Subject: Move CoeffReadCost mechanism to evaluators --- Eigen/src/Core/ArrayBase.h | 4 +- Eigen/src/Core/Assign.h | 3 - Eigen/src/Core/AssignEvaluator.h | 64 ++++++++-------- Eigen/src/Core/BooleanRedux.h | 29 ++++++-- Eigen/src/Core/CoreEvaluators.h | 111 ++++++++++++++++++++-------- Eigen/src/Core/CwiseBinaryOp.h | 9 ++- Eigen/src/Core/CwiseNullaryOp.h | 5 +- Eigen/src/Core/CwiseUnaryOp.h | 5 +- Eigen/src/Core/CwiseUnaryView.h | 2 + Eigen/src/Core/DenseBase.h | 2 + Eigen/src/Core/Diagonal.h | 2 + Eigen/src/Core/DiagonalMatrix.h | 5 +- Eigen/src/Core/DiagonalProduct.h | 5 +- Eigen/src/Core/Matrix.h | 2 + Eigen/src/Core/MatrixBase.h | 4 +- Eigen/src/Core/ProductEvaluators.h | 48 +++++++----- Eigen/src/Core/Redux.h | 2 +- Eigen/src/Core/Replicate.h | 5 +- Eigen/src/Core/Reverse.h | 6 +- Eigen/src/Core/Select.h | 5 +- Eigen/src/Core/Transpose.h | 2 + Eigen/src/Core/TriangularMatrix.h | 15 ++-- Eigen/src/Core/VectorwiseOp.h | 2 + Eigen/src/Core/Visitor.h | 43 +++++++++++ Eigen/src/Core/products/CoeffBasedProduct.h | 8 +- Eigen/src/Core/util/Macros.h | 41 ++++++++++ Eigen/src/Core/util/XprHelper.h | 4 +- 27 files changed, 317 insertions(+), 116 deletions(-) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index e67ca34cd..d1c422836 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -64,8 +64,10 @@ template class ArrayBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; +#ifndef EIGEN_TEST_EVALUATORS using Base::CoeffReadCost; - +#endif + using Base::derived; using Base::const_cast_derived; using Base::rows; diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 95306a9a7..95eb37dd5 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -508,9 +508,6 @@ EIGEN_STRONG_INLINE Derived& DenseBase #ifdef EIGEN_TEST_EVALUATORS -#ifdef EIGEN_DEBUG_ASSIGN - internal::copy_using_evaluator_traits::debug(); -#endif eigen_assert(rows() == other.rows() && cols() == other.cols()); internal::call_dense_assignment_loop(derived(),other.derived()); diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 14effd1f2..2ea1cc126 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -24,37 +24,45 @@ namespace internal { // copy_using_evaluator_traits is based on assign_traits -template +template struct copy_using_evaluator_traits { + typedef typename DstEvaluator::XprType Dst; + typedef typename SrcEvaluator::XprType Src; + // TODO, we should get these flags from the evaluators + enum { + DstFlags = Dst::Flags, + SrcFlags = Src::Flags + }; + public: enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, + DstIsAligned = DstFlags & AlignedBit, + DstHasDirectAccess = DstFlags & DirectAccessBit, + SrcIsAligned = SrcFlags & AlignedBit, JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned }; private: enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime, + PacketSize = packet_traits::size }; enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), + StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit) + && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) && (functor_traits::PacketAccess), MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), + MayLinearize = StorageOrdersAgree && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, @@ -81,12 +89,12 @@ public: private: enum { UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), + MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic + && int(SrcEvaluator::CoeffReadCost) != Dynamic + && int(Dst::SizeAtCompileTime) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit), MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) + && int(SrcEvaluator::CoeffReadCost) != Dynamic + && int(InnerSize) * int(SrcEvaluator::CoeffReadCost) <= int(UnrollingLimit) }; public: @@ -518,12 +526,16 @@ public: typedef SrcEvaluatorTypeT SrcEvaluatorType; typedef typename DstEvaluatorType::Scalar Scalar; typedef typename DstEvaluatorType::Index Index; - typedef copy_using_evaluator_traits AssignmentTraits; + typedef copy_using_evaluator_traits AssignmentTraits; generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) - {} + { + #ifdef EIGEN_DEBUG_ASSIGN + AssignmentTraits::debug(); + #endif + } Index size() const { return m_dstExpr.size(); } Index innerSize() const { return m_dstExpr.innerSize(); } @@ -612,10 +624,6 @@ protected: template void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { -#ifdef EIGEN_DEBUG_ASSIGN - // TODO these traits should be computed from information provided by the evaluators - internal::copy_using_evaluator_traits::debug(); -#endif eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); typedef typename evaluator::type DstEvaluatorType; @@ -750,10 +758,6 @@ struct Assignment { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); - #ifdef EIGEN_DEBUG_ASSIGN - internal::copy_using_evaluator_traits::debug(); - #endif - call_dense_assignment_loop(dst, src, func); } }; diff --git a/Eigen/src/Core/BooleanRedux.h b/Eigen/src/Core/BooleanRedux.h index f0b68f470..192e1db53 100644 --- a/Eigen/src/Core/BooleanRedux.h +++ b/Eigen/src/Core/BooleanRedux.h @@ -94,14 +94,14 @@ struct any_unroller template inline bool DenseBase::all() const { +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::evaluator::type Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic + && Evaluator::CoeffReadCost != Dynamic && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; -#ifdef EIGEN_TEST_EVALUATORS - typedef typename internal::evaluator::type Evaluator; Evaluator evaluator(derived()); if(unroll) return internal::all_unroller::run(evaluator); @@ -113,6 +113,13 @@ inline bool DenseBase::all() const return true; } #else + enum { + unroll = SizeAtCompileTime != Dynamic + && CoeffReadCost != Dynamic + && NumTraits::AddCost != Dynamic + && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + }; + if(unroll) return internal::all_unroller::run(derived()); else @@ -132,14 +139,14 @@ inline bool DenseBase::all() const template inline bool DenseBase::any() const { +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::evaluator::type Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic + && Evaluator::CoeffReadCost != Dynamic && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; -#ifdef EIGEN_TEST_EVALUATORS - typedef typename internal::evaluator::type Evaluator; Evaluator evaluator(derived()); if(unroll) return internal::any_unroller::run(evaluator); @@ -151,6 +158,12 @@ inline bool DenseBase::any() const return false; } #else + enum { + unroll = SizeAtCompileTime != Dynamic + && CoeffReadCost != Dynamic + && NumTraits::AddCost != Dynamic + && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + }; if(unroll) return internal::any_unroller::run(derived()); else diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 92b50d190..33c89c2d4 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -71,7 +71,7 @@ struct evaluator_traits_base // typedef evaluator type; // typedef evaluator nestedType; - // by default, get evalautor kind and shape from storage + // by default, get evaluator kind and shape from storage typedef typename storage_kind_to_evaluator_kind::Kind Kind; typedef typename storage_kind_to_shape::Shape Shape; @@ -124,12 +124,19 @@ struct evaluator > : evaluator_base { typedef PlainObjectBase PlainObjectType; + typedef typename PlainObjectType::Index Index; + typedef typename PlainObjectType::Scalar Scalar; + typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; + typedef typename PlainObjectType::PacketScalar PacketScalar; + typedef typename PlainObjectType::PacketReturnType PacketReturnType; enum { IsRowMajor = PlainObjectType::IsRowMajor, IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, - ColsAtCompileTime = PlainObjectType::ColsAtCompileTime + ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, + + CoeffReadCost = NumTraits::ReadCost }; evaluator() @@ -143,12 +150,6 @@ struct evaluator > : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { } - typedef typename PlainObjectType::Index Index; - typedef typename PlainObjectType::Scalar Scalar; - typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; - typedef typename PlainObjectType::PacketScalar PacketScalar; - typedef typename PlainObjectType::PacketReturnType PacketReturnType; - CoeffReturnType coeff(Index row, Index col) const { if (IsRowMajor) @@ -320,6 +321,10 @@ struct evaluator > : evaluator_base > { typedef Transpose XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + }; evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} @@ -384,6 +389,10 @@ struct evaluator > : evaluator_base > { typedef CwiseNullaryOp XprType; + + enum { + CoeffReadCost = internal::functor_traits::Cost + }; evaluator(const XprType& n) : m_functor(n.functor()) @@ -426,6 +435,10 @@ struct evaluator > : evaluator_base > { typedef CwiseUnaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost + }; evaluator(const XprType& op) : m_functor(op.functor()), @@ -470,6 +483,10 @@ struct evaluator > : evaluator_base > { typedef CwiseBinaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost + }; evaluator(const XprType& xpr) : m_functor(xpr.functor()), @@ -518,6 +535,10 @@ struct evaluator > : evaluator_base > { typedef CwiseUnaryView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost + }; evaluator(const XprType& op) : m_unaryOp(op.functor()), @@ -561,7 +582,6 @@ struct evaluator > { typedef MapBase MapType; typedef Derived XprType; - typedef typename XprType::PointerType PointerType; typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -569,16 +589,17 @@ struct evaluator > typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime, + CoeffReadCost = NumTraits::ReadCost + }; + evaluator(const XprType& map) : m_data(const_cast(map.data())), m_rowStride(map.rowStride()), m_colStride(map.colStride()) { } - enum { - RowsAtCompileTime = XprType::RowsAtCompileTime - }; - CoeffReturnType coeff(Index row, Index col) const { return m_data[col * m_colStride + row * m_rowStride]; @@ -670,6 +691,9 @@ struct evaluator > : block_evaluator { typedef Block XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + }; typedef block_evaluator block_evaluator_type; evaluator(const XprType& block) : block_evaluator_type(block) {} }; @@ -703,8 +727,7 @@ struct block_evaluator @@ -728,7 +750,7 @@ struct block_evaluator(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + RowsAtCompileTime == 1 ? index : 0); } template @@ -741,8 +763,8 @@ struct block_evaluator(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0, - x); + RowsAtCompileTime == 1 ? index : 0, + x); } protected: @@ -773,6 +795,11 @@ struct evaluator > : evaluator_base > { typedef Select XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + + EIGEN_SIZE_MAX(evaluator::CoeffReadCost, + evaluator::CoeffReadCost) + }; evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), @@ -813,6 +840,18 @@ struct evaluator > : evaluator_base > { typedef Replicate XprType; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketReturnType PacketReturnType; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + }; evaluator(const XprType& replicate) : m_arg(replicate.nestedExpression()), @@ -821,10 +860,6 @@ struct evaluator > m_cols(replicate.nestedExpression().cols()) { } - typedef typename XprType::Index Index; - typedef typename XprType::CoeffReturnType CoeffReturnType; - typedef typename XprType::PacketReturnType PacketReturnType; - CoeffReturnType coeff(Index row, Index col) const { // try to avoid using modulo; this is a pure optimization strategy @@ -852,13 +887,7 @@ struct evaluator > } protected: - enum { - Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor - }; - typedef typename internal::nested_eval::type ArgTypeNested; - typedef typename internal::remove_all::type ArgTypeNestedCleaned; - - const ArgTypeNested m_arg; // FIXME is it OK to store both the argument and its evaluator?? (we have the same situation in evalautor_product) + const ArgTypeNested m_arg; // FIXME is it OK to store both the argument and its evaluator?? (we have the same situation in evaluator_product) typename evaluator::nestedType m_argImpl; const variable_if_dynamic m_rows; const variable_if_dynamic m_cols; @@ -876,6 +905,15 @@ struct evaluator > : evaluator_base > { typedef PartialReduxExpr XprType; + typedef typename XprType::Scalar InputScalar; + enum { + TraversalSize = Direction==Vertical ? XprType::RowsAtCompileTime : XprType::ColsAtCompileTime + }; + typedef typename MemberOp::template Cost CostOpType; + enum { + CoeffReadCost = TraversalSize==Dynamic ? Dynamic + : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value) + }; evaluator(const XprType expr) : m_expr(expr) @@ -909,6 +947,9 @@ struct evaluator_wrapper_base : evaluator_base { typedef typename remove_all::type ArgType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + }; evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} @@ -1015,7 +1056,9 @@ struct evaluator > OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, ReversePacket = (Direction == BothDirections) || ((Direction == Vertical) && IsColMajor) - || ((Direction == Horizontal) && IsRowMajor) + || ((Direction == Horizontal) && IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost }; typedef internal::reverse_packet_cond reverse_packet; @@ -1093,6 +1136,10 @@ struct evaluator > : evaluator_base > { typedef Diagonal XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + }; evaluator(const XprType& diagonal) : m_argImpl(diagonal.nestedExpression()), diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index c78067a88..105e7fb11 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -65,8 +65,6 @@ struct traits > typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, LhsFlags = _LhsNested::Flags, RhsFlags = _RhsNested::Flags, SameType = is_same::value, @@ -80,8 +78,13 @@ struct traits > ) ) ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) +#ifndef EIGEN_TEST_EVALUATORS + , + LhsCoeffReadCost = _LhsNested::CoeffReadCost, + RhsCoeffReadCost = _RhsNested::CoeffReadCost, CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost +#endif }; }; } // end namespace internal diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index 124383114..560e03f12 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -39,8 +39,11 @@ struct traits > : traits::ret ? LinearAccessBit : 0) | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = functor_traits::Cost +#endif }; }; } diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index aa7df197f..25da52ab7 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -46,8 +46,11 @@ struct traits > enum { Flags = _XprTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + | (functor_traits::PacketAccess ? PacketAccessBit : 0)) +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost +#endif }; }; } diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index b2638d326..a0bd80fb9 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -38,7 +38,9 @@ struct traits > typedef typename remove_all::type _MatrixTypeNested; enum { Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, +#endif MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 2fea574dd..f3c79aa31 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -169,10 +169,12 @@ template class DenseBase InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = internal::traits::CoeffReadCost, /**< This is a rough measure of how expensive it is to read one coefficient from * this expression. */ +#endif InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index b160479ab..02ab04980 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -53,7 +53,9 @@ struct traits > MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = _MatrixTypeNested::CoeffReadCost, +#endif MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 8df636928..784e4b1ce 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -280,8 +280,11 @@ struct traits > ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit, + Flags = traits::Flags & LvalueBit +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = traits<_DiagonalVectorType>::CoeffReadCost +#endif }; }; } diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index f5539df13..840b70dbb 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -35,8 +35,11 @@ struct traits > _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit //(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost +#endif }; }; } diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index c2cedbf6a..f84db0dc2 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -115,7 +115,9 @@ struct traits > MaxRowsAtCompileTime = _MaxRows, MaxColsAtCompileTime = _MaxCols, Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = NumTraits::ReadCost, +#endif Options = _Options, InnerStrideAtCompileTime = 1, OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 72aa75da8..1f9f295c9 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -66,8 +66,10 @@ template class MatrixBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; +#ifndef EIGEN_TEST_EVALUATORS using Base::CoeffReadCost; - +#endif + using Base::derived; using Base::const_cast_derived; using Base::rows; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index b16b86d8f..7ebf31696 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -109,6 +109,9 @@ struct product_evaluator, ProductTag, DenseSha : public evaluator::PlainObject>::type { typedef Product XprType; +// enum { +// CoeffReadCost = 0 // FIXME why is it needed? (this was already the case before the evaluators, see traits) +// }; typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; @@ -366,6 +369,11 @@ struct product_evaluator, ProductTag, DenseShape, { typedef Product XprType; typedef CoeffBasedProduct CoeffBasedProductType; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; product_evaluator(const XprType& xpr) : m_lhs(xpr.lhs()), @@ -376,24 +384,8 @@ struct product_evaluator, ProductTag, DenseShape, m_innerDim(xpr.lhs().cols()) { } - typedef typename XprType::Index Index; - typedef typename XprType::Scalar Scalar; - typedef typename XprType::CoeffReturnType CoeffReturnType; - typedef typename XprType::PacketScalar PacketScalar; - typedef typename XprType::PacketReturnType PacketReturnType; - // Everything below here is taken from CoeffBasedProduct.h - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - PacketSize = packet_traits::size, - InnerSize = traits::InnerSize, - CoeffReadCost = traits::CoeffReadCost, - Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = traits::CanVectorizeInner, - Flags = traits::Flags - }; - typedef typename internal::nested_eval::type LhsNested; typedef typename internal::nested_eval::type RhsNested; @@ -403,6 +395,22 @@ struct product_evaluator, ProductTag, DenseShape, typedef typename evaluator::type LhsEtorType; typedef typename evaluator::type RhsEtorType; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + PacketSize = packet_traits::size, + InnerSize = traits::InnerSize, + + LhsCoeffReadCost = LhsEtorType::CoeffReadCost, + RhsCoeffReadCost = RhsEtorType::CoeffReadCost, + CoeffReadCost = (InnerSize == Dynamic || LhsCoeffReadCost==Dynamic || RhsCoeffReadCost==Dynamic || NumTraits::AddCost==Dynamic || NumTraits::MulCost==Dynamic) ? Dynamic + : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + + (InnerSize - 1) * NumTraits::AddCost, + + Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, + CanVectorizeInner = traits::CanVectorizeInner, + Flags = traits::Flags + }; + const CoeffReturnType coeff(Index row, Index col) const { // TODO check performance regression wrt to Eigen 3.2 which has special handling of this function @@ -689,6 +697,10 @@ struct diagonal_product_evaluator_base typedef typename scalar_product_traits::ReturnType Scalar; typedef typename internal::packet_traits::type PacketScalar; public: + enum { + CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost + }; + diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) : m_diagImpl(diag), m_matImpl(mat) { @@ -739,7 +751,9 @@ struct product_evaluator, ProductTag, DiagonalSha typedef Product XprType; typedef typename XprType::PlainObject PlainObject; - enum { StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 1b6a4177a..41290323f 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -331,7 +331,7 @@ public: IsRowMajor = XprType::IsRowMajor, SizeAtCompileTime = XprType::SizeAtCompileTime, InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, - CoeffReadCost = XprType::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost }; Index rows() const { return m_xpr.rows(); } diff --git a/Eigen/src/Core/Replicate.h b/Eigen/src/Core/Replicate.h index dde86a834..1e640d8aa 100644 --- a/Eigen/src/Core/Replicate.h +++ b/Eigen/src/Core/Replicate.h @@ -53,8 +53,11 @@ struct traits > IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), + Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0) +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _MatrixTypeNested::CoeffReadCost +#endif }; }; } diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index e30ae3d28..495b44cc4 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -49,9 +49,11 @@ struct traits > LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) ? LinearAccessBit : 0, - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - + Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess) +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _MatrixTypeNested::CoeffReadCost +#endif }; }; diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h index 87993bbb5..abcba2d15 100644 --- a/Eigen/src/Core/Select.h +++ b/Eigen/src/Core/Select.h @@ -43,10 +43,13 @@ struct 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 +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = traits::type>::CoeffReadCost + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, traits::type>::CoeffReadCost) +#endif }; }; } diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 976708a0f..98f9e888f 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -45,7 +45,9 @@ struct traits > : traits Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), Flags1 = Flags0 | FlagsLvalueBit, Flags = Flags1 ^ RowMajorBit, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = MatrixTypeNestedPlain::CoeffReadCost, +#endif InnerStrideAtCompileTime = inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = outer_stride_at_compile_time::ret }; diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 96c81f933..064e0e10d 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -32,7 +32,9 @@ template class TriangularBase : public EigenBase enum { Mode = internal::traits::Mode, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = internal::traits::CoeffReadCost, +#endif RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, @@ -174,8 +176,11 @@ struct traits > : traits typedef typename MatrixType::PlainObject DenseMatrixType; enum { Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode, + Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost +#endif }; }; } @@ -1141,10 +1146,6 @@ public: template void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { -#ifdef EIGEN_DEBUG_ASSIGN - // TODO these traits should be computed from information provided by the evaluators - internal::copy_using_evaluator_traits::debug(); -#endif eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); typedef typename evaluator::type DstEvaluatorType; @@ -1159,8 +1160,8 @@ void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& sr enum { unroll = DstXprType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && DstXprType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT + && SrcEvaluatorType::CoeffReadCost != Dynamic + && DstXprType::SizeAtCompileTime * SrcEvaluatorType::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT }; triangular_assignment_loop::run(kernel); diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index f25ddca17..702d0006d 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -52,6 +52,7 @@ struct traits > Flags = (Flags0 & ~RowMajorBit) | (RowsAtCompileTime == 1 ? RowMajorBit : 0), TraversalSize = Direction==Vertical ? MatrixType::RowsAtCompileTime : MatrixType::ColsAtCompileTime }; +#ifndef EIGEN_TEST_EVALUATORS #if EIGEN_GNUC_AT_LEAST(3,4) typedef typename MemberOp::template Cost CostOpType; #else @@ -61,6 +62,7 @@ struct traits > CoeffReadCost = TraversalSize==Dynamic ? Dynamic : TraversalSize * traits<_MatrixTypeNested>::CoeffReadCost + int(CostOpType::value) }; +#endif }; } diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h index 64867b7a2..fba0e2a76 100644 --- a/Eigen/src/Core/Visitor.h +++ b/Eigen/src/Core/Visitor.h @@ -53,6 +53,35 @@ struct visitor_impl } }; +#ifdef EIGEN_ENABLE_EVALUATORS +// evaluator adaptor +template +class visitor_evaluator +{ +public: + visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime, + CoeffReadCost = internal::evaluator::CoeffReadCost + }; + + Index rows() const { return m_xpr.rows(); } + Index cols() const { return m_xpr.cols(); } + Index size() const { return m_xpr.size(); } + + CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + +protected: + typename internal::evaluator::nestedType m_evaluator; + const XprType &m_xpr; +}; +#endif } // end namespace internal /** Applies the visitor \a visitor to the whole coefficients of the matrix or vector. @@ -76,6 +105,19 @@ template template void DenseBase::visit(Visitor& visitor) const { +#ifdef EIGEN_TEST_EVALUATORS + typedef typename internal::visitor_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + enum { unroll = SizeAtCompileTime != Dynamic + && ThisEvaluator::CoeffReadCost != Dynamic + && (SizeAtCompileTime == 1 || internal::functor_traits::Cost != Dynamic) + && SizeAtCompileTime * ThisEvaluator::CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits::Cost + <= EIGEN_UNROLLING_LIMIT }; + return internal::visitor_impl::run(thisEval, visitor); +#else enum { unroll = SizeAtCompileTime != Dynamic && CoeffReadCost != Dynamic && (SizeAtCompileTime == 1 || internal::functor_traits::Cost != Dynamic) @@ -84,6 +126,7 @@ void DenseBase::visit(Visitor& visitor) const return internal::visitor_impl::run(derived(), visitor); +#endif } namespace internal { diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 77f291ab9..94099b7d3 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -47,8 +47,6 @@ struct traits > typename traits<_RhsNested>::Index>::type Index; enum { - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, LhsFlags = traits<_LhsNested>::Flags, RhsFlags = traits<_RhsNested>::Flags, @@ -89,11 +87,13 @@ struct traits > | (CanVectorizeRhs ? (RhsFlags & AlignedBit) : 0) // TODO enable vectorization for mixed types | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), - +#ifndef EIGEN_TEST_EVALUATORS + LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, + RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, CoeffReadCost = (InnerSize == Dynamic || LhsCoeffReadCost==Dynamic || RhsCoeffReadCost==Dynamic || NumTraits::AddCost==Dynamic || NumTraits::MulCost==Dynamic) ? Dynamic : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + (InnerSize - 1) * NumTraits::AddCost, - +#endif /* 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 * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index debc04f3f..3a1dec129 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -345,6 +345,8 @@ * documentation in a single line. **/ +#ifndef EIGEN_TEST_EVALUATORS + #define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ typedef typename Eigen::internal::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. */ \ @@ -381,7 +383,46 @@ using Base::derived; \ using Base::const_cast_derived; +#else + +// TODO The EIGEN_DENSE_PUBLIC_INTERFACE should not exists anymore + +#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ + typedef typename Eigen::internal::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::internal::nested::type Nested; \ + typedef typename Eigen::internal::traits::StorageKind StorageKind; \ + typedef typename Eigen::internal::traits::Index Index; \ + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ + Flags = Eigen::internal::traits::Flags, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; + + +#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ + typedef typename Eigen::internal::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::internal::nested::type Nested; \ + typedef typename Eigen::internal::traits::StorageKind StorageKind; \ + typedef typename Eigen::internal::traits::Index Index; \ + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ + MaxRowsAtCompileTime = Eigen::internal::traits::MaxRowsAtCompileTime, \ + MaxColsAtCompileTime = Eigen::internal::traits::MaxColsAtCompileTime, \ + Flags = Eigen::internal::traits::Flags, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ + using Base::derived; \ + using Base::const_cast_derived; +#endif // EIGEN_TEST_EVALUATORS + #define EIGEN_PLAIN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b) #define EIGEN_PLAIN_ENUM_MAX(a,b) (((int)a >= (int)b) ? (int)a : (int)b) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index a4baa921c..8931c5a2d 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -370,7 +370,9 @@ template::type> struc DynamicAsInteger = 10000, ScalarReadCost = NumTraits::Scalar>::ReadCost, ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), - CoeffReadCost = traits::CoeffReadCost, + CoeffReadCost = evaluator::CoeffReadCost, // TODO What if an evaluator evaluate itself into a tempory? + // Then CoeffReadCost will be small but we still have to evaluate if n>1... + // The solution might be to ask the evaluator if it creates a temp. Perhaps we could even ask the number of temps? CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, -- cgit v1.2.3 From 2bf63c6b4a6fb9f69df184dc69f3427ffd81c4a3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 11:42:07 +0100 Subject: Even ReturnByValue should not evaluate when assembling the expression --- Eigen/src/Core/ReturnByValue.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 7834f6cbc..d63b96138 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -33,6 +33,7 @@ struct traits > }; }; +#ifndef EIGEN_TEST_EVALUATORS /* The ReturnByValue object doesn't even have a coeff() method. * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. * So internal::nested always gives the plain return matrix type. @@ -44,6 +45,13 @@ struct nested, n, PlainObject> { typedef typename traits::ReturnType type; }; +#else +template +struct nested_eval, n, PlainObject> +{ + typedef typename traits::ReturnType type; +}; +#endif } // end namespace internal -- cgit v1.2.3 From 5806e7380026ab4ebd8f1aa4792b83cfc60f58a9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 11:44:11 +0100 Subject: It is not clear what XprType::Nested should be, so let's use nested::type as much as possible --- Eigen/src/Core/Product.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 31730983f..cac90bc1f 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -62,8 +62,8 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; + typedef typename internal::nested::type LhsNested; + typedef typename internal::nested::type RhsNested; typedef typename internal::remove_all::type LhsNestedCleaned; typedef typename internal::remove_all::type RhsNestedCleaned; -- cgit v1.2.3 From ae405839652dc72935821bdaed163e7be04b3082 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 11:47:14 +0100 Subject: Fix CoeffReadCost issues --- Eigen/src/Core/PermutationMatrix.h | 9 ++++++++- Eigen/src/LU/FullPivLU.h | 8 ++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 6a26af3a5..9add80c54 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -60,7 +60,9 @@ class PermutationBase : public EigenBase typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = Traits::CoeffReadCost, +#endif RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, @@ -473,8 +475,11 @@ struct traits > ColsAtCompileTime = _IndicesType::SizeAtCompileTime, MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, - Flags = 0, + Flags = 0 +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _IndicesType::CoeffReadCost +#endif }; }; } @@ -626,7 +631,9 @@ class Transpose > typedef typename Derived::DenseMatrixType DenseMatrixType; enum { Flags = Traits::Flags, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = Traits::CoeffReadCost, +#endif RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index e0236fd9e..a06f5702c 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -16,11 +16,7 @@ namespace internal { template struct traits > : traits<_MatrixType> { - typedef traits<_MatrixType> BaseTraits; - enum { - Flags = BaseTraits::Flags & RowMajorBit, - CoeffReadCost = Dynamic - }; + enum { Flags = 0 }; }; } // end namespace internal @@ -755,7 +751,7 @@ void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const namespace internal { -#ifdef EIGEN_TEST_EVALUATORS +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> -- cgit v1.2.3 From 9be72cda2ab25650ce97eacd6dc2e994c988741b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 11:47:32 +0100 Subject: Port QR module to Solve/Inverse --- Eigen/src/QR/ColPivHouseholderQR.h | 110 +++++++++++++++++++++-------- Eigen/src/QR/FullPivHouseholderQR.h | 133 ++++++++++++++++++++++++++---------- Eigen/src/QR/HouseholderQR.h | 65 ++++++++++++------ 3 files changed, 227 insertions(+), 81 deletions(-) diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index 07126a9f4..1bf19d19e 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -13,6 +13,15 @@ namespace Eigen { +namespace internal { +template struct traits > + : traits<_MatrixType> +{ + enum { Flags = 0 }; +}; + +} // end namespace internal + /** \ingroup QR_Module * * \class ColPivHouseholderQR @@ -56,6 +65,7 @@ template class ColPivHouseholderQR typedef typename internal::plain_row_type::type RowVectorType; typedef typename internal::plain_row_type::type RealRowVectorType; typedef HouseholderSequence::type> HouseholderSequenceType; + typedef typename MatrixType::PlainObject PlainObject; private: @@ -137,6 +147,15 @@ template class ColPivHouseholderQR * Example: \include ColPivHouseholderQR_solve.cpp * Output: \verbinclude ColPivHouseholderQR_solve.out */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -144,9 +163,10 @@ template class ColPivHouseholderQR eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return internal::solve_retval(*this, b.derived()); } +#endif - HouseholderSequenceType householderQ(void) const; - HouseholderSequenceType matrixQ(void) const + HouseholderSequenceType householderQ() const; + HouseholderSequenceType matrixQ() const { return householderQ(); } @@ -284,6 +304,13 @@ template class ColPivHouseholderQR * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. */ +#ifdef EIGEN_TEST_EVALUATORS + inline const Inverse inverse() const + { + eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); + return Inverse(*this); + } +#else inline const internal::solve_retval inverse() const @@ -292,6 +319,7 @@ template class ColPivHouseholderQR return internal::solve_retval (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols())); } +#endif inline Index rows() const { return m_qr.rows(); } inline Index cols() const { return m_qr.cols(); } @@ -382,6 +410,12 @@ template class ColPivHouseholderQR eigen_assert(m_isInitialized && "Decomposition is not initialized."); return Success; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: MatrixType m_qr; @@ -514,8 +548,41 @@ ColPivHouseholderQR& ColPivHouseholderQR::compute(const return *this; } +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + eigen_assert(rhs.rows() == rows()); + + const Index nonzero_pivots = nonzeroPivots(); + + if(nonzero_pivots == 0) + { + dst.setZero(); + return; + } + + typename RhsType::PlainObject c(rhs); + + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(householderSequence(m_qr, m_hCoeffs) + .setLength(nonzero_pivots) + .transpose() + ); + + m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots) + .template triangularView() + .solveInPlace(c.topRows(nonzero_pivots)); + + for(Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i); + for(Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero(); +} +#endif + namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -524,34 +591,23 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - eigen_assert(rhs().rows() == dec().rows()); - - const Index cols = dec().cols(), - nonzero_pivots = dec().nonzeroPivots(); - - if(nonzero_pivots == 0) - { - dst.setZero(); - return; - } - - typename Rhs::PlainObject c(rhs()); - - // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T - c.applyOnTheLeft(householderSequence(dec().matrixQR(), dec().hCoeffs()) - .setLength(dec().nonzeroPivots()) - .transpose() - ); - - dec().matrixR() - .topLeftCorner(nonzero_pivots, nonzero_pivots) - .template triangularView() - .solveInPlace(c.topRows(nonzero_pivots)); + dec()._solve_impl(rhs(), dst); + } +}; +#endif - for(Index i = 0; i < nonzero_pivots; ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i); - for(Index i = nonzero_pivots; i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero(); +#ifdef EIGEN_TEST_EVALUATORS +template +struct Assignment >, internal::assign_op, Dense2Dense, Scalar> +{ + typedef ColPivHouseholderQR QrType; + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; +#endif } // end namespace internal diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 44eaa1b1a..8cdf14e4b 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -15,6 +15,12 @@ namespace Eigen { namespace internal { +template struct traits > + : traits<_MatrixType> +{ + enum { Flags = 0 }; +}; + template struct FullPivHouseholderQRMatrixQReturnType; template @@ -23,7 +29,7 @@ struct traits > typedef typename MatrixType::PlainObject ReturnType; }; -} +} // end namespace internal /** \ingroup QR_Module * @@ -69,6 +75,7 @@ template class FullPivHouseholderQR typedef PermutationMatrix PermutationType; typedef typename internal::plain_row_type::type RowVectorType; typedef typename internal::plain_col_type::type ColVectorType; + typedef typename MatrixType::PlainObject PlainObject; /** \brief Default Constructor. * @@ -144,6 +151,15 @@ template class FullPivHouseholderQR * Example: \include FullPivHouseholderQR_solve.cpp * Output: \verbinclude FullPivHouseholderQR_solve.out */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -151,6 +167,7 @@ template class FullPivHouseholderQR eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return internal::solve_retval(*this, b.derived()); } +#endif /** \returns Expression object representing the matrix Q */ @@ -280,7 +297,15 @@ template class FullPivHouseholderQR * * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. - */ inline const + */ +#ifdef EIGEN_TEST_EVALUATORS + inline const Inverse inverse() const + { + eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); + return Inverse(*this); + } +#else + inline const internal::solve_retval inverse() const { @@ -288,6 +313,7 @@ template class FullPivHouseholderQR return internal::solve_retval (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols())); } +#endif inline Index rows() const { return m_qr.rows(); } inline Index cols() const { return m_qr.cols(); } @@ -366,6 +392,12 @@ template class FullPivHouseholderQR * diagonal coefficient of U. */ RealScalar maxPivot() const { return m_maxpivot; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: MatrixType m_qr; @@ -485,8 +517,46 @@ FullPivHouseholderQR& FullPivHouseholderQR::compute(cons return *this; } -namespace internal { +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + eigen_assert(rhs.rows() == rows()); + const Index l_rank = rank(); + + // FIXME introduce nonzeroPivots() and use it here. and more generally, + // make the same improvements in this dec as in FullPivLU. + if(l_rank==0) + { + dst.setZero(); + return; + } + typename RhsType::PlainObject c(rhs); + + Matrix temp(rhs.cols()); + for (Index k = 0; k < l_rank; ++k) + { + Index remainingSize = rows()-k; + c.row(k).swap(c.row(m_rows_transpositions.coeff(k))); + c.bottomRightCorner(remainingSize, rhs.cols()) + .applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1), + m_hCoeffs.coeff(k), &temp.coeffRef(0)); + } + + m_qr.topLeftCorner(l_rank, l_rank) + .template triangularView() + .solveInPlace(c.topRows(l_rank)); + + for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i); + for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero(); +} +#endif + +namespace internal { + +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -495,38 +565,23 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - const Index rows = dec().rows(), cols = dec().cols(); - eigen_assert(rhs().rows() == rows); - - // FIXME introduce nonzeroPivots() and use it here. and more generally, - // make the same improvements in this dec as in FullPivLU. - if(dec().rank()==0) - { - dst.setZero(); - return; - } - - typename Rhs::PlainObject c(rhs()); - - Matrix temp(rhs().cols()); - for (Index k = 0; k < dec().rank(); ++k) - { - Index remainingSize = rows-k; - c.row(k).swap(c.row(dec().rowsTranspositions().coeff(k))); - c.bottomRightCorner(remainingSize, rhs().cols()) - .applyHouseholderOnTheLeft(dec().matrixQR().col(k).tail(remainingSize-1), - dec().hCoeffs().coeff(k), &temp.coeffRef(0)); - } - - dec().matrixQR() - .topLeftCorner(dec().rank(), dec().rank()) - .template triangularView() - .solveInPlace(c.topRows(dec().rank())); + dec()._solve_impl(rhs(), dst); + } +}; +#endif // EIGEN_TEST_EVALUATORS - for(Index i = 0; i < dec().rank(); ++i) dst.row(dec().colsPermutation().indices().coeff(i)) = c.row(i); - for(Index i = dec().rank(); i < cols; ++i) dst.row(dec().colsPermutation().indices().coeff(i)).setZero(); +#ifdef EIGEN_TEST_EVALUATORS +template +struct Assignment >, internal::assign_op, Dense2Dense, Scalar> +{ + typedef FullPivHouseholderQR QrType; + typedef Inverse SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; +#endif /** \ingroup QR_Module * @@ -534,6 +589,7 @@ struct solve_retval, Rhs> * * \tparam MatrixType type of underlying dense matrix */ +// #ifndef EIGEN_TEST_EVALUATORS template struct FullPivHouseholderQRMatrixQReturnType : public ReturnByValue > { @@ -550,7 +606,7 @@ public: : m_qr(qr), m_hCoeffs(hCoeffs), m_rowsTranspositions(rowsTranspositions) - {} + {} template void evalTo(ResultType& result) const @@ -580,8 +636,8 @@ public: } } - Index rows() const { return m_qr.rows(); } - Index cols() const { return m_qr.rows(); } + Index rows() const { return m_qr.rows(); } + Index cols() const { return m_qr.rows(); } protected: typename MatrixType::Nested m_qr; @@ -589,6 +645,13 @@ protected: typename IntDiagSizeVectorType::Nested m_rowsTranspositions; }; +// #ifdef EIGEN_TEST_EVALUATORS +// template +// struct evaluator > +// : public evaluator > > +// {}; +// #endif + } // end namespace internal template diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 352dbf3f0..8808e6c0d 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -117,6 +117,15 @@ template class HouseholderQR * Example: \include HouseholderQR_solve.cpp * Output: \verbinclude HouseholderQR_solve.out */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -124,6 +133,7 @@ template class HouseholderQR eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); return internal::solve_retval(*this, b.derived()); } +#endif /** This method returns an expression of the unitary matrix Q as a sequence of Householder transformations. * @@ -187,6 +197,12 @@ template class HouseholderQR * For advanced uses only. */ const HCoeffsType& hCoeffs() const { return m_hCoeffs; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: MatrixType m_qr; @@ -308,6 +324,35 @@ struct householder_qr_inplace_blocked } }; +} // end namespace internal + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + const Index rank = (std::min)(rows(), cols()); + eigen_assert(rhs.rows() == rows()); + + typename RhsType::PlainObject c(rhs); + + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(householderSequence( + m_qr.leftCols(rank), + m_hCoeffs.head(rank)).transpose() + ); + + m_qr.topLeftCorner(rank, rank) + .template triangularView() + .solveInPlace(c.topRows(rank)); + + dst.topRows(rank) = c.topRows(rank); + dst.bottomRows(cols()-rank).setZero(); +} +#endif + +namespace internal { + template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -316,25 +361,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - const Index rows = dec().rows(), cols = dec().cols(); - const Index rank = (std::min)(rows, cols); - eigen_assert(rhs().rows() == rows); - - typename Rhs::PlainObject c(rhs()); - - // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T - c.applyOnTheLeft(householderSequence( - dec().matrixQR().leftCols(rank), - dec().hCoeffs().head(rank)).transpose() - ); - - dec().matrixQR() - .topLeftCorner(rank, rank) - .template triangularView() - .solveInPlace(c.topRows(rank)); - - dst.topRows(rank) = c.topRows(rank); - dst.bottomRows(cols-rank).setZero(); + dec()._solve_impl(rhs(), dst); } }; -- cgit v1.2.3 From 082f7ddc3745160c57d8a5a185a2a22e4d781b5f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 13:33:44 +0100 Subject: Port Cholesky module to evaluators --- Eigen/src/Cholesky/LDLT.h | 86 ++++++++++++++++++++++++++-------------- Eigen/src/Cholesky/LLT.h | 32 ++++++++++++++- Eigen/src/Core/SelfAdjointView.h | 5 ++- Eigen/src/Core/util/XprHelper.h | 2 +- 4 files changed, 93 insertions(+), 32 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index f34d26465..c5ae2c87e 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -181,6 +181,17 @@ template class LDLT * * \sa MatrixBase::ldlt() */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + eigen_assert(m_matrix.rows()==b.rows() + && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -190,6 +201,7 @@ template class LDLT && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#endif #ifdef EIGEN2_SUPPORT template @@ -233,6 +245,12 @@ template class LDLT eigen_assert(m_isInitialized && "LDLT is not initialized."); return Success; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: @@ -492,7 +510,44 @@ LDLT& LDLT::rankUpdate(const MatrixBase +template +void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + eigen_assert(rhs.rows() == rows()); + // dst = P b + dst = m_transpositions * rhs; + + // dst = L^-1 (P b) + matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + // more precisely, use pseudo-inverse of D (see bug 241) + using std::abs; + EIGEN_USING_STD_MATH(max); + const Diagonal vecD = vectorD(); + RealScalar tolerance = (max)( vecD.array().abs().maxCoeff() * NumTraits::epsilon(), + RealScalar(1) / NumTraits::highest()); // motivated by LAPACK's xGELSS + + for (Index i = 0; i < vecD.size(); ++i) + { + if(abs(vecD(i)) > tolerance) + dst.row(i) /= vecD(i); + else + dst.row(i).setZero(); + } + + // dst = L^-T (D^-1 L^-1 P b) + matrixU().solveInPlace(dst); + + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = m_transpositions.transpose() * dst; +} +#endif + namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -502,37 +557,10 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); - // dst = P b - dst = dec().transpositionsP() * rhs(); - - // dst = L^-1 (P b) - dec().matrixL().solveInPlace(dst); - - // dst = D^-1 (L^-1 P b) - // more precisely, use pseudo-inverse of D (see bug 241) - using std::abs; - EIGEN_USING_STD_MATH(max); - typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::Scalar Scalar; - typedef typename LDLTType::RealScalar RealScalar; - const Diagonal vectorD = dec().vectorD(); - RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() * NumTraits::epsilon(), - RealScalar(1) / NumTraits::highest()); // motivated by LAPACK's xGELSS - for (Index i = 0; i < vectorD.size(); ++i) { - if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); - else - dst.row(i).setZero(); - } - - // dst = L^-T (D^-1 L^-1 P b) - dec().matrixU().solveInPlace(dst); - - // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b - dst = dec().transpositionsP().transpose() * dst; + dec()._solve_impl(rhs(),dst); } }; +#endif } /** \internal use x = ldlt_object.solve(x); diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 2201c641e..d9a8ef1fb 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -117,6 +117,17 @@ template class LLT * * \sa solveInPlace(), MatrixBase::llt() */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(m_matrix.rows()==b.rows() + && "LLT::solve(): invalid number of rows of the right hand side matrix b"); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -126,6 +137,7 @@ template class LLT && "LLT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#endif #ifdef EIGEN2_SUPPORT template @@ -172,6 +184,12 @@ template class LLT template LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: /** \internal @@ -415,8 +433,19 @@ LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, c return *this; } - + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + dst = rhs; + solveInPlace(dst); +} +#endif + namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -430,6 +459,7 @@ struct solve_retval, Rhs> dec().solveInPlace(dst); } }; +#endif } /** \internal use x = llt_object.solve(x); diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index f7f512cf4..b300c6a48 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -39,8 +39,11 @@ struct traits > : traits enum { Mode = UpLo | SelfAdjoint, Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) - & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)), // FIXME these flags should be preserved + & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)) // FIXME these flags should be preserved +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost +#endif }; }; } diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 8931c5a2d..bcd6183e2 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -348,7 +348,7 @@ template::type> str // When using evaluators, we never evaluate when assembling the expression!! // TODO: get rid of this nested class since it's just an alias for ref_selector. -template::type> struct nested +template struct nested { typedef typename ref_selector::type type; }; -- cgit v1.2.3 From 7eefdb948c1ff372f85991ff3f9d998e66a554d9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 11 Mar 2014 13:43:46 +0100 Subject: Migrate JacobiSVD to Solver --- Eigen/src/LU/FullPivLU.h | 4 ++-- Eigen/src/SVD/JacobiSVD.h | 50 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index a06f5702c..78cd9b90f 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -702,8 +702,8 @@ struct image_retval > #ifndef EIGEN_PARSED_BY_DOXYGEN template template -void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const { - +void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ /* The decomposition PAQ = LU can be rewritten as A = P^{-1} L U Q^{-1}. * So we proceed as follows: * Step 1: compute c = P * rhs. diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index eee31ca97..d78583ecc 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -653,6 +653,16 @@ template class JacobiSVD * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); + return Solve(*this, b.derived()); + } +#else template inline const internal::solve_retval solve(const MatrixBase& b) const @@ -661,6 +671,7 @@ template class JacobiSVD eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); return internal::solve_retval(*this, b.derived()); } +#endif /** \returns the number of singular values that are not exactly 0 */ Index nonzeroSingularValues() const @@ -734,6 +745,12 @@ template class JacobiSVD inline Index rows() const { return m_rows; } inline Index cols() const { return m_cols; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif private: void allocate(Index rows, Index cols, unsigned int computationOptions); @@ -912,7 +929,27 @@ JacobiSVD::compute(const MatrixType& matrix, unsig return *this; } +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void JacobiSVD<_MatrixType,QRPreconditioner>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + eigen_assert(rhs.rows() == rows()); + + // A = U S V^* + // So A^{-1} = V S^{-1} U^* + + Matrix tmp; + Index l_rank = rank(); + + tmp.noalias() = m_matrixU.leftCols(l_rank).adjoint() * rhs; + tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp; + dst = m_matrixV.leftCols(l_rank) * tmp; +} +#endif + namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template struct solve_retval, Rhs> : solve_retval_base, Rhs> @@ -922,19 +959,10 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - eigen_assert(rhs().rows() == dec().rows()); - - // A = U S V^* - // So A^{-1} = V S^{-1} U^* - - Matrix tmp; - Index rank = dec().rank(); - - tmp.noalias() = dec().matrixU().leftCols(rank).adjoint() * rhs(); - tmp = dec().singularValues().head(rank).asDiagonal().inverse() * tmp; - dst = dec().matrixV().leftCols(rank) * tmp; + dec()._solve_impl(rhs(), dst); } }; +#endif } // end namespace internal #ifndef __CUDACC__ -- cgit v1.2.3 From 8dd3b716e39d4b4b472b948de1af20838bf17493 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 13:34:11 +0100 Subject: Move evaluation related flags from traits to evaluator and fix evaluators of MapBase and Replicate --- Eigen/src/Core/AssignEvaluator.h | 15 +- Eigen/src/Core/Block.h | 11 ++ Eigen/src/Core/CoreEvaluators.h | 231 +++++++++++++++++------ Eigen/src/Core/CwiseBinaryOp.h | 8 +- Eigen/src/Core/CwiseNullaryOp.h | 7 +- Eigen/src/Core/CwiseUnaryOp.h | 7 +- Eigen/src/Core/CwiseUnaryView.h | 4 +- Eigen/src/Core/Diagonal.h | 5 +- Eigen/src/Core/DiagonalMatrix.h | 1 + Eigen/src/Core/DiagonalProduct.h | 8 +- Eigen/src/Core/Map.h | 7 +- Eigen/src/Core/MapBase.h | 9 +- Eigen/src/Core/Product.h | 27 ++- Eigen/src/Core/ProductEvaluators.h | 111 ++++++++--- Eigen/src/Core/Redux.h | 11 ++ Eigen/src/Core/Replicate.h | 7 +- Eigen/src/Core/Reverse.h | 7 +- Eigen/src/Core/Select.h | 5 +- Eigen/src/Core/Transpose.h | 7 +- Eigen/src/Core/VectorwiseOp.h | 4 + Eigen/src/Core/products/TriangularMatrixVector.h | 2 +- Eigen/src/Core/util/ForwardDeclarations.h | 12 ++ Eigen/src/Core/util/XprHelper.h | 52 +++++ 23 files changed, 433 insertions(+), 125 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 2ea1cc126..05816094c 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -28,11 +28,10 @@ template struct copy_using_evaluator_traits { typedef typename DstEvaluator::XprType Dst; - typedef typename SrcEvaluator::XprType Src; - // TODO, we should get these flags from the evaluators + enum { - DstFlags = Dst::Flags, - SrcFlags = Src::Flags + DstFlags = DstEvaluator::Flags, + SrcFlags = SrcEvaluator::Flags }; public: @@ -56,7 +55,9 @@ private: }; enum { - StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), + DstIsRowMajor = DstEvaluator::Flags&RowMajorBit, + SrcIsRowMajor = SrcEvaluator::Flags&RowMajorBit, + StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), MightVectorize = StorageOrdersAgree && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) && (functor_traits::PacketAccess), @@ -596,7 +597,7 @@ public: typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::RowsAtCompileTime) == 1 ? 0 : int(Traits::ColsAtCompileTime) == 1 ? inner - : int(Traits::Flags)&RowMajorBit ? outer + : int(DstEvaluatorType::Flags)&RowMajorBit ? outer : inner; } @@ -605,7 +606,7 @@ public: typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::ColsAtCompileTime) == 1 ? 0 : int(Traits::RowsAtCompileTime) == 1 ? inner - : int(Traits::Flags)&RowMajorBit ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? inner : outer; } diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 31cd5c72c..d92797a98 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -68,6 +68,7 @@ struct traits > : traits::MaxColsAtCompileTime), + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 @@ -80,6 +81,10 @@ struct traits > : traits::ret) : int(inner_stride_at_compile_time::ret), + // IsAligned is needed by MapBase's assertions + // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator + IsAligned = 0, +#ifndef EIGEN_TEST_EVALUATORS MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) && (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, @@ -92,6 +97,12 @@ struct traits > : traits::value ? LvalueBit : 0, + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, + Flags = (traits::Flags & DirectAccessBit) | FlagsLvalueBit | FlagsRowMajorBit // FIXME DirectAccessBit should not be handled by expressions +#endif }; }; diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 33c89c2d4..a5de3593c 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -136,7 +136,9 @@ struct evaluator > RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, - CoeffReadCost = NumTraits::ReadCost + CoeffReadCost = NumTraits::ReadCost, + Flags = compute_matrix_evaluator_flags< Scalar,Derived::RowsAtCompileTime,Derived::ColsAtCompileTime, + Derived::Options,Derived::MaxRowsAtCompileTime,Derived::MaxColsAtCompileTime>::ret }; evaluator() @@ -323,7 +325,8 @@ struct evaluator > typedef Transpose XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags ^ RowMajorBit }; evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} @@ -389,9 +392,16 @@ struct evaluator > : evaluator_base > { typedef CwiseNullaryOp XprType; + typedef typename internal::remove_all::type PlainObjectTypeCleaned; enum { - CoeffReadCost = internal::functor_traits::Cost + CoeffReadCost = internal::functor_traits::Cost, + + Flags = (evaluator::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) // FIXME EvalBeforeNestingBit should be needed anymore }; evaluator(const XprType& n) @@ -437,7 +447,11 @@ struct evaluator > typedef CwiseUnaryOp XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = evaluator::Flags & ( + HereditaryBits | LinearAccessBit | AlignedBit + | (functor_traits::PacketAccess ? PacketAccessBit : 0)) }; evaluator(const XprType& op) @@ -485,7 +499,22 @@ struct evaluator > typedef CwiseBinaryOp XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + LhsFlags = evaluator::Flags, + RhsFlags = evaluator::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( AlignedBit + | (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) }; evaluator(const XprType& xpr) @@ -537,7 +566,9 @@ struct evaluator > typedef CwiseUnaryView XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)) }; evaluator(const XprType& op) @@ -576,12 +607,15 @@ protected: // -------------------- Map -------------------- -template -struct evaluator > - : evaluator_base +// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? +// but that might complicate template specialization +template +struct mapbase_evaluator; + +template +struct mapbase_evaluator : evaluator_base { - typedef MapBase MapType; - typedef Derived XprType; + typedef Derived XprType; typedef typename XprType::PointerType PointerType; typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -590,81 +624,103 @@ struct evaluator > typedef typename XprType::PacketReturnType PacketReturnType; enum { - RowsAtCompileTime = XprType::RowsAtCompileTime, + IsRowMajor = XprType::RowsAtCompileTime, + ColsAtCompileTime = XprType::ColsAtCompileTime, CoeffReadCost = NumTraits::ReadCost }; - evaluator(const XprType& map) + mapbase_evaluator(const XprType& map) : m_data(const_cast(map.data())), - m_rowStride(map.rowStride()), - m_colStride(map.colStride()) - { } + m_xpr(map) + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + } CoeffReturnType coeff(Index row, Index col) const - { - return m_data[col * m_colStride + row * m_rowStride]; + { + return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; } CoeffReturnType coeff(Index index) const - { - return coeff(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + { + return m_data[index * m_xpr.innerStride()]; } Scalar& coeffRef(Index row, Index col) - { - return m_data[col * m_colStride + row * m_rowStride]; + { + return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; } Scalar& coeffRef(Index index) - { - return coeffRef(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + { + return m_data[index * m_xpr.innerStride()]; } template PacketReturnType packet(Index row, Index col) const - { - PointerType ptr = m_data + row * m_rowStride + col * m_colStride; + { + PointerType ptr = m_data + row * m_xpr.rowStride() + col * m_xpr.colStride(); return internal::ploadt(ptr); } template PacketReturnType packet(Index index) const - { - return packet(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0); + { + return internal::ploadt(m_data + index * m_xpr.innerStride()); } template void writePacket(Index row, Index col, const PacketScalar& x) - { - PointerType ptr = m_data + row * m_rowStride + col * m_colStride; + { + PointerType ptr = m_data + row * m_xpr.rowStride() + col * m_xpr.colStride(); return internal::pstoret(ptr, x); } template void writePacket(Index index, const PacketScalar& x) - { - return writePacket(RowsAtCompileTime == 1 ? 0 : index, - RowsAtCompileTime == 1 ? index : 0, - x); + { + internal::pstoret(m_data + index * m_xpr.innerStride(), x); } protected: PointerType m_data; - int m_rowStride; - int m_colStride; + const XprType& m_xpr; }; template struct evaluator > - : public evaluator > > + : public mapbase_evaluator, PlainObjectType> { typedef Map XprType; + typedef typename XprType::Scalar Scalar; + + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + KeepsPacketAccess = bool(HasNoInnerStride) + && ( bool(IsDynamicSize) + || HasNoOuterStride + || ( OuterStrideAtCompileTime!=Dynamic + && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), + Flags0 = evaluator::Flags, + Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), + Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) + ? int(Flags1) : int(Flags1 & ~LinearAccessBit), + Flags = KeepsPacketAccess ? int(Flags2) : (int(Flags2) & ~PacketAccessBit) + }; evaluator(const XprType& map) - : evaluator >(map) + : mapbase_evaluator(map) { } }; @@ -672,12 +728,16 @@ struct evaluator > template struct evaluator > - : public evaluator > > + : public mapbase_evaluator, PlainObjectType> { typedef Ref XprType; + + enum { + Flags = evaluator >::Flags + }; - evaluator(const XprType& map) - : evaluator >(map) + evaluator(const XprType& ref) + : mapbase_evaluator(ref) { } }; @@ -691,8 +751,39 @@ struct evaluator > : block_evaluator { typedef Block XprType; + typedef typename XprType::Scalar Scalar; + enum { - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) + && (InnerStrideAtCompileTime == 1) + ? PacketAccessBit : 0, + MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + FlagsRowMajorBit = XprType::Flags&RowMajorBit, + Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit | + MaskAlignedBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit }; typedef block_evaluator block_evaluator_type; evaluator(const XprType& block) : block_evaluator_type(block) {} @@ -778,18 +869,23 @@ protected: template struct block_evaluator - : evaluator > > + : mapbase_evaluator, + typename Block::PlainObject> { typedef Block XprType; block_evaluator(const XprType& block) - : evaluator >(block) - { } + : mapbase_evaluator(block) + { + // FIXME this should be an internal assertion + eigen_assert(EIGEN_IMPLIES(evaluator::Flags&AlignedBit, (size_t(block.data()) % 16) == 0) && "data is not aligned"); + } }; // -------------------- Select -------------------- +// TODO enable vectorization for Select template struct evaluator > : evaluator_base > @@ -798,7 +894,9 @@ struct evaluator > enum { CoeffReadCost = evaluator::CoeffReadCost + EIGEN_SIZE_MAX(evaluator::CoeffReadCost, - evaluator::CoeffReadCost) + evaluator::CoeffReadCost), + + Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits }; evaluator(const XprType& select) @@ -850,7 +948,9 @@ struct evaluator > typedef typename internal::remove_all::type ArgTypeNestedCleaned; enum { - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (evaluator::Flags & HereditaryBits & ~RowMajorBit) | (traits::Flags & RowMajorBit) }; evaluator(const XprType& replicate) @@ -858,7 +958,7 @@ struct evaluator > m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), m_cols(replicate.nestedExpression().cols()) - { } + {} CoeffReturnType coeff(Index row, Index col) const { @@ -907,17 +1007,19 @@ struct evaluator > typedef PartialReduxExpr XprType; typedef typename XprType::Scalar InputScalar; enum { - TraversalSize = Direction==Vertical ? XprType::RowsAtCompileTime : XprType::ColsAtCompileTime + TraversalSize = Direction==Vertical ? ArgType::RowsAtCompileTime : XprType::ColsAtCompileTime }; typedef typename MemberOp::template Cost CostOpType; enum { CoeffReadCost = TraversalSize==Dynamic ? Dynamic - : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value) + : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value), + + Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&HereditaryBits) }; evaluator(const XprType expr) : m_expr(expr) - { } + {} typedef typename XprType::Index Index; typedef typename XprType::CoeffReturnType CoeffReturnType; @@ -948,7 +1050,8 @@ struct evaluator_wrapper_base { typedef typename remove_all::type ArgType; enum { - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags }; evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} @@ -1058,7 +1161,15 @@ struct evaluator > || ((Direction == Vertical) && IsColMajor) || ((Direction == Horizontal) && IsRowMajor), - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + + // let's enable LinearAccess only with vectorization because of the product overhead + // FIXME enable DirectAccess with negative strides? + Flags0 = evaluator::Flags, + LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) + ? LinearAccessBit : 0, + + Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess) }; typedef internal::reverse_packet_cond reverse_packet; @@ -1071,7 +1182,7 @@ struct evaluator > CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, - ReverseCol ? m_cols.value() - col - 1 : col); + ReverseCol ? m_cols.value() - col - 1 : col); } CoeffReturnType coeff(Index index) const @@ -1082,7 +1193,7 @@ struct evaluator > Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, - ReverseCol ? m_cols.value() - col - 1 : col); + ReverseCol ? m_cols.value() - col - 1 : col); } Scalar& coeffRef(Index index) @@ -1138,7 +1249,9 @@ struct evaluator > typedef Diagonal XprType; enum { - CoeffReadCost = evaluator::CoeffReadCost + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (unsigned int)evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit) & ~RowMajorBit }; evaluator(const XprType& diagonal) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 105e7fb11..07861dbc9 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -65,6 +65,7 @@ struct traits > typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { +#ifndef EIGEN_TEST_EVALUATORS LhsFlags = _LhsNested::Flags, RhsFlags = _RhsNested::Flags, SameType = is_same::value, @@ -78,12 +79,13 @@ struct traits > ) ) ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) -#ifndef EIGEN_TEST_EVALUATORS - , + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + LhsCoeffReadCost = _LhsNested::CoeffReadCost, RhsCoeffReadCost = _RhsNested::CoeffReadCost, CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost +#else + Flags = _LhsNested::Flags & RowMajorBit #endif }; }; diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index 560e03f12..f9f127cc2 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -35,14 +35,15 @@ template struct traits > : traits { enum { +#ifndef EIGEN_TEST_EVALUATORS Flags = (traits::Flags & ( HereditaryBits | (functor_has_linear_access::ret ? LinearAccessBit : 0) | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) -#ifndef EIGEN_TEST_EVALUATORS - , + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), CoeffReadCost = functor_traits::Cost +#else + Flags = traits::Flags & RowMajorBit #endif }; }; diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index 25da52ab7..af05a9108 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -44,12 +44,13 @@ struct traits > typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { +#ifndef EIGEN_TEST_EVALUATORS Flags = _XprTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)) -#ifndef EIGEN_TEST_EVALUATORS - , + | (functor_traits::PacketAccess ? PacketAccessBit : 0)), CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost +#else + Flags = _XprTypeNested::Flags & RowMajorBit #endif }; }; diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index a0bd80fb9..9cdebb8e7 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -37,9 +37,11 @@ struct traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), #ifndef EIGEN_TEST_EVALUATORS + Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, +#else + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | LvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions #endif MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 02ab04980..3ff6a3e66 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -51,10 +51,13 @@ struct traits > : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, +#ifndef EIGEN_TEST_EVALUATORS MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, -#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = _MatrixTypeNested::CoeffReadCost, +#else + MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions #endif MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 784e4b1ce..ba0042ba4 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -275,6 +275,7 @@ struct traits > typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::Index Index; typedef typename DiagonalVectorType::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index 840b70dbb..c6dafdddc 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -26,6 +26,7 @@ struct traits > MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, +#ifndef EIGEN_TEST_EVALUATORS _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), @@ -34,11 +35,10 @@ struct traits > //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit //(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), -#ifndef EIGEN_TEST_EVALUATORS - , + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit, //(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost +#else + Flags = RowMajorBit & (unsigned int)(MatrixType::Flags) #endif }; }; diff --git a/Eigen/src/Core/Map.h b/Eigen/src/Core/Map.h index 8ea13cfb7..23bbb46bf 100644 --- a/Eigen/src/Core/Map.h +++ b/Eigen/src/Core/Map.h @@ -79,10 +79,11 @@ struct traits > OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 ? int(PlainObjectType::OuterStrideAtCompileTime) : int(StrideType::OuterStrideAtCompileTime), + IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), +#ifndef EIGEN_TEST_EVALUATORS HasNoInnerStride = InnerStrideAtCompileTime == 1, HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, KeepsPacketAccess = bool(HasNoInnerStride) && ( bool(IsDynamicSize) @@ -95,6 +96,10 @@ struct traits > ? int(Flags1) : int(Flags1 & ~LinearAccessBit), Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) +#else + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) +#endif }; private: enum { Options }; // Expressions don't have Options diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index ffa1371c2..de1424b09 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -161,11 +161,16 @@ template class MapBase EIGEN_DEVICE_FUNC void checkSanity() const { +#ifndef EIGEN_TEST_EVALUATORS + // moved to evaluator EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "data is not aligned"); + eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) && "data is not aligned"); +#else + eigen_assert(EIGEN_IMPLIES(internal::traits::IsAligned, (size_t(m_data) % 16) == 0) && "data is not aligned"); +#endif + } PointerType m_data; diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index cac90bc1f..453180049 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -33,14 +33,29 @@ template class Pro namespace internal { template struct traits > - : traits > -{ - // We want A+B*C to be of type Product and not Product - // TODO: This flag should eventually go in a separate evaluator traits class +{ + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + + typedef MatrixXpr XprKind; + + typedef typename scalar_product_traits::ReturnType Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + enum { - Flags = traits >::Flags & ~(EvalBeforeNestingBit | DirectAccessBit) + RowsAtCompileTime = LhsCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsCleaned::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsCleaned::MaxColsAtCompileTime, + + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. + Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) }; }; + } // end namespace internal @@ -59,8 +74,6 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, typename internal::promote_storage_type::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) - - typedef typename internal::nested::type LhsNested; typedef typename internal::nested::type RhsNested; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 7ebf31696..1159c2f44 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -17,19 +17,6 @@ namespace Eigen { namespace internal { -/** \internal - * \class product_evaluator - * Products need their own evaluator with more template arguments allowing for - * easier partial template specializations. - */ -template< typename T, - int ProductTag = internal::product_type::ret, - typename LhsShape = typename evaluator_traits::Shape, - typename RhsShape = typename evaluator_traits::Shape, - typename LhsScalar = typename T::Lhs::Scalar, - typename RhsScalar = typename T::Rhs::Scalar - > struct product_evaluator; - /** \internal * Evaluator of a product expression. * Since products require special treatments to handle all possible cases, @@ -119,6 +106,18 @@ struct product_evaluator, ProductTag, DenseSha : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); + +// FIXME shall we handle nested_eval here? +// typedef typename internal::nested_eval::type LhsNested; +// typedef typename internal::nested_eval::type RhsNested; +// typedef typename internal::remove_all::type LhsNestedCleaned; +// typedef typename internal::remove_all::type RhsNestedCleaned; +// +// const LhsNested lhs(xpr.lhs()); +// const RhsNested rhs(xpr.rhs()); +// +// generic_product_impl::evalTo(m_result, lhs, rhs); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } @@ -133,6 +132,7 @@ struct Assignment, internal::assign_ typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { + // FIXME shall we handle nested_eval here? generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); } }; @@ -144,6 +144,7 @@ struct Assignment, internal::add_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) { + // FIXME shall we handle nested_eval here? generic_product_impl::addTo(dst, src.lhs(), src.rhs()); } }; @@ -155,6 +156,7 @@ struct Assignment, internal::sub_ass typedef Product SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) { + // FIXME shall we handle nested_eval here? generic_product_impl::subTo(dst, src.lhs(), src.rhs()); } }; @@ -368,7 +370,6 @@ struct product_evaluator, ProductTag, DenseShape, : evaluator_base > { typedef Product XprType; - typedef CoeffBasedProduct CoeffBasedProductType; typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; @@ -396,9 +397,13 @@ struct product_evaluator, ProductTag, DenseShape, typedef typename evaluator::type RhsEtorType; enum { - RowsAtCompileTime = traits::RowsAtCompileTime, + RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), + MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime, + PacketSize = packet_traits::size, - InnerSize = traits::InnerSize, LhsCoeffReadCost = LhsEtorType::CoeffReadCost, RhsCoeffReadCost = RhsEtorType::CoeffReadCost, @@ -407,8 +412,51 @@ struct product_evaluator, ProductTag, DenseShape, + (InnerSize - 1) * NumTraits::AddCost, Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = traits::CanVectorizeInner, - Flags = traits::Flags + + LhsFlags = LhsEtorType::Flags, + RhsFlags = RhsEtorType::Flags, + + LhsRowMajor = LhsFlags & RowMajorBit, + RhsRowMajor = RhsFlags & RowMajorBit, + + SameType = is_same::value, + + CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit) + && (ColsAtCompileTime == Dynamic + || ( (ColsAtCompileTime % packet_traits::size) == 0 + && (RhsFlags&AlignedBit) + ) + ), + + CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) + && (RowsAtCompileTime == Dynamic + || ( (RowsAtCompileTime % packet_traits::size) == 0 + && (LhsFlags&AlignedBit) + ) + ), + + EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : (RhsRowMajor && !CanVectorizeLhs), + + Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) + | (EvalToRowMajor ? RowMajorBit : 0) + | (CanVectorizeLhs ? (LhsFlags & AlignedBit) : 0) + | (CanVectorizeRhs ? (RhsFlags & AlignedBit) : 0) + // TODO enable vectorization for mixed types + | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), + + /* 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 + * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect + * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. + */ + CanVectorizeInner = SameType + && LhsRowMajor + && (!RhsRowMajor) + && (LhsFlags & RhsFlags & ActualPacketAccessBit) + && (LhsFlags & RhsFlags & AlignedBit) + && (InnerSize % packet_traits::size == 0) }; const CoeffReturnType coeff(Index row, Index col) const @@ -689,7 +737,7 @@ protected: * Diagonal products ***************************************************************************/ -template +template struct diagonal_product_evaluator_base : evaluator_base { @@ -698,7 +746,20 @@ struct diagonal_product_evaluator_base typedef typename internal::packet_traits::type PacketScalar; public: enum { - CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost + CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost, + + MatrixFlags = evaluator::Flags, + DiagFlags = evaluator::Flags, + _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), + _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit + //(int(MatrixFlags)&int(DiagFlags)&AlignedBit), }; diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) @@ -724,7 +785,7 @@ protected: { enum { InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) + DiagonalPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagFlags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) }; return internal::pmul(m_matImpl.template packet(row, col), m_diagImpl.template packet(id)); @@ -737,9 +798,9 @@ protected: // diagonal * dense template struct product_evaluator, ProductTag, DiagonalShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : diagonal_product_evaluator_base > + : diagonal_product_evaluator_base, OnTheLeft> { - typedef diagonal_product_evaluator_base > Base; + typedef diagonal_product_evaluator_base, OnTheLeft> Base; using Base::m_diagImpl; using Base::m_matImpl; using Base::coeff; @@ -783,9 +844,9 @@ struct product_evaluator, ProductTag, DiagonalSha // dense * diagonal template struct product_evaluator, ProductTag, DenseShape, DiagonalShape, typename Lhs::Scalar, typename Rhs::Scalar> - : diagonal_product_evaluator_base > + : diagonal_product_evaluator_base, OnTheRight> { - typedef diagonal_product_evaluator_base > Base; + typedef diagonal_product_evaluator_base, OnTheRight> Base; using Base::m_diagImpl; using Base::m_matImpl; using Base::coeff; diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 41290323f..6c8c58e95 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -389,8 +389,19 @@ DenseBase::redux(const Func& func) const eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); #ifdef EIGEN_TEST_EVALUATORS + // FIXME, eval_nest should be handled by redux_evaluator, however: + // - it is currently difficult to provide the right Flags since they are still handled by the expressions + // - handling it here might reduce the number of template instantiations +// typedef typename internal::nested_eval::type ThisNested; +// typedef typename internal::remove_all::type ThisNestedCleaned; +// typedef typename internal::redux_evaluator ThisEvaluator; +// +// ThisNested thisNested(derived()); +// ThisEvaluator thisEval(thisNested); + typedef typename internal::redux_evaluator ThisEvaluator; ThisEvaluator thisEval(derived()); + return internal::redux_impl::run(thisEval, func); #else diff --git a/Eigen/src/Core/Replicate.h b/Eigen/src/Core/Replicate.h index 1e640d8aa..2dff03ea3 100644 --- a/Eigen/src/Core/Replicate.h +++ b/Eigen/src/Core/Replicate.h @@ -53,10 +53,13 @@ struct traits > IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0) + #ifndef EIGEN_TEST_EVALUATORS - , + Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), CoeffReadCost = _MatrixTypeNested::CoeffReadCost +#else + // FIXME enable DirectAccess with negative strides? + Flags = IsRowMajor ? RowMajorBit : 0 #endif }; }; diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index 495b44cc4..4969bb4fc 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -45,14 +45,15 @@ struct traits > MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, +#ifndef EIGEN_TEST_EVALUATORS // let's enable LinearAccess only with vectorization because of the product overhead LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) ? LinearAccessBit : 0, - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess) -#ifndef EIGEN_TEST_EVALUATORS - , + Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), CoeffReadCost = _MatrixTypeNested::CoeffReadCost +#else + Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) #endif }; }; diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h index abcba2d15..d4fd88e62 100644 --- a/Eigen/src/Core/Select.h +++ b/Eigen/src/Core/Select.h @@ -43,12 +43,13 @@ struct traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits #ifndef EIGEN_TEST_EVALUATORS - , + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, CoeffReadCost = traits::type>::CoeffReadCost + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, traits::type>::CoeffReadCost) +#else + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit #endif }; }; diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 98f9e888f..11b0e45a8 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -41,12 +41,17 @@ struct traits > : traits ColsAtCompileTime = MatrixType::RowsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime, +#ifndef EIGEN_TEST_EVALUATORS FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), Flags1 = Flags0 | FlagsLvalueBit, Flags = Flags1 ^ RowMajorBit, -#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = MatrixTypeNestedPlain::CoeffReadCost, +#else + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), + Flags1 = Flags0 | FlagsLvalueBit, + Flags = Flags1 ^ RowMajorBit, #endif InnerStrideAtCompileTime = inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = outer_stride_at_compile_time::ret diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index 702d0006d..672b9662f 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -48,8 +48,12 @@ struct traits > ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime, +#ifndef EIGEN_TEST_EVALUATORS Flags0 = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits, Flags = (Flags0 & ~RowMajorBit) | (RowsAtCompileTime == 1 ? RowMajorBit : 0), +#else + Flags = RowsAtCompileTime == 1 ? RowMajorBit : 0, +#endif TraversalSize = Direction==Vertical ? MatrixType::RowsAtCompileTime : MatrixType::ColsAtCompileTime }; #ifndef EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index eed7f4258..771613b11 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h @@ -259,7 +259,7 @@ template struct trmv_selector typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; typedef internal::blas_traits RhsBlasTraits; typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - + typedef Map, Aligned> MappedDest; typename internal::add_const_on_value_type::type actualLhs = LhsBlasTraits::extract(lhs); diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 975fdbf2a..092ba758e 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -157,6 +157,18 @@ template struct product_type; +/** \internal + * \class product_evaluator + * Products need their own evaluator with more template arguments allowing for + * easier partial template specializations. + */ +template< typename T, + int ProductTag = internal::product_type::ret, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + typename LhsScalar = typename T::Lhs::Scalar, + typename RhsScalar = typename T::Rhs::Scalar + > struct product_evaluator; } template type; }; +#ifndef EIGEN_TEST_EVALUATORS template class compute_matrix_flags { @@ -158,6 +159,57 @@ class compute_matrix_flags enum { ret = LinearAccessBit | LvalueBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit }; }; +#else // EIGEN_TEST_EVALUATORS + +template +class compute_matrix_flags +{ + enum { row_major_bit = Options&RowMajor ? RowMajorBit : 0 }; + public: + // FIXME currently we still have to handle DirectAccessBit at the expression level to handle DenseCoeffsBase<> + // and then propagate this information to the evaluator's flags. + // However, I (Gael) think that DirectAccessBit should only matter at the evaluation stage. + enum { ret = DirectAccessBit | LvalueBit | NestByRefBit | row_major_bit }; +}; +#endif + +#ifdef EIGEN_ENABLE_EVALUATORS +template +class compute_matrix_evaluator_flags +{ + enum { + row_major_bit = Options&RowMajor ? RowMajorBit : 0, + is_dynamic_size_storage = MaxRows==Dynamic || MaxCols==Dynamic, + + aligned_bit = + ( + ((Options&DontAlign)==0) + && ( +#if EIGEN_ALIGN_STATICALLY + ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % 16) == 0)) +#else + 0 +#endif + + || + +#if EIGEN_ALIGN + is_dynamic_size_storage +#else + 0 +#endif + + ) + ) ? AlignedBit : 0, + packet_access_bit = packet_traits::Vectorizable && aligned_bit ? PacketAccessBit : 0 + }; + + public: + enum { ret = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit | aligned_bit }; +}; + +#endif // EIGEN_ENABLE_EVALUATORS + template struct size_at_compile_time { enum { ret = (_Rows==Dynamic || _Cols==Dynamic) ? Dynamic : _Rows * _Cols }; -- cgit v1.2.3 From 0bd5671b9e0fe85a7de50d316688b83927900bca Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 13:35:44 +0100 Subject: Fix Eigenvalues module --- Eigen/src/Eigenvalues/Tridiagonalization.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index 192278d68..e3a27f275 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -18,8 +18,10 @@ namespace internal { template struct TridiagonalizationMatrixTReturnType; template struct traits > + : public traits { - typedef typename MatrixType::PlainObject ReturnType; + typedef typename MatrixType::PlainObject ReturnType; // FIXME shall it be a BandMatrix? + enum { Flags = 0 }; }; template -- cgit v1.2.3 From a6be1952f4d345b10011c605a833e609bcc695e7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 16:18:34 +0100 Subject: Fix a few regression when moving the flags --- Eigen/Core | 7 +++++++ Eigen/src/Core/AssignEvaluator.h | 4 ++++ Eigen/src/Core/CoreEvaluators.h | 8 ++++---- Eigen/src/Core/Matrix.h | 3 +++ Eigen/src/Core/PlainObjectBase.h | 4 ++++ Eigen/src/Core/Product.h | 8 ++++++++ 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 474ef5f8f..6d5571875 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -11,6 +11,13 @@ #ifndef EIGEN_CORE_H #define EIGEN_CORE_H +// EIGEN_TEST_EVALUATORS => EIGEN_ENABLE_EVALUATORS +#ifdef EIGEN_TEST_EVALUATORS +#ifndef EIGEN_ENABLE_EVALUATORS +#define EIGEN_ENABLE_EVALUATORS +#endif +#endif + // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 05816094c..62ab531f0 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -126,6 +126,10 @@ public: EIGEN_DEBUG_VAR(PacketSize) EIGEN_DEBUG_VAR(StorageOrdersAgree) EIGEN_DEBUG_VAR(MightVectorize) + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(DstFlags) + EIGEN_DEBUG_VAR(SrcFlags) + std::cerr.unsetf(std::ios::hex); EIGEN_DEBUG_VAR(MayLinearize) EIGEN_DEBUG_VAR(MayInnerVectorize) EIGEN_DEBUG_VAR(MayLinearVectorize) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index a5de3593c..5f2d742f8 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -779,10 +779,10 @@ struct evaluator > MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, FlagsRowMajorBit = XprType::Flags&RowMajorBit, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), + Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit | + MaskAlignedBit), Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit }; typedef block_evaluator block_evaluator_type; diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index f84db0dc2..cd4913525 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -117,6 +117,9 @@ struct traits > Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, #ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = NumTraits::ReadCost, +#else + // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase + EvaluatorFlags = compute_matrix_evaluator_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, #endif Options = _Options, InnerStrideAtCompileTime = 1, diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 4f456804c..c31bfbc8c 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -128,7 +128,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type DenseStorage m_storage; public: +#ifndef EIGEN_TEST_EVALUATORS enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; +#else + enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::EvaluatorFlags & AlignedBit) != 0 }; +#endif EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 453180049..2785847a6 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -51,6 +51,14 @@ struct traits > MaxRowsAtCompileTime = LhsCleaned::MaxRowsAtCompileTime, MaxColsAtCompileTime = RhsCleaned::MaxColsAtCompileTime, + // FIXME: only needed by GeneralMatrixMatrixTriangular + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsCleaned::ColsAtCompileTime, RhsCleaned::RowsAtCompileTime), + +#ifndef EIGEN_TEST_EVALUATORS + // dummy, for evaluators unit test only + CoeffReadCost = Dynamic, +#endif + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) }; -- cgit v1.2.3 From 0b362e0c9ab1670e73fc8ae951d765f686342882 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 16:18:54 +0100 Subject: This file is not needed anymore --- Eigen/src/Core/products/CoeffBasedProduct.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 94099b7d3..85e8ac2c7 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -13,6 +13,7 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS namespace internal { /********************************************************************************* @@ -451,6 +452,8 @@ struct product_packet_impl #endif // EIGEN_TEST_EVALUATORS +#endif // Date: Wed, 12 Mar 2014 18:13:18 +0100 Subject: Extend evaluation traits debuging info --- Eigen/src/Core/AssignEvaluator.h | 11 +++++++---- Eigen/src/Core/Redux.h | 26 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 62ab531f0..a083e340e 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -118,6 +118,12 @@ public: #ifdef EIGEN_DEBUG_ASSIGN static void debug() { + std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; + std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(DstFlags) + EIGEN_DEBUG_VAR(SrcFlags) + std::cerr.unsetf(std::ios::hex); EIGEN_DEBUG_VAR(DstIsAligned) EIGEN_DEBUG_VAR(SrcIsAligned) EIGEN_DEBUG_VAR(JointAlignment) @@ -126,10 +132,6 @@ public: EIGEN_DEBUG_VAR(PacketSize) EIGEN_DEBUG_VAR(StorageOrdersAgree) EIGEN_DEBUG_VAR(MightVectorize) - std::cerr.setf(std::ios::hex, std::ios::basefield); - EIGEN_DEBUG_VAR(DstFlags) - EIGEN_DEBUG_VAR(SrcFlags) - std::cerr.unsetf(std::ios::hex); EIGEN_DEBUG_VAR(MayLinearize) EIGEN_DEBUG_VAR(MayInnerVectorize) EIGEN_DEBUG_VAR(MayLinearVectorize) @@ -139,6 +141,7 @@ public: EIGEN_DEBUG_VAR(MayUnrollCompletely) EIGEN_DEBUG_VAR(MayUnrollInner) EIGEN_DEBUG_VAR(Unrolling) + std::cerr << std::endl; } #endif }; diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 6c8c58e95..b9d59af47 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -65,6 +65,29 @@ public: ? CompleteUnrolling : NoUnrolling }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; +#else + std::cerr << "Xpr: " << typeid(Derived).name() << std::endl; +#endif + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(Derived::Flags) + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + EIGEN_DEBUG_VAR(Traversal) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(Unrolling) + std::cerr << std::endl; + } +#endif }; /*************************************************************************** @@ -311,10 +334,11 @@ struct redux_impl #ifdef EIGEN_ENABLE_EVALUATORS // evaluator adaptor -template +template class redux_evaluator { public: + typedef _XprType XprType; redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} typedef typename XprType::Index Index; -- cgit v1.2.3 From f74ed345395b57f299d597c835177222120d9992 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 18:14:08 +0100 Subject: Fix regressions in redux_evaluator flags and evaluator flags --- Eigen/src/Core/Block.h | 2 +- Eigen/src/Core/CoreEvaluators.h | 26 +++++++++++++------------- Eigen/src/Core/Redux.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index d92797a98..e0b24e199 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -98,7 +98,7 @@ struct traits > : traits::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, Flags = (traits::Flags & DirectAccessBit) | FlagsLvalueBit | FlagsRowMajorBit // FIXME DirectAccessBit should not be handled by expressions diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 5f2d742f8..47f50d548 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -756,23 +756,23 @@ struct evaluator > enum { CoeffReadCost = evaluator::CoeffReadCost, - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 - : XprTypeIsRowMajor, - HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + : ArgTypeIsRowMajor, + HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - InnerStrideAtCompileTime = HasSameStorageOrderAsXprType - ? int(inner_stride_at_compile_time::ret) - : int(outer_stride_at_compile_time::ret), - OuterStrideAtCompileTime = HasSameStorageOrderAsXprType - ? int(outer_stride_at_compile_time::ret) - : int(inner_stride_at_compile_time::ret), + InnerStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) && (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index b9d59af47..1e2270d34 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -351,7 +351,7 @@ public: MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator - Flags = XprType::Flags & ~DirectAccessBit, + Flags = evaluator::Flags & ~DirectAccessBit, IsRowMajor = XprType::IsRowMajor, SizeAtCompileTime = XprType::SizeAtCompileTime, InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, -- cgit v1.2.3 From a395024d4496d6ee5f6876c41a7988e340b392e1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 18:14:58 +0100 Subject: More debug info and use lazyProd instead of operator* to query the right flags --- test/vectorization_logic.cpp | 69 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp index aee68a87f..23be0ffba 100644 --- a/test/vectorization_logic.cpp +++ b/test/vectorization_logic.cpp @@ -27,19 +27,43 @@ std::string demangle_unrolling(int t) if(t==CompleteUnrolling) return "CompleteUnrolling"; return "?"; } +std::string demangle_flags(int f) +{ + std::string res; + if(f&RowMajorBit) res += " | RowMajor"; + if(f&PacketAccessBit) res += " | Packet"; + if(f&LinearAccessBit) res += " | Linear"; + if(f&LvalueBit) res += " | Lvalue"; + if(f&DirectAccessBit) res += " | Direct"; + if(f&AlignedBit) res += " | Aligned"; + if(f&NestByRefBit) res += " | NestByRef"; + return res; +} template bool test_assign(const Dst&, const Src&, int traversal, int unrolling) { - internal::assign_traits::debug(); - bool res = internal::assign_traits::Traversal==traversal - && internal::assign_traits::Unrolling==unrolling; +#ifdef EIGEN_TEST_EVALUATORS + typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; +#else + typedef internal::assign_traits traits; +#endif + bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { + std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; +#endif + std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; +#endif + traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) - << " got " << demangle_traversal(internal::assign_traits::Traversal) << "\n"; + << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) - << " got " << demangle_unrolling(internal::assign_traits::Unrolling) << "\n"; + << " got " << demangle_unrolling(traits::Unrolling) << "\n"; } return res; } @@ -47,15 +71,27 @@ bool test_assign(const Dst&, const Src&, int traversal, int unrolling) template bool test_assign(int traversal, int unrolling) { - internal::assign_traits::debug(); - bool res = internal::assign_traits::Traversal==traversal - && internal::assign_traits::Unrolling==unrolling; +#ifdef EIGEN_TEST_EVALUATORS + typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; +#else + typedef internal::assign_traits traits; +#endif + bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { + std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; +#endif + std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; +#endif + traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) - << " got " << demangle_traversal(internal::assign_traits::Traversal) << "\n"; + << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) - << " got " << demangle_unrolling(internal::assign_traits::Unrolling) << "\n"; + << " got " << demangle_unrolling(traits::Unrolling) << "\n"; } return res; } @@ -63,10 +99,21 @@ bool test_assign(int traversal, int unrolling) template bool test_redux(const Xpr&, int traversal, int unrolling) { +#ifdef EIGEN_TEST_EVALUATORS + typedef internal::redux_traits,internal::redux_evaluator > traits; +#else typedef internal::redux_traits,Xpr> traits; +#endif + bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { + std::cerr << demangle_flags(Xpr::Flags) << std::endl; +#ifdef EIGEN_TEST_EVALUATORS + std::cerr << demangle_flags(internal::evaluator::Flags) << std::endl; +#endif + traits::debug(); + std::cerr << " Expected Traversal == " << demangle_traversal(traversal) << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) @@ -185,7 +232,7 @@ template::Vectori Matrix22 >(DefaultTraversal,CompleteUnrolling))); - VERIFY((test_assign(Matrix11(), Matrix11()*Matrix11(), InnerVectorizedTraversal, CompleteUnrolling))); + VERIFY((test_assign(Matrix11(), Matrix11().lazyProduct(Matrix11()), InnerVectorizedTraversal, CompleteUnrolling))); #endif VERIFY(test_assign(MatrixXX(10,10),MatrixXX(20,20).block(10,10,2,3), -- cgit v1.2.3 From 16d4c7a5e80cc1bcda3eb5d3eb9c5e890d47b2b5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 20:23:44 +0100 Subject: Conditionally disable unit tests that are not supported by evaluators yet --- test/CMakeLists.txt | 66 ++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e1bff179d..83cdb40b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -129,7 +129,6 @@ add_custom_target(BuildOfficial) option(EIGEN_TEST_EVALUATORS "Enable work in progress evaluators" OFF) if(EIGEN_TEST_EVALUATORS) add_definitions("-DEIGEN_TEST_EVALUATORS=1") - add_definitions("-DEIGEN_ENABLE_EVALUATORS=1") endif(EIGEN_TEST_EVALUATORS) ei_add_test(meta) @@ -137,6 +136,7 @@ ei_add_test(sizeof) ei_add_test(dynalloc) ei_add_test(nomalloc) ei_add_test(first_aligned) +ei_add_test(nullary) ei_add_test(mixingtypes) ei_add_test(packetmath) ei_add_test(unalignedassert) @@ -144,13 +144,15 @@ ei_add_test(vectorization_logic) ei_add_test(basicstuff) ei_add_test(linearstructure) ei_add_test(integer_types) -ei_add_test(cwiseop) ei_add_test(unalignedcount) ei_add_test(exceptions) ei_add_test(redux) ei_add_test(visitor) ei_add_test(block) ei_add_test(corners) +ei_add_test(swap) +ei_add_test(resize) +ei_add_test(conservative_resize) ei_add_test(product_small) ei_add_test(product_large) ei_add_test(product_extra) @@ -179,6 +181,7 @@ ei_add_test(product_trsolve) ei_add_test(product_mmtr) ei_add_test(product_notemporary) ei_add_test(stable_norm) +ei_add_test(permutationmatrices) ei_add_test(bandmatrix) ei_add_test(cholesky) ei_add_test(lu) @@ -198,30 +201,33 @@ ei_add_test(real_qz) ei_add_test(eigensolver_generalized_real) ei_add_test(jacobi) ei_add_test(jacobisvd) -ei_add_test(geo_orthomethods) -ei_add_test(geo_homogeneous) -ei_add_test(geo_quaternion) -ei_add_test(geo_transformations) -ei_add_test(geo_eulerangles) -ei_add_test(geo_hyperplane) -ei_add_test(geo_parametrizedline) -ei_add_test(geo_alignedbox) -ei_add_test(stdvector) -ei_add_test(stdvector_overload) -ei_add_test(stdlist) -ei_add_test(stddeque) -ei_add_test(resize) -ei_add_test(sparse_vector) -ei_add_test(sparse_basic) -ei_add_test(sparse_product) -ei_add_test(sparse_solvers) -ei_add_test(umeyama) ei_add_test(householder) -ei_add_test(swap) -ei_add_test(conservative_resize) -ei_add_test(permutationmatrices) -ei_add_test(sparse_permutations) -ei_add_test(nullary) +if(NOT EIGEN_TEST_EVALUATORS) + ei_add_test(cwiseop) # Eigen2 related + ei_add_test(geo_orthomethods) + ei_add_test(geo_homogeneous) + ei_add_test(geo_quaternion) + ei_add_test(geo_transformations) + ei_add_test(geo_eulerangles) + ei_add_test(geo_hyperplane) + ei_add_test(geo_parametrizedline) + ei_add_test(geo_alignedbox) + ei_add_test(stdvector) + ei_add_test(stdvector_overload) + ei_add_test(stdlist) + ei_add_test(stddeque) + ei_add_test(sparse_vector) + ei_add_test(sparse_basic) + ei_add_test(sparse_product) + ei_add_test(sparse_solvers) + ei_add_test(sparse_permutations) + ei_add_test(simplicial_cholesky) + ei_add_test(conjugate_gradient) + ei_add_test(bicgstab) + ei_add_test(sparselu) + ei_add_test(sparseqr) +endif(NOT EIGEN_TEST_EVALUATORS) +ei_add_test(umeyama) ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}") ei_add_test(zerosized) ei_add_test(dontalign) @@ -233,13 +239,9 @@ ei_add_test(special_numbers) ei_add_test(rvalue_types) ei_add_test(dense_storage) -ei_add_test(simplicial_cholesky) -ei_add_test(conjugate_gradient) -ei_add_test(bicgstab) -ei_add_test(sparselu) -ei_add_test(sparseqr) +# # ei_add_test(denseLM) -# ei_add_test(denseLM) +if(NOT EIGEN_TEST_EVALUATORS) if(QT4_FOUND) ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}") @@ -275,6 +277,8 @@ if(METIS_FOUND) ei_add_test(metis_support "" "${METIS_LIBRARIES}") endif() +endif(NOT EIGEN_TEST_EVALUATORS) + string(TOLOWER "${CMAKE_CXX_COMPILER}" cmake_cxx_compiler_tolower) if(cmake_cxx_compiler_tolower MATCHES "qcc") set(CXX_IS_QCC "ON") -- cgit v1.2.3 From aceae8314b80fbf96e8dc1b0d45c1e99951e770c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 12 Mar 2014 20:25:36 +0100 Subject: Resurect EvalBeforeNestingBit to control nested_eval --- Eigen/src/Core/Inverse.h | 2 ++ Eigen/src/Core/util/Constants.h | 3 +-- Eigen/src/Core/util/XprHelper.h | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 0cfc71d34..57eaf99f1 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -110,6 +110,8 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; evaluator(const InverseType& inv_xpr) : m_result(inv_xpr.rows(), inv_xpr.cols()) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index d9e51ffea..64efac8e9 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -53,9 +53,8 @@ const int Infinity = -1; const unsigned int RowMajorBit = 0x1; /** \ingroup flags - * \deprecated * means the expression should be evaluated by the calling expression */ -const unsigned int EvalBeforeNestingBit = 0x2; // FIXME deprecated +const unsigned int EvalBeforeNestingBit = 0x2; /** \ingroup flags * \deprecated diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 016b37f71..0be5029c9 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -432,7 +432,8 @@ template::type> struc }; typedef typename conditional< - int(CostEvalAsInteger) < int(CostNoEvalAsInteger), + ( (int(evaluator::Flags) & EvalBeforeNestingBit) || + (int(CostEvalAsInteger) < int(CostNoEvalAsInteger)) ), PlainObject, typename ref_selector::type >::type type; -- cgit v1.2.3 From 0a6c472335b593a227c3adbcf1d770187449a30f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 13 Mar 2014 15:44:20 +0100 Subject: A bit of cleaning --- Eigen/src/Core/Assign.h | 82 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 95eb37dd5..0e10f125f 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -509,7 +509,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase #ifdef EIGEN_TEST_EVALUATORS eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::call_dense_assignment_loop(derived(),other.derived()); + internal::call_assignment_no_alias(derived(),other.derived()); #else // EIGEN_TEST_EVALUATORS @@ -530,23 +530,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase namespace internal { -#ifdef EIGEN_TEST_EVALUATORS - -// TODO remove this class which is now useless - -template -struct assign_selector { - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { - call_assignment(dst, other.derived(), internal::assign_op()); - return dst; - } - template - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; - -#else // EIGEN_TEST_EVALUATORS +#ifndef EIGEN_TEST_EVALUATORS template::Flags) & EvalBeforeAssigningBit) != 0, bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) @@ -585,6 +569,59 @@ struct assign_selector { #endif // EIGEN_TEST_EVALUATORS } // end namespace internal +#ifdef EIGEN_TEST_EVALUATORS +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) +{ + other.derived().evalTo(derived()); + return derived(); +} +#else // EIGEN_TEST_EVALUATORS template template EIGEN_DEVICE_FUNC @@ -620,11 +657,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { -#ifdef EIGEN_TEST_EVALUATORS - return internal::assign_selector::evalTo(derived(), other.derived()); -#else return internal::assign_selector::evalTo(derived(), other.derived()); -#endif } template @@ -632,12 +665,9 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { -#ifdef EIGEN_TEST_EVALUATORS - return internal::assign_selector::evalTo(derived(), other.derived()); -#else return internal::assign_selector::evalTo(derived(), other.derived()); -#endif } +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen -- cgit v1.2.3 From 59f5f155c2d4c6069f61fc3df39c7f6264857488 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 15 Apr 2014 15:21:38 +0100 Subject: Port products with permutation matrices to evaluators. --- Eigen/src/Core/PermutationMatrix.h | 116 ++++++++++++++++++++++++++++++++++++- Eigen/src/Core/Product.h | 26 ++++++++- Eigen/src/Core/ProductEvaluators.h | 87 ++++++++++++++++++++++++++++ Eigen/src/Core/util/Constants.h | 1 + 4 files changed, 227 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 9add80c54..61aa0ce31 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -288,6 +288,10 @@ class PermutationMatrix : public PermutationBase Traits; public: +#ifdef EIGEN_TEST_EVALUATORS + typedef const PermutationMatrix& Nested; +#endif + #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; #endif @@ -461,6 +465,22 @@ class Map, struct PermutationStorage {}; +#ifdef EIGEN_TEST_EVALUATORS + +// storage type of product of permutation wrapper with dense + +namespace internal { + +template<> struct promote_storage_type +{ typedef Dense ret; }; + +template<> struct promote_storage_type +{ typedef Dense ret; }; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + template class TranspositionsWrapper; namespace internal { template @@ -473,8 +493,13 @@ struct traits > enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, +#ifdef EIGEN_TEST_EVALUATORS + MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, +#else + MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, // is this a bug in Eigen 2.2 ? MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, +#endif Flags = 0 #ifndef EIGEN_TEST_EVALUATORS , @@ -508,6 +533,37 @@ class PermutationWrapper : public PermutationBase +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const PermutationBase& permutation) +{ + return Product + (matrix.derived(), permutation.derived()); +} + +/** \returns the matrix with the permutation applied to the rows. + */ +template +EIGEN_DEVICE_FUNC +const Product +operator*(const PermutationBase &permutation, + const MatrixBase& matrix) +{ + return Product + (permutation.derived(), matrix.derived()); +} + +#else // EIGEN_TEST_EVALUATORS + /** \returns the matrix with the permutation applied to the columns. */ template @@ -533,6 +589,8 @@ operator*(const PermutationBase &permutation, (permutation.derived(), matrix.derived()); } +#endif // EIGEN_TEST_EVALUATORS + namespace internal { template @@ -662,6 +720,28 @@ class Transpose > DenseMatrixType toDenseMatrix() const { return *this; } +#ifdef EIGEN_TEST_EVALUATORS + + /** \returns the matrix with the inverse permutation applied to the columns. + */ + template friend + const Product + operator*(const MatrixBase& matrix, const Transpose& trPerm) + { + return Product(matrix.derived(), trPerm.derived()); + } + + /** \returns the matrix with the inverse permutation applied to the rows. + */ + template + const Product + operator*(const MatrixBase& matrix) const + { + return Product(*this, matrix.derived()); + } + +#else // EIGEN_TEST_EVALUATORS + /** \returns the matrix with the inverse permutation applied to the columns. */ template friend @@ -680,6 +760,8 @@ class Transpose > return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); } +#endif // EIGEN_TEST_EVALUATORS + const PermutationType& nestedPermutation() const { return m_permutation; } protected: @@ -692,6 +774,38 @@ const PermutationWrapper MatrixBase::asPermutation() con return derived(); } +#ifdef EIGEN_TEST_EVALUATORS +namespace internal { + +// TODO currently a permutation matrix expression has the form PermutationMatrix or PermutationWrapper +// or their transpose; in the future shape should be defined by the expression traits +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef PermutationShape Shape; + static const int AssumeAliasing = 0; +}; + +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef PermutationShape Shape; + static const int AssumeAliasing = 0; +}; + +template +struct evaluator_traits > > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef PermutationShape Shape; + static const int AssumeAliasing = 0; +}; + +} // end namespace internal +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 2785847a6..626b737c7 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -29,8 +29,30 @@ template class Pro * */ -// Use ProductReturnType to get correct traits, in particular vectorization flags + namespace internal { + +// Determine the scalar of Product. This is normally the same as Lhs::Scalar times +// Rhs::Scalar, but product with permutation matrices inherit the scalar of the other factor. +template::Shape, + typename RhsShape = typename evaluator_traits::Shape > +struct product_result_scalar +{ + typedef typename scalar_product_traits::ReturnType Scalar; +}; + +template +struct product_result_scalar +{ + typedef typename Rhs::Scalar Scalar; +}; + +template + struct product_result_scalar +{ + typedef typename Lhs::Scalar Scalar; +}; + template struct traits > { @@ -39,7 +61,7 @@ struct traits > typedef MatrixXpr XprKind; - typedef typename scalar_product_traits::ReturnType Scalar; + typedef typename product_result_scalar::Scalar Scalar; typedef typename promote_storage_type::StorageKind, typename traits::StorageKind>::ret StorageKind; typedef typename promote_index_type::Index, diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 1159c2f44..7298c51b1 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -885,6 +885,93 @@ struct product_evaluator, ProductTag, DenseShape, }; +/*************************************************************************** +* Products with permutation matrices +***************************************************************************/ + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permut_matrix_product_retval pmpr(lhs, rhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permut_matrix_product_retval pmpr(rhs, lhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, DenseShape, ProductType> +{ + template + static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + permut_matrix_product_retval pmpr(lhs.nestedPermutation(), rhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl, DenseShape, PermutationShape, ProductType> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + permut_matrix_product_retval pmpr(rhs.nestedPermutation(), lhs); + pmpr.evalTo(dst); + } +}; + +// TODO: left/right and self-adj/symmetric/permutation look the same ... Too much boilerplate? +template +struct product_evaluator, ProductTag, PermutationShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, DenseShape, PermutationShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 64efac8e9..aae8625d1 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -447,6 +447,7 @@ struct DiagonalShape { static std::string debugName() { return "DiagonalShape struct BandShape { static std::string debugName() { return "BandShape"; } }; struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; +struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; struct SparseShape { static std::string debugName() { return "SparseShape"; } }; #endif -- cgit v1.2.3 From b30706bd5cfb9df8ab10f7861232623373aec626 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Tue, 15 Apr 2014 22:51:46 +0100 Subject: Fix typo in Inverse.h --- Eigen/src/Core/Inverse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 57eaf99f1..51a39fe29 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -63,7 +63,7 @@ public: EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } protected: - XprTypeNested &m_xpr; + XprTypeNested m_xpr; }; /** \internal -- cgit v1.2.3 From ffc995c9e40ef27cba672738802e989c4ee383d0 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Wed, 16 Apr 2014 18:16:36 +0100 Subject: Implement evaluator. All supported tests pass apart from Sparse and Geometry, except test in adjoint_4 that a = a.transpose() raises an assert. --- Eigen/src/Core/CoreEvaluators.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 47f50d548..8df1b706d 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -1292,6 +1292,32 @@ private: EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } }; +// -------------------- ReturnByValue -------------------- + +// Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that +// when a ReturnByValue expression is assigned, the evaluator is not constructed. +// TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world + +template +struct evaluator > + : evaluator::PlainObject>::type +{ + typedef typename ReturnByValue::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const ReturnByValue& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + + PlainObject m_result; +}; + } // namespace internal } // end namespace Eigen -- cgit v1.2.3 From 78bb80833708615c330659d9b64870b19185df37 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 20 Jun 2014 15:39:38 +0200 Subject: 1- Introduce sub-evaluator types for unary, binary, product, and map expressions to ease specializing them. 2- Remove a lot of code which should not be there with evaluators, in particular coeff/packet methods implemented in the expressions. --- Eigen/src/Core/ArrayBase.h | 4 + Eigen/src/Core/ArrayWrapper.h | 2 + Eigen/src/Core/Block.h | 13 +- Eigen/src/Core/CoreEvaluators.h | 247 ++++++++++++++------------ Eigen/src/Core/CwiseBinaryOp.h | 30 +++- Eigen/src/Core/CwiseUnaryOp.h | 14 +- Eigen/src/Core/CwiseUnaryView.h | 9 +- Eigen/src/Core/DenseBase.h | 5 +- Eigen/src/Core/DenseCoeffsBase.h | 45 +++-- Eigen/src/Core/Inverse.h | 9 +- Eigen/src/Core/Replicate.h | 1 + Eigen/src/Core/ReturnByValue.h | 28 +++ Eigen/src/Core/Reverse.h | 1 + Eigen/src/Core/Transpose.h | 30 ++-- Eigen/src/Core/TriangularMatrix.h | 4 +- Eigen/src/Core/products/GeneralMatrixMatrix.h | 4 +- Eigen/src/Core/util/ForwardDeclarations.h | 4 +- Eigen/src/Core/util/XprHelper.h | 9 + 18 files changed, 300 insertions(+), 159 deletions(-) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index d1c422836..f5bae6357 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -123,7 +123,11 @@ template class ArrayBase EIGEN_DEVICE_FUNC Derived& operator=(const ArrayBase& other) { +#ifndef EIGEN_TEST_EVALUATORS return internal::assign_selector::run(derived(), other.derived()); +#else + internal::call_assignment(derived(), other.derived()); +#endif } EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/ArrayWrapper.h b/Eigen/src/Core/ArrayWrapper.h index 4bb648024..599d87f64 100644 --- a/Eigen/src/Core/ArrayWrapper.h +++ b/Eigen/src/Core/ArrayWrapper.h @@ -39,6 +39,7 @@ class ArrayWrapper : public ArrayBase > typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -176,6 +177,7 @@ class MatrixWrapper : public MatrixBase > typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index e0b24e199..ef6c143d3 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -344,6 +344,9 @@ class BlockImpl_dense : public MapBase > { typedef Block BlockType; + enum { + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 + }; public: typedef MapBase Base; @@ -354,9 +357,8 @@ class BlockImpl_dense */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) - : Base(internal::const_cast_ptr(&xpr.coeffRef( - (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, - (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) + || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), m_xpr(xpr) @@ -368,7 +370,8 @@ class BlockImpl_dense */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), + m_xpr(xpr) { init(); } @@ -379,7 +382,7 @@ class BlockImpl_dense inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), m_xpr(xpr) { init(); diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 47f50d548..f872b41e1 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -27,14 +27,6 @@ struct storage_kind_to_evaluator_kind { typedef IndexBased Kind; }; -// TODO to be moved to SparseCore: -/* -template<> -struct storage_kind_to_evaluator_kind { - typedef IteratorBased Kind -}; -*/ - // This class returns the evaluator shape from the expression storage kind. // It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. template struct storage_kind_to_shape; @@ -45,22 +37,28 @@ struct storage_kind_to_shape { typedef DenseShape Shape; }; -// TODO to be moved to SparseCore: -/* -template<> -struct storage_kind_to_shape { - typedef SparseSpape Shape; -}; -*/ - +// Evaluators have to be specialized with respect to various criteria such as: +// - storage/structure/shape +// - scalar type +// - etc. +// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. +// We currently distinguish the following kind of evaluators: +// - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) +// - binary_evaluator for expression taking two arguments (CwiseBinaryOp) +// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. +// - mapbase_evaluator for Map, Block, Ref +// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) - template< typename T, - typename LhsKind = typename evaluator_traits::Kind, - typename RhsKind = typename evaluator_traits::Kind, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, typename LhsScalar = typename T::Lhs::Scalar, typename RhsScalar = typename T::Rhs::Scalar> struct binary_evaluator; +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct unary_evaluator; + // evaluator_traits contains traits for evaluator template @@ -80,15 +78,20 @@ struct evaluator_traits_base static const int AssumeAliasing = 0; }; +// Default evaluator traits template struct evaluator_traits : public evaluator_traits_base { }; -// expression class for evaluating nested expression to a temporary - -template -class EvalToTemp; + +// By default, we assume a unary expression: +template +struct evaluator : public unary_evaluator +{ + typedef unary_evaluator Base; + evaluator(const T& xpr) : Base(xpr) {} +}; // TODO: Think about const-correctness @@ -118,6 +121,8 @@ struct evaluator_base // // evaluator is a common base class for the // Matrix and Array evaluators. +// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, +// so no need for more sophisticated dispatching. template struct evaluator > @@ -245,81 +250,10 @@ struct evaluator > { } }; -// -------------------- EvalToTemp -------------------- - -template -struct traits > - : public traits -{ }; - -template -class EvalToTemp - : public dense_xpr_base >::type -{ - public: - - typedef typename dense_xpr_base::type Base; - EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) - - EvalToTemp(const ArgType& arg) - : m_arg(arg) - { } - - const ArgType& arg() const - { - return m_arg; - } - - Index rows() const - { - return m_arg.rows(); - } - - Index cols() const - { - return m_arg.cols(); - } - - private: - const ArgType& m_arg; -}; - -template -struct evaluator > - : public evaluator::type -{ - typedef EvalToTemp XprType; - typedef typename ArgType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - typedef evaluator type; - typedef evaluator nestedType; - - evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - // TODO we should simply do m_result(xpr.arg()); - call_dense_assignment_loop(m_result, xpr.arg()); - } - - // This constructor is used when nesting an EvalTo evaluator in another evaluator - evaluator(const ArgType& arg) - : m_result(arg.rows(), arg.cols()) - { - ::new (static_cast(this)) Base(m_result); - // TODO we should simply do m_result(xpr.arg()); - call_dense_assignment_loop(m_result, arg); - } - -protected: - PlainObject m_result; -}; - // -------------------- Transpose -------------------- template -struct evaluator > +struct unary_evaluator > : evaluator_base > { typedef Transpose XprType; @@ -329,7 +263,7 @@ struct evaluator > Flags = evaluator::Flags ^ RowMajorBit }; - evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -386,6 +320,8 @@ protected: }; // -------------------- CwiseNullaryOp -------------------- +// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. +// Likewise, there is not need to more sophisticated dispatching here. template struct evaluator > @@ -441,7 +377,7 @@ protected: // -------------------- CwiseUnaryOp -------------------- template -struct evaluator > +struct unary_evaluator, IndexBased > : evaluator_base > { typedef CwiseUnaryOp XprType; @@ -454,7 +390,7 @@ struct evaluator > | (functor_traits::PacketAccess ? PacketAccessBit : 0)) }; - evaluator(const XprType& op) + unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -492,8 +428,19 @@ protected: // -------------------- CwiseBinaryOp -------------------- +// this is a binary expression template struct evaluator > + : public binary_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef binary_evaluator > Base; + + evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct binary_evaluator > : evaluator_base > { typedef CwiseBinaryOp XprType; @@ -517,7 +464,7 @@ struct evaluator > Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) }; - evaluator(const XprType& xpr) + binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -560,7 +507,7 @@ protected: // -------------------- CwiseUnaryView -------------------- template -struct evaluator > +struct unary_evaluator > : evaluator_base > { typedef CwiseUnaryView XprType; @@ -571,7 +518,7 @@ struct evaluator > Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)) }; - evaluator(const XprType& op) + unary_evaluator(const XprType& op) : m_unaryOp(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -884,6 +831,7 @@ struct block_evaluator @@ -934,7 +882,7 @@ protected: // -------------------- Replicate -------------------- template -struct evaluator > +struct unary_evaluator > : evaluator_base > { typedef Replicate XprType; @@ -953,7 +901,7 @@ struct evaluator > Flags = (evaluator::Flags & HereditaryBits & ~RowMajorBit) | (traits::Flags & RowMajorBit) }; - evaluator(const XprType& replicate) + unary_evaluator(const XprType& replicate) : m_arg(replicate.nestedExpression()), m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), @@ -1111,23 +1059,23 @@ protected: }; template -struct evaluator > +struct unary_evaluator > : evaluator_wrapper_base > { typedef MatrixWrapper XprType; - evaluator(const XprType& wrapper) + unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; template -struct evaluator > +struct unary_evaluator > : evaluator_wrapper_base > { typedef ArrayWrapper XprType; - evaluator(const XprType& wrapper) + unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -1139,7 +1087,7 @@ struct evaluator > template struct reverse_packet_cond; template -struct evaluator > +struct unary_evaluator > : evaluator_base > { typedef Reverse XprType; @@ -1173,7 +1121,7 @@ struct evaluator > }; typedef internal::reverse_packet_cond reverse_packet; - evaluator(const XprType& reverse) + unary_evaluator(const XprType& reverse) : m_argImpl(reverse.nestedExpression()), m_rows(ReverseRow ? reverse.nestedExpression().rows() : 0), m_cols(ReverseCol ? reverse.nestedExpression().cols() : 0) @@ -1292,6 +1240,87 @@ private: EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } }; + + +//---------------------------------------------------------------------- +// deprecated code +//---------------------------------------------------------------------- + +// -------------------- EvalToTemp -------------------- + +// expression class for evaluating nested expression to a temporary + +template class EvalToTemp; + +template +struct traits > + : public traits +{ }; + +template +class EvalToTemp + : public dense_xpr_base >::type +{ + public: + + typedef typename dense_xpr_base::type Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) + + EvalToTemp(const ArgType& arg) + : m_arg(arg) + { } + + const ArgType& arg() const + { + return m_arg; + } + + Index rows() const + { + return m_arg.rows(); + } + + Index cols() const + { + return m_arg.cols(); + } + + private: + const ArgType& m_arg; +}; + +template +struct evaluator > + : public evaluator::type +{ + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + // TODO we should simply do m_result(xpr.arg()); + call_dense_assignment_loop(m_result, xpr.arg()); + } + + // This constructor is used when nesting an EvalTo evaluator in another evaluator + evaluator(const ArgType& arg) + : m_result(arg.rows(), arg.cols()) + { + ::new (static_cast(this)) Base(m_result); + // TODO we should simply do m_result(xpr.arg()); + call_dense_assignment_loop(m_result, arg); + } + +protected: + PlainObject m_result; +}; + } // namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 07861dbc9..5e4fb147b 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -94,23 +94,26 @@ struct traits > template class CwiseBinaryOpImpl; -template +template class CwiseBinaryOp : internal::no_assignment_operator, public CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> + BinaryOp, LhsType, RhsType, + typename internal::promote_storage_type::StorageKind, + typename internal::traits::StorageKind>::ret> { public: + + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; typedef typename CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, + BinaryOp, LhsType, RhsType, + typename internal::promote_storage_type::StorageKind, typename internal::traits::StorageKind>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) - typedef typename internal::nested::type LhsNested; - typedef typename internal::nested::type RhsNested; + typedef typename internal::nested::type LhsNested; + typedef typename internal::nested::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; @@ -157,6 +160,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp m_functor; }; +#ifndef EIGEN_TEST_EVALUATORS template class CwiseBinaryOpImpl : public internal::dense_xpr_base >::type @@ -195,6 +199,16 @@ class CwiseBinaryOpImpl derived().rhs().template packet(index)); } }; +#else +// Generic API dispatcher +template +class CwiseBinaryOpImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; +#endif /** replaces \c *this by \c *this - \a other. * diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index af05a9108..098034a1e 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -67,6 +67,7 @@ class CwiseUnaryOp : internal::no_assignment_operator, typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + typedef typename internal::remove_all::type NestedExpression; EIGEN_DEVICE_FUNC inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) @@ -96,6 +97,7 @@ class CwiseUnaryOp : internal::no_assignment_operator, const UnaryOp m_functor; }; +#ifndef EIGEN_TEST_EVALUATORS // This is the generic implementation for dense storage. // It can be used for any expression types implementing the dense concept. template @@ -107,7 +109,7 @@ class CwiseUnaryOpImpl typedef CwiseUnaryOp Derived; typedef typename internal::dense_xpr_base >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const { @@ -133,6 +135,16 @@ class CwiseUnaryOpImpl return derived().functor().packetOp(derived().nestedExpression().template packet(index)); } }; +#else +// Generic API dispatcher +template +class CwiseUnaryOpImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; +#endif } // end namespace Eigen diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 9cdebb8e7..92b031e19 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -66,6 +66,7 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + typedef typename internal::remove_all::type NestedExpression; inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} @@ -104,8 +105,8 @@ class CwiseUnaryViewImpl EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - inline Scalar* data() { return &coeffRef(0); } - inline const Scalar* data() const { return &coeff(0); } + inline Scalar* data() { return &(this->coeffRef(0)); } + inline const Scalar* data() const { return &(this->coeff(0)); } inline Index innerStride() const { @@ -116,6 +117,8 @@ class CwiseUnaryViewImpl { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } + +#ifndef EIGEN_TEST_EVALUATORS EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { @@ -136,6 +139,8 @@ class CwiseUnaryViewImpl { return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); } + +#endif }; } // end namespace Eigen diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index f3c79aa31..624276240 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -74,6 +74,7 @@ template class DenseBase using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; +#ifndef EIGEN_TEST_EVALUATORS using Base::packet; using Base::packetByOuterInner; using Base::writePacket; @@ -84,6 +85,7 @@ template class DenseBase using Base::copyCoeffByOuterInner; using Base::copyPacket; using Base::copyPacketByOuterInner; +#endif using Base::operator(); using Base::operator[]; using Base::x; @@ -280,7 +282,8 @@ template class DenseBase Derived& operator=(const ReturnByValue& func); #ifndef EIGEN_PARSED_BY_DOXYGEN - /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** Copies \a other into *this without evaluating other. \returns a reference to *this. + * \deprecated */ template EIGEN_DEVICE_FUNC Derived& lazyAssign(const DenseBase& other); diff --git a/Eigen/src/Core/DenseCoeffsBase.h b/Eigen/src/Core/DenseCoeffsBase.h index efabb5e67..6f35a67ca 100644 --- a/Eigen/src/Core/DenseCoeffsBase.h +++ b/Eigen/src/Core/DenseCoeffsBase.h @@ -97,8 +97,12 @@ class DenseCoeffsBase : public EigenBase EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); + && col >= 0 && col < cols()); +#ifndef EIGEN_TEST_EVALUATORS return derived().coeff(row, col); +#else + return typename internal::evaluator::type(derived()).coeff(row,col); +#endif } EIGEN_DEVICE_FUNC @@ -117,7 +121,7 @@ class DenseCoeffsBase : public EigenBase { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeff(row, col); + return coeff(row, col); } /** Short version: don't use this function, use @@ -140,7 +144,11 @@ class DenseCoeffsBase : public EigenBase coeff(Index index) const { eigen_internal_assert(index >= 0 && index < size()); +#ifndef EIGEN_TEST_EVALUATORS return derived().coeff(index); +#else + return typename internal::evaluator::type(derived()).coeff(index); +#endif } @@ -161,7 +169,7 @@ class DenseCoeffsBase : public EigenBase THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) #endif eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** \returns the coefficient at given index. @@ -179,7 +187,7 @@ class DenseCoeffsBase : public EigenBase operator()(Index index) const { eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** equivalent to operator[](0). */ @@ -219,9 +227,12 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); + eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); +#ifndef EIGEN_TEST_EVALUATORS return derived().template packet(row,col); +#else + return typename internal::evaluator::type(derived()).template packet(row,col); +#endif } @@ -247,7 +258,11 @@ class DenseCoeffsBase : public EigenBase EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { eigen_internal_assert(index >= 0 && index < size()); +#ifndef EIGEN_TEST_EVALUATORS return derived().template packet(index); +#else + return typename internal::evaluator::type(derived()).template packet(index); +#endif } protected: @@ -327,8 +342,12 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() - && col >= 0 && col < cols()); + && col >= 0 && col < cols()); +#ifndef EIGEN_TEST_EVALUATORS return derived().coeffRef(row, col); +#else + return typename internal::evaluator::type(derived()).coeffRef(row,col); +#endif } EIGEN_DEVICE_FUNC @@ -350,7 +369,7 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + return coeffRef(row, col); } @@ -374,7 +393,11 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); +#ifndef EIGEN_TEST_EVALUATORS return derived().coeffRef(index); +#else + return typename internal::evaluator::type(derived()).coeffRef(index); +#endif } /** \returns a reference to the coefficient at given index. @@ -393,7 +416,7 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -410,7 +433,7 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** equivalent to operator[](0). */ @@ -437,6 +460,7 @@ class DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase(row, col, other); } #endif +#endif // EIGEN_TEST_EVALUATORS }; diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 57eaf99f1..788d0664d 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -81,6 +81,7 @@ public: typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + typedef typename internal::remove_all::type NestedExpression; private: @@ -101,19 +102,19 @@ namespace internal { * \sa class Inverse */ template -struct evaluator > +struct unary_evaluator > : public evaluator::PlainObject>::type { typedef Inverse InverseType; typedef typename InverseType::PlainObject PlainObject; typedef typename evaluator::type Base; - typedef evaluator type; - typedef evaluator nestedType; + typedef evaluator type; + typedef evaluator nestedType; enum { Flags = Base::Flags | EvalBeforeNestingBit }; - evaluator(const InverseType& inv_xpr) + unary_evaluator(const InverseType& inv_xpr) : m_result(inv_xpr.rows(), inv_xpr.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/Replicate.h b/Eigen/src/Core/Replicate.h index 2dff03ea3..e63f0d421 100644 --- a/Eigen/src/Core/Replicate.h +++ b/Eigen/src/Core/Replicate.h @@ -74,6 +74,7 @@ template class Replicate typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + typedef typename internal::remove_all::type NestedExpression; template inline explicit Replicate(const OriginalMatrixType& a_matrix) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index d63b96138..30ade1b75 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -92,6 +92,34 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +#ifdef EIGEN_TEST_EVALUATORS +namespace internal { + +template +struct evaluator > + : public evaluator::ReturnType>::type +{ + typedef ReturnByValue XprType; + typedef typename internal::traits::ReturnType PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal +#endif + } // end namespace Eigen #endif // EIGEN_RETURNBYVALUE_H diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index 4969bb4fc..ceb6e4701 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -77,6 +77,7 @@ template class Reverse typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + typedef typename internal::remove_all::type NestedExpression; using Base::IsRowMajor; // next line is necessary because otherwise const version of operator() diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 079f21fd9..4b605dfd6 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -68,6 +68,7 @@ template class Transpose typedef typename TransposeImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose) + typedef typename internal::remove_all::type NestedExpression; EIGEN_DEVICE_FUNC inline Transpose(MatrixType& a_matrix) : m_matrix(a_matrix) {} @@ -113,6 +114,7 @@ template class TransposeImpl public: typedef typename internal::TransposeImpl_base::type Base; + using Base::coeffRef; EIGEN_DENSE_PUBLIC_INTERFACE(Transpose) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(TransposeImpl) @@ -127,6 +129,8 @@ template class TransposeImpl inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } inline const Scalar* data() const { return derived().nestedExpression().data(); } + +#ifndef EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index rowId, Index colId) @@ -142,18 +146,6 @@ template class TransposeImpl return derived().nestedExpression().const_cast_derived().coeffRef(index); } - EIGEN_DEVICE_FUNC - inline const Scalar& coeffRef(Index rowId, Index colId) const - { - return derived().nestedExpression().coeffRef(colId, rowId); - } - - EIGEN_DEVICE_FUNC - inline const Scalar& coeffRef(Index index) const - { - return derived().nestedExpression().coeffRef(index); - } - EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index rowId, Index colId) const { @@ -189,6 +181,20 @@ template class TransposeImpl { derived().nestedExpression().const_cast_derived().template writePacket(index, x); } +#endif + + // FIXME: shall we keep the const version of coeffRef? + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return derived().nestedExpression().coeffRef(colId, rowId); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + return derived().nestedExpression().coeffRef(index); + } }; /** \returns an expression of the transpose of *this. diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 064e0e10d..180efdd62 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -1071,8 +1071,8 @@ struct evaluator_traits > static const int AssumeAliasing = 0; }; -template -struct evaluator, Kind, typename MatrixType::Scalar> +template +struct evaluator > : evaluator::type> { typedef TriangularView XprType; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 1726f98ed..b0a09216d 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -219,8 +219,8 @@ struct gemm_functor cols = m_rhs.cols(); Gemm::run(rows, cols, m_lhs.cols(), - /*(const Scalar*)*/&m_lhs.coeffRef(row,0), m_lhs.outerStride(), - /*(const Scalar*)*/&m_rhs.coeffRef(0,col), m_rhs.outerStride(), + &m_lhs.coeffRef(row,0), m_lhs.outerStride(), + &m_rhs.coeffRef(0,col), m_rhs.outerStride(), (Scalar*)&(m_dest.coeffRef(row,col)), m_dest.outerStride(), m_actualAlpha, m_blocking, info); } diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 092ba758e..ead5de650 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -38,9 +38,7 @@ template struct accessors_level template struct evaluator_traits; -template< typename T, - typename Kind = typename evaluator_traits::Kind, - typename Scalar = typename T::Scalar> struct evaluator; +template< typename T> struct evaluator; } // end namespace internal diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 0be5029c9..5407645c9 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -465,6 +465,15 @@ struct dense_xpr_base typedef ArrayBase type; }; +template::XprKind, typename StorageKind = typename traits::StorageKind> +struct generic_xpr_base; + +template +struct generic_xpr_base +{ + typedef typename dense_xpr_base::type type; +}; + /** \internal Helper base class to add a scalar multiple operator * overloads for complex types */ template Date: Fri, 20 Jun 2014 15:42:13 +0200 Subject: Started to move the SparseCore module to evaluators: implemented assignment and cwise-unary evaluator --- Eigen/SparseCore | 5 +- Eigen/src/SparseCore/SparseAssign.h | 252 ++++++++++++++++++++++++++++++ Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 150 +++++++++++++++++- Eigen/src/SparseCore/SparseMatrix.h | 93 +++++++++++ Eigen/src/SparseCore/SparseMatrixBase.h | 83 +--------- Eigen/src/SparseCore/SparseUtil.h | 6 + 6 files changed, 508 insertions(+), 81 deletions(-) create mode 100644 Eigen/src/SparseCore/SparseAssign.h diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 9b5be5e15..c0f0a4121 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -35,14 +35,16 @@ struct Sparse {}; #include "src/SparseCore/SparseUtil.h" #include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/SparseAssign.h" #include "src/SparseCore/CompressedStorage.h" #include "src/SparseCore/AmbiVector.h" #include "src/SparseCore/SparseMatrix.h" #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" +#include "src/SparseCore/SparseCwiseUnaryOp.h" +#ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseTranspose.h" -#include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparsePermutation.h" @@ -57,6 +59,7 @@ struct Sparse {}; #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/TriangularSolver.h" #include "src/SparseCore/SparseView.h" +#endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h new file mode 100644 index 000000000..99a1a8712 --- /dev/null +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -0,0 +1,252 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEASSIGN_H +#define EIGEN_SPARSEASSIGN_H + +namespace Eigen { + +#ifndef EIGEN_TEST_EVALUATORS + +template +template +Derived& SparseMatrixBase::operator=(const EigenBase &other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +template +template +Derived& SparseMatrixBase::operator=(const ReturnByValue& other) +{ + other.evalTo(derived()); + return derived(); +} + +template +template +inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) +{ + return assign(other.derived()); +} + +template +inline Derived& SparseMatrixBase::operator=(const Derived& other) +{ +// if (other.isRValue()) +// derived().swap(other.const_cast_derived()); +// else + return assign(other.derived()); +} + +template +template +inline Derived& SparseMatrixBase::assign(const OtherDerived& other) +{ + const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); + if ((!transpose) && other.isRValue()) + { + // eval without temporary + derived().resize(other.rows(), other.cols()); + derived().setZero(); + derived().reserve((std::max)(this->rows(),this->cols())*2); + for (Index j=0; j +template +inline void SparseMatrixBase::assignGeneric(const OtherDerived& other) +{ + //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || + (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && + "the transpose operation is supposed to be handled in SparseMatrix::operator="); + + enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; + + const Index outerSize = other.outerSize(); + //typedef typename internal::conditional, Derived>::type TempType; + // thanks to shallow copies, we always eval to a tempary + Derived temp(other.rows(), other.cols()); + + temp.reserve((std::max)(this->rows(),this->cols())*2); + for (Index j=0; j +// inline Derived& operator=(const SparseSparseProduct& product); +// +// template +// Derived& operator+=(const SparseMatrixBase& other); +// template +// Derived& operator-=(const SparseMatrixBase& other); +// +// Derived& operator*=(const Scalar& other); +// Derived& operator/=(const Scalar& other); +// +// template +// Derived& operator*=(const SparseMatrixBase& other); + +#else // EIGEN_TEST_EVALUATORS + +template +template +Derived& SparseMatrixBase::operator=(const EigenBase &other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +template +template +Derived& SparseMatrixBase::operator=(const ReturnByValue& other) +{ + other.evalTo(derived()); + return derived(); +} + +template +template +inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) +{ + internal::call_assignment_no_alias(derived(), other.derived()); + return derived(); +} + +template +inline Derived& SparseMatrixBase::operator=(const Derived& other) +{ + internal::call_assignment_no_alias(derived(), other.derived()); + return derived(); +} + +namespace internal { + +template<> +struct storage_kind_to_evaluator_kind { + typedef IteratorBased Kind; +}; + +template<> +struct storage_kind_to_shape { + typedef SparseShape Shape; +}; + +struct Sparse2Sparse {}; + +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; + + +template +void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) +{ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + typedef typename DstXprType::Index Index; + typedef typename DstXprType::Scalar Scalar; + typedef typename internal::evaluator::type DstEvaluatorType; + typedef typename internal::evaluator::type SrcEvaluatorType; + + DstEvaluatorType dstEvaluator(dst); + SrcEvaluatorType srcEvaluator(src); + + const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit); + const Index outerSize = (int(SrcEvaluatorType::Flags) & RowMajorBit) ? src.rows() : src.cols(); + if ((!transpose) && src.isRValue()) + { + // eval without temporary + dst.resize(src.rows(), src.cols()); + dst.setZero(); + dst.reserve((std::max)(src.rows(),src.cols())*2); + for (Index j=0; j::SupportedAccessPatterns & OuterRandomAccessPattern)==OuterRandomAccessPattern) || + (!((DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit)))) && + "the transpose operation is supposed to be handled in SparseMatrix::operator="); + + enum { Flip = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit) }; + + const Index outerSize = src.outerSize(); + DstXprType temp(src.rows(), src.cols()); + + temp.reserve((std::max)(src.rows(),src.cols())*2); + for (Index j=0; j +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + assign_sparse_to_sparse(dst.derived(), src.derived()); + } +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + +} // end namespace Eigen + +#endif // EIGEN_SPARSEASSIGN_H diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index 5a50c7803..c5042504b 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -11,6 +11,8 @@ #define EIGEN_SPARSE_CWISE_UNARY_OP_H namespace Eigen { + +#ifndef EIGEN_TEST_EVALUATORS template class CwiseUnaryOpImpl @@ -18,12 +20,12 @@ class CwiseUnaryOpImpl { public: - class InnerIterator; - class ReverseInnerIterator; - typedef CwiseUnaryOp Derived; EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) + class InnerIterator; + class ReverseInnerIterator; + protected: typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; @@ -138,6 +140,148 @@ class CwiseUnaryViewImpl::ReverseInnerIterator const ViewOp m_functor; }; +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > +{ + public: + typedef CwiseUnaryOp XprType; + + class InnerIterator; + class ReverseInnerIterator; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} + + protected: + typedef typename evaluator::InnerIterator EvalIterator; + typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; + + const UnaryOp m_functor; + typename evaluator::nestedType m_argImpl; +}; + +template +class unary_evaluator, IteratorBased>::InnerIterator + : public unary_evaluator, IteratorBased>::EvalIterator +{ + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, typename XprType::Index outer) + : Base(unaryOp.m_argImpl,outer), m_functor(unaryOp.m_functor) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { Base::operator++(); return *this; } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } + + protected: + const UnaryOp m_functor; + private: + Scalar& valueRef(); +}; + +template +class unary_evaluator, IteratorBased>::ReverseInnerIterator + : public unary_evaluator, IteratorBased>::EvalReverseIterator +{ + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() + { Base::operator--(); return *this; } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } + + protected: + const UnaryOp m_functor; + private: + Scalar& valueRef(); +}; + + +// template +// class CwiseUnaryViewImpl +// : public SparseMatrixBase > +// { +// public: +// +// class InnerIterator; +// class ReverseInnerIterator; +// +// typedef CwiseUnaryView Derived; +// EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) +// +// protected: +// typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; +// typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; +// typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; +// }; +// +// template +// class CwiseUnaryViewImpl::InnerIterator +// : public CwiseUnaryViewImpl::MatrixTypeIterator +// { +// typedef typename CwiseUnaryViewImpl::Scalar Scalar; +// typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; +// public: +// +// EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) +// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) +// {} +// +// EIGEN_STRONG_INLINE InnerIterator& operator++() +// { Base::operator++(); return *this; } +// +// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } +// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } +// +// protected: +// const ViewOp m_functor; +// }; +// +// template +// class CwiseUnaryViewImpl::ReverseInnerIterator +// : public CwiseUnaryViewImpl::MatrixTypeReverseIterator +// { +// typedef typename CwiseUnaryViewImpl::Scalar Scalar; +// typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; +// public: +// +// EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) +// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) +// {} +// +// EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() +// { Base::operator--(); return *this; } +// +// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } +// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } +// +// protected: +// const ViewOp m_functor; +// }; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + template EIGEN_STRONG_INLINE Derived& SparseMatrixBase::operator*=(const Scalar& other) diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 9ac18bcf6..a25bd83eb 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -1053,6 +1053,7 @@ void SparseMatrix::sumupDuplicates() m_data.resize(m_outerIndex[m_outerSize]); } +#ifndef EIGEN_TEST_EVALUATORS template template EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) @@ -1114,6 +1115,71 @@ EIGEN_DONT_INLINE SparseMatrix& SparseMatrix +template +EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) +{ + EIGEN_STATIC_ASSERT((internal::is_same::value), + YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + if (needToTranspose) + { + // two passes algorithm: + // 1 - compute the number of coeffs per dest inner vector + // 2 - do the actual copy/eval + // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed + typedef typename internal::nested_eval::type OtherCopy; + typedef typename internal::remove_all::type _OtherCopy; + typedef internal::evaluator<_OtherCopy> OtherCopyEval; + OtherCopy otherCopy(other.derived()); + OtherCopyEval otherCopyEval(otherCopy); + + SparseMatrix dest(other.rows(),other.cols()); + Eigen::Map > (dest.m_outerIndex,dest.outerSize()).setZero(); + + // pass 1 + // FIXME the above copy could be merged with that pass + for (Index j=0; j positions(dest.outerSize()); + for (Index j=0; jswap(dest); + return *this; + } + else + { + if(other.isRValue()) + initAssignment(other.derived()); + // there is no special optimization + return Base::operator=(other.derived()); + } +} +#endif template EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col) @@ -1254,6 +1320,33 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse return (m_data.value(p) = 0); } +#ifdef EIGEN_ENABLE_EVALUATORS +namespace internal { + +template +struct evaluator > + : evaluator_base > +{ + typedef SparseMatrix<_Scalar,_Options,_Index> SparseMatrixType; + typedef typename SparseMatrixType::InnerIterator InnerIterator; + typedef typename SparseMatrixType::ReverseInnerIterator ReverseInnerIterator; + + enum { + CoeffReadCost = NumTraits<_Scalar>::ReadCost, + Flags = SparseMatrixType::Flags + }; + + evaluator(const SparseMatrixType &mat) : m_matrix(mat) {} + + operator SparseMatrixType&() { return m_matrix.const_cast_derived(); } + operator const SparseMatrixType&() const { return m_matrix; } + + const SparseMatrixType &m_matrix; +}; + +} +#endif + } // end namespace Eigen #endif // EIGEN_SPARSEMATRIX_H diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index bbcf7fb1c..a87407fe9 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -39,11 +39,7 @@ template class SparseMatrixBase : public EigenBase typedef EigenBase Base; template - Derived& operator=(const EigenBase &other) - { - other.derived().evalTo(derived()); - return derived(); - } + Derived& operator=(const EigenBase &other); enum { @@ -175,87 +171,20 @@ template class SparseMatrixBase : public EigenBase template - Derived& operator=(const ReturnByValue& other) - { - other.evalTo(derived()); - return derived(); - } - + Derived& operator=(const ReturnByValue& other); template - inline Derived& operator=(const SparseMatrixBase& other) - { - return assign(other.derived()); - } + inline Derived& operator=(const SparseMatrixBase& other); - inline Derived& operator=(const Derived& other) - { -// if (other.isRValue()) -// derived().swap(other.const_cast_derived()); -// else - return assign(other.derived()); - } + inline Derived& operator=(const Derived& other); protected: template - inline Derived& assign(const OtherDerived& other) - { - const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? other.rows() : other.cols(); - if ((!transpose) && other.isRValue()) - { - // eval without temporary - derived().resize(other.rows(), other.cols()); - derived().setZero(); - derived().reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j - inline void assignGeneric(const OtherDerived& other) - { - //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || - (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && - "the transpose operation is supposed to be handled in SparseMatrix::operator="); - - enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; - - const Index outerSize = other.outerSize(); - //typedef typename internal::conditional, Derived>::type TempType; - // thanks to shallow copies, we always eval to a tempary - Derived temp(other.rows(), other.cols()); - - temp.reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j struct plain_matrix_type typedef SparseMatrix<_Scalar, _Options, _Index> type; }; +template +struct generic_xpr_base +{ + typedef SparseMatrixBase type; +}; + } // end namespace internal /** \ingroup SparseCore_Module -- cgit v1.2.3 From 7fa87a8b12fbc6a3e8af91fc773ba054e59a5ae5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 20 Jun 2014 16:17:57 +0200 Subject: Backport changes from old to new expression engines --- Eigen/src/Core/CoreEvaluators.h | 9 +++--- Eigen/src/Core/products/GeneralMatrixMatrix.h | 34 +++++++++++++++++++++- .../Core/products/GeneralMatrixMatrixTriangular.h | 2 ++ Eigen/src/Core/util/XprHelper.h | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 95ea72680..5c4da9978 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -658,7 +658,7 @@ struct evaluator > && ( bool(IsDynamicSize) || HasNoOuterStride || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), + && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%EIGEN_ALIGN_BYTES)==0 ) ), Flags0 = evaluator::Flags, Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) @@ -723,8 +723,9 @@ struct evaluator > MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) && (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + + MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) ? AlignedBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, FlagsRowMajorBit = XprType::Flags&RowMajorBit, Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | DirectAccessBit | @@ -825,7 +826,7 @@ struct block_evaluator(block) { // FIXME this should be an internal assertion - eigen_assert(EIGEN_IMPLIES(evaluator::Flags&AlignedBit, (size_t(block.data()) % 16) == 0) && "data is not aligned"); + eigen_assert(EIGEN_IMPLIES(evaluator::Flags&AlignedBit, (size_t(block.data()) % EIGEN_ALIGN_BYTES) == 0) && "data is not aligned"); } }; diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 5fd9a98ac..66a4fe536 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -471,6 +471,38 @@ struct generic_product_impl MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) }; + typedef generic_product_impl lazyproduct; + + template + static void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::evalTo(dst, lhs, rhs); + else + { + dst.setZero(); + scaleAndAddTo(dst, lhs, rhs, Scalar(1)); + } + } + + template + static void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::addTo(dst, lhs, rhs); + else + scaleAndAddTo(dst,lhs, rhs, Scalar(1)); + } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + if((rhs.rows()+dst.rows()+dst.cols())<20 && rhs.rows()>0) + lazyproduct::subTo(dst, lhs, rhs); + else + scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); + } + template static void scaleAndAddTo(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha) { @@ -494,7 +526,7 @@ struct generic_product_impl (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, ActualLhsTypeCleaned, ActualRhsTypeCleaned, Dest, BlockingType> GemmFunctor; - BlockingType blocking(dst.rows(), dst.cols(), lhs.cols()); + BlockingType blocking(dst.rows(), dst.cols(), lhs.cols(), true); internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)> (GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), a_lhs.rows(), a_rhs.cols(), Dest::Flags&RowMajorBit); diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 6070664d5..b28f07bdc 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -266,6 +266,8 @@ template template TriangularView& TriangularView::_assignProduct(const ProductType& prod, const Scalar& alpha) { + eigen_assert(m_matrix.rows() == prod.rows() && m_matrix.cols() == prod.cols()); + general_product_to_triangular_selector::InnerSize==1>::run(m_matrix.const_cast_derived(), prod, alpha); return *this; diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 14adb6795..5c4b9dbcd 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -187,7 +187,7 @@ class compute_matrix_evaluator_flags ((Options&DontAlign)==0) && ( #if EIGEN_ALIGN_STATICALLY - ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % 16) == 0)) + ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) #else 0 #endif -- cgit v1.2.3 From ec0a8b2e6dab9af4b4fc6c91d2ab7b01e47ea5ce Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 20 Jun 2014 16:30:34 +0200 Subject: rm conflict --- test/vectorization_logic.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp index 1fb079c48..5c6e8042d 100644 --- a/test/vectorization_logic.cpp +++ b/test/vectorization_logic.cpp @@ -232,12 +232,8 @@ template::Vectori Matrix >(DefaultTraversal,CompleteUnrolling))); -<<<<<<< local - VERIFY((test_assign(Matrix11(), Matrix11().lazyProduct(Matrix11()), InnerVectorizedTraversal, CompleteUnrolling))); -======= VERIFY((test_assign(Matrix11(), Matrix()*Matrix(), PacketSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD?DefaultTraversal:InnerVectorizedTraversal, CompleteUnrolling))); ->>>>>>> other #endif VERIFY(test_assign(MatrixXX(10,10),MatrixXX(20,20).block(10,10,2,3), -- cgit v1.2.3 From 3849cc65ee2192ddd9d63cdc2e65cb74128bcbb3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 23 Jun 2014 10:40:03 +0200 Subject: Implement binaryop and transpose evaluators for sparse matrices --- Eigen/SparseCore | 4 +- Eigen/src/Core/AssignEvaluator.h | 10 +- Eigen/src/Core/CoreEvaluators.h | 6 +- Eigen/src/Core/CwiseBinaryOp.h | 2 +- Eigen/src/Core/CwiseUnaryOp.h | 6 +- Eigen/src/Core/Transpose.h | 13 +- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 312 ++++++++++++++++++++++++++++- Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 2 +- Eigen/src/SparseCore/SparseMatrix.h | 2 +- Eigen/src/SparseCore/SparseMatrixBase.h | 4 +- Eigen/src/SparseCore/SparseTranspose.h | 54 ++++- 11 files changed, 396 insertions(+), 19 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index c0f0a4121..799cb1ba1 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -42,10 +42,10 @@ struct Sparse {}; #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" #include "src/SparseCore/SparseCwiseUnaryOp.h" +#include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseTranspose.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparseBlock.h" -#include "src/SparseCore/SparseTranspose.h" -#include "src/SparseCore/SparseCwiseBinaryOp.h" #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index a083e340e..77b4dd9bc 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2011 Benoit Jacob -// Copyright (C) 2011-2013 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2011-2012 Jitse Niesen // // This Source Code Form is subject to the terms of the Mozilla @@ -738,8 +738,10 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) && int(Dst::SizeAtCompileTime) != 1 }; - dst.resize(NeedToTranspose ? src.cols() : src.rows(), - NeedToTranspose ? src.rows() : src.cols()); + typename Dst::Index dstRows = NeedToTranspose ? src.cols() : src.rows(); + typename Dst::Index dstCols = NeedToTranspose ? src.rows() : src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; typedef typename internal::conditional, Dst&>::type ActualDstType; @@ -749,7 +751,7 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) EIGEN_STATIC_ASSERT_LVALUE(Dst) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); - + Assignment::run(actualDst, src, func); } template diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 5c4da9978..b56c3c635 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2011 Benoit Jacob -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2011-2012 Jitse Niesen // // This Source Code Form is subject to the terms of the Mozilla @@ -253,7 +253,7 @@ struct evaluator > // -------------------- Transpose -------------------- template -struct unary_evaluator > +struct unary_evaluator, IndexBased> : evaluator_base > { typedef Transpose XprType; @@ -440,7 +440,7 @@ struct evaluator > }; template -struct binary_evaluator > +struct binary_evaluator, IndexBased, IndexBased> : evaluator_base > { typedef CwiseBinaryOp XprType; diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 5e4fb147b..355f3bdc8 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.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-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index 098034a1e..c2bc47c93 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-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -135,7 +135,7 @@ class CwiseUnaryOpImpl return derived().functor().packetOp(derived().nestedExpression().template packet(index)); } }; -#else +#else // EIGEN_TEST_EVALUATORS // Generic API dispatcher template class CwiseUnaryOpImpl @@ -144,7 +144,7 @@ class CwiseUnaryOpImpl public: typedef typename internal::generic_xpr_base >::type Base; }; -#endif +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 4b605dfd6..f5148221d 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2009-2010 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -108,6 +108,17 @@ struct TransposeImpl_base } // end namespace internal +#ifdef EIGEN_TEST_EVALUATORS +// Generic API dispatcher +template +class TransposeImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; +#endif + template class TransposeImpl : public internal::TransposeImpl_base::type { diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index ec86ca933..f43976641 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.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) 2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -44,6 +44,8 @@ class sparse_cwise_binary_op_inner_iterator_selector; } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS + template class CwiseBinaryOpImpl : public SparseMatrixBase > @@ -291,6 +293,314 @@ class sparse_cwise_binary_op_inner_iterator_selector, Lhs, } // end namespace internal +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + + +// Generic "sparse OP sparse" +template +struct binary_evaluator, IteratorBased, IteratorBased> + : evaluator_base > +{ +protected: + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::InnerIterator RhsIterator; +public: + typedef CwiseBinaryOp XprType; + + class ReverseInnerIterator; + class InnerIterator + { + typedef typename traits::Scalar Scalar; + typedef typename XprType::Index Index; + + public: + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor) + { + this->operator++(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) + { + m_id = m_lhsIter.index(); + m_value = m_functor(m_lhsIter.value(), m_rhsIter.value()); + ++m_lhsIter; + ++m_rhsIter; + } + else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) + { + m_id = m_lhsIter.index(); + m_value = m_functor(m_lhsIter.value(), Scalar(0)); + ++m_lhsIter; + } + else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) + { + m_id = m_rhsIter.index(); + m_value = m_functor(Scalar(0), m_rhsIter.value()); + ++m_rhsIter; + } + else + { + m_value = 0; // this is to avoid a compilation warning + m_id = -1; + } + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const { return m_value; } + + EIGEN_STRONG_INLINE Index index() const { return m_id; } + EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } + EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; } + + protected: + LhsIterator m_lhsIter; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; + Scalar m_value; + Index m_id; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { } + +protected: + const BinaryOp m_functor; + typename evaluator::nestedType m_lhsImpl; + typename evaluator::nestedType m_rhsImpl; +}; + +// "sparse .* sparse" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IteratorBased> + : evaluator_base, Lhs, Rhs> > +{ +protected: + typedef scalar_product_op BinaryOp; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::InnerIterator RhsIterator; +public: + typedef CwiseBinaryOp XprType; + + class ReverseInnerIterator; + class InnerIterator + { + typedef typename traits::Scalar Scalar; + typedef typename XprType::Index Index; + + public: + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor) + { + while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) + { + if (m_lhsIter.index() < m_rhsIter.index()) + ++m_lhsIter; + else + ++m_rhsIter; + } + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + ++m_lhsIter; + ++m_rhsIter; + while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) + { + if (m_lhsIter.index() < m_rhsIter.index()) + ++m_lhsIter; + else + ++m_rhsIter; + } + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } + + EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return (m_lhsIter && m_rhsIter); } + + protected: + LhsIterator m_lhsIter; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { } + +protected: + const BinaryOp m_functor; + typename evaluator::nestedType m_lhsImpl; + typename evaluator::nestedType m_rhsImpl; +}; + +// "dense .* sparse" +template +struct binary_evaluator, Lhs, Rhs>, IndexBased, IteratorBased> + : evaluator_base, Lhs, Rhs> > +{ +protected: + typedef scalar_product_op BinaryOp; + typedef typename evaluator::type LhsEvaluator; + typedef typename evaluator::InnerIterator RhsIterator; +public: + typedef CwiseBinaryOp XprType; + + class ReverseInnerIterator; + class InnerIterator + { + typedef typename traits::Scalar Scalar; + typedef typename XprType::Index Index; + enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; + + public: + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsEval(aEval.m_lhsImpl), m_rhsIter(aEval.m_rhsImpl,outer), m_functor(aEval.m_functor), m_outer(outer) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + ++m_rhsIter; + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const + { return m_functor(m_lhsEval.coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } + + EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } + + protected: + const LhsEvaluator &m_lhsEval; + RhsIterator m_rhsIter; + const BinaryOp& m_functor; + const Index m_outer; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { } + +protected: + const BinaryOp m_functor; + typename evaluator::nestedType m_lhsImpl; + typename evaluator::nestedType m_rhsImpl; +}; + +// "sparse .* dense" +template +struct binary_evaluator, Lhs, Rhs>, IteratorBased, IndexBased> + : evaluator_base, Lhs, Rhs> > +{ +protected: + typedef scalar_product_op BinaryOp; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::type RhsEvaluator; +public: + typedef CwiseBinaryOp XprType; + + class ReverseInnerIterator; + class InnerIterator + { + typedef typename traits::Scalar Scalar; + typedef typename XprType::Index Index; + enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; + + public: + + EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer) + : m_lhsIter(aEval.m_lhsImpl,outer), m_rhsEval(aEval.m_rhsImpl), m_functor(aEval.m_functor), m_outer(outer) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + ++m_lhsIter; + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const + { return m_functor(m_lhsIter.value(), + m_rhsEval.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } + + EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } + EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } + EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } + + EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } + + protected: + LhsIterator m_lhsIter; + const RhsEvaluator &m_rhsEval; + const BinaryOp& m_functor; + const Index m_outer; + }; + + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { } + +protected: + const BinaryOp m_functor; + typename evaluator::nestedType m_lhsImpl; + typename evaluator::nestedType m_rhsImpl; +}; + +} + +#endif + + + /*************************************************************************** * Implementation of SparseMatrixBase and SparseCwise functions/operators ***************************************************************************/ diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index c5042504b..ead3af59d 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index aa8bfc0f5..8aa0ed7e6 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index a87407fe9..e4960a445 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -79,10 +79,12 @@ template class SparseMatrixBase : public EigenBase * constructed from this one. See the \ref flags "list of flags". */ +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = internal::traits::CoeffReadCost, /**< This is a rough measure of how expensive it is to read one coefficient from * this expression. */ +#endif IsRowMajor = Flags&RowMajorBit ? 1 : 0, diff --git a/Eigen/src/SparseCore/SparseTranspose.h b/Eigen/src/SparseCore/SparseTranspose.h index 7c300ee8d..b20843dd3 100644 --- a/Eigen/src/SparseCore/SparseTranspose.h +++ b/Eigen/src/SparseCore/SparseTranspose.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,6 +12,7 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS template class TransposeImpl : public SparseMatrixBase > { @@ -58,6 +59,57 @@ template class TransposeImpl::ReverseInn Index col() const { return Base::row(); } }; +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > +{ + typedef typename evaluator::InnerIterator EvalIterator; + typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; + public: + typedef Transpose XprType; + typedef typename XprType::Index Index; + + class InnerIterator : public EvalIterator + { + public: + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, typename XprType::Index outer) + : EvalIterator(unaryOp.m_argImpl,outer) + {} + + Index row() const { return EvalIterator::col(); } + Index col() const { return EvalIterator::row(); } + }; + + class ReverseInnerIterator : public EvalReverseIterator + { + public: + EIGEN_STRONG_INLINE ReverseInnerIterator(const unary_evaluator& unaryOp, typename XprType::Index outer) + : EvalReverseIterator(unaryOp.m_argImpl,outer) + {} + + Index row() const { return EvalReverseIterator::col(); } + Index col() const { return EvalReverseIterator::row(); } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType& op) :m_argImpl(op.nestedExpression()) {} + + protected: + typename evaluator::nestedType m_argImpl; +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_SPARSETRANSPOSE_H -- cgit v1.2.3 From 17f119689e8b0060c41ca6ab0d291bd7d09fe5ce Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 09:58:03 +0200 Subject: implement evaluator for SparseVector --- Eigen/src/SparseCore/SparseVector.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index 7e15c814b..cd22dfd49 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.h @@ -410,6 +410,7 @@ class SparseVector::ReverseInnerIterator namespace internal { +#ifndef EIGEN_TEST_EVALUATORS template< typename Dest, typename Src> struct sparse_vector_assign_selector { static void run(Dest& dst, const Src& src) { @@ -431,6 +432,33 @@ struct sparse_vector_assign_selector { } } }; +#else // EIGEN_TEST_EVALUATORS +template< typename Dest, typename Src> +struct sparse_vector_assign_selector { + static void run(Dest& dst, const Src& src) { + eigen_internal_assert(src.innerSize()==src.size()); + typedef typename internal::evaluator::type SrcEvaluatorType; + SrcEvaluatorType srcEval(src); + for(typename SrcEvaluatorType::InnerIterator it(srcEval, 0); it; ++it) + dst.insert(it.index()) = it.value(); + } +}; + +template< typename Dest, typename Src> +struct sparse_vector_assign_selector { + static void run(Dest& dst, const Src& src) { + eigen_internal_assert(src.outerSize()==src.size()); + typedef typename internal::evaluator::type SrcEvaluatorType; + SrcEvaluatorType srcEval(src); + for(typename Dest::Index i=0; i struct sparse_vector_assign_selector { -- cgit v1.2.3 From e3ba5329ff369401da836ac5e4a86cd059a51a69 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 09:58:26 +0200 Subject: Implement evaluators for sparse Block. --- Eigen/SparseCore | 2 +- Eigen/src/Core/Block.h | 2 + Eigen/src/Core/CoreEvaluators.h | 14 +++- Eigen/src/SparseCore/SparseAssign.h | 1 - Eigen/src/SparseCore/SparseBlock.h | 163 +++++++++++++++++++++++++++++++++++- 5 files changed, 175 insertions(+), 7 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 799cb1ba1..4ad6f47a0 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -44,8 +44,8 @@ struct Sparse {}; #include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" #include "src/SparseCore/SparseTranspose.h" -#ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparseBlock.h" +#ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 70e457028..0f3ab304a 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -122,6 +122,8 @@ template class typedef Impl Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + typedef typename internal::remove_all::type NestedExpression; /** Column or Row constructor */ diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index b56c3c635..81b4d63bf 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -737,13 +737,25 @@ struct evaluator > evaluator(const XprType& block) : block_evaluator_type(block) {} }; +// no direct-access => dispatch to a unary evaluator template struct block_evaluator - : evaluator_base > + : unary_evaluator > { typedef Block XprType; block_evaluator(const XprType& block) + : unary_evaluator(block) + {} +}; + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Block XprType; + + unary_evaluator(const XprType& block) : m_argImpl(block.nestedExpression()), m_startRow(block.startRow()), m_startCol(block.startCol()) diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 99a1a8712..d4434e0ae 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -181,7 +181,6 @@ void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) typedef typename internal::evaluator::type DstEvaluatorType; typedef typename internal::evaluator::type SrcEvaluatorType; - DstEvaluatorType dstEvaluator(dst); SrcEvaluatorType srcEvaluator(src); const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit); diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h index 5b95cc33f..4926f6923 100644 --- a/Eigen/src/SparseCore/SparseBlock.h +++ b/Eigen/src/SparseCore/SparseBlock.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,6 +12,7 @@ namespace Eigen { +// Subset of columns or rows template class BlockImpl : public SparseMatrixBase > @@ -25,6 +26,7 @@ protected: public: EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) +#ifndef EIGEN_TEST_EVALUATORS class InnerIterator: public XprType::InnerIterator { typedef typename BlockImpl::Index Index; @@ -49,6 +51,7 @@ public: protected: Index m_outer; }; +#endif // EIGEN_TEST_EVALUATORS inline BlockImpl(const XprType& xpr, int i) : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) @@ -63,13 +66,30 @@ public: Index nonZeros() const { - Index nnz = 0; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename internal::evaluator::type EvaluatorType; Index end = m_outerStart + m_outerSize.value(); for(int j=m_outerStart; j::type EvaluatorType; + EvaluatorType matEval(m_matrix); + Index nnz = 0; + Index end = m_outerStart + m_outerSize.value(); + for(int j=m_outerStart; j InnerIterator; class ReverseInnerIterator : public _MatrixTypeNested::ReverseInnerIterator @@ -431,6 +458,14 @@ public: inline operator bool() const { return Base::operator bool() && Base::index() >= m_begin; } }; +#endif // EIGEN_TEST_EVALUATORS + + inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } + Index startRow() const { return m_startRow.value(); } + Index startCol() const { return m_startCol.value(); } + Index blockRows() const { return m_blockRows.value(); } + Index blockCols() const { return m_blockCols.value(); } + protected: friend class internal::GenericSparseBlockInnerIteratorImpl; friend class ReverseInnerIterator; @@ -535,7 +570,127 @@ namespace internal { inline operator bool() const { return m_outerPos < m_end; } }; + +#ifdef EIGEN_TEST_EVALUATORS + +// +template +struct unary_evaluator, IteratorBased > + : public evaluator_base > +{ + class InnerVectorInnerIterator; + class OuterVectorInnerIterator; + public: + typedef Block XprType; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + + class ReverseInnerIterator; + + enum { + IsRowMajor = XprType::IsRowMajor, + + OuterVector = (BlockCols==1 && ArgType::IsRowMajor) + | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". + // revert to || as soon as not needed anymore. + (BlockRows==1 && !ArgType::IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + typedef typename internal::conditional::type InnerIterator; + + unary_evaluator(const XprType& op) + : m_argImpl(op.nestedExpression()), m_block(op) + {} + + protected: + typedef typename evaluator::InnerIterator EvalIterator; + typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; + + typename evaluator::nestedType m_argImpl; + const XprType &m_block; +}; + +template +class unary_evaluator, IteratorBased>::InnerVectorInnerIterator + : public EvalIterator +{ + const XprType& m_block; + Index m_end; +public: + + EIGEN_STRONG_INLINE InnerVectorInnerIterator(const unary_evaluator& aEval, Index outer) + : EvalIterator(aEval.m_argImpl, outer + (IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol())), + m_block(aEval.m_block), + m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()) + { + while( (EvalIterator::operator bool()) && (EvalIterator::index() < (IsRowMajor ? m_block.startCol() : m_block.startRow())) ) + EvalIterator::operator++(); + } + inline Index index() const { return EvalIterator::index() - (IsRowMajor ? m_block.startCol() : m_block.startRow()); } + inline Index outer() const { return EvalIterator::outer() - (IsRowMajor ? m_block.startRow() : m_block.startCol()); } + inline Index row() const { return EvalIterator::row() - m_block.startRow(); } + inline Index col() const { return EvalIterator::col() - m_block.startCol(); } + + inline operator bool() const { return EvalIterator::operator bool() && EvalIterator::index() < m_end; } +}; + +template +class unary_evaluator, IteratorBased>::OuterVectorInnerIterator +{ + const XprType& m_block; + Index m_outerPos; + Index m_innerIndex; + Scalar m_value; + Index m_end; +public: + + EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer) + : m_block(aEval.m_block), + m_outerPos( (IsRowMajor ? aEval.startCol() : aEval.startRow()) - 1), // -1 so that operator++ finds the first non-zero entry + m_innerIndex(IsRowMajor ? aEval.startRow() : aEval.startCol()), + m_end(IsRowMajor ? aEval.startCol()+aEval.blockCols() : aEval.startRow()+aEval.blockRows()) + { + EIGEN_UNUSED_VARIABLE(outer); + eigen_assert(outer==0); + + ++(*this); + } + + inline Index index() const { return m_outerPos - (IsRowMajor ? m_block.startCol() : m_block.startRow()); } + inline Index outer() const { return 0; } + inline Index row() const { return IsRowMajor ? 0 : index(); } + inline Index col() const { return IsRowMajor ? index() : 0; } + + inline Scalar value() const { return m_value; } + + inline OuterVectorInnerIterator& operator++() + { + // search next non-zero entry + while(m_outerPos Date: Wed, 25 Jun 2014 17:21:04 +0200 Subject: Implement evaluators for sparse coeff-wise views --- Eigen/src/Core/CwiseUnaryView.h | 11 +++ Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 133 ++++++++++++++++-------------- 2 files changed, 83 insertions(+), 61 deletions(-) diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 92b031e19..99cc03ac1 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -93,6 +93,17 @@ class CwiseUnaryView : public CwiseUnaryViewImpl +class CwiseUnaryViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; +#endif + template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index ead3af59d..7a849c822 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -216,67 +216,78 @@ class unary_evaluator, IteratorBased>::ReverseInne }; -// template -// class CwiseUnaryViewImpl -// : public SparseMatrixBase > -// { -// public: -// -// class InnerIterator; -// class ReverseInnerIterator; -// -// typedef CwiseUnaryView Derived; -// EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) -// -// protected: -// typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; -// typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; -// typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; -// }; -// -// template -// class CwiseUnaryViewImpl::InnerIterator -// : public CwiseUnaryViewImpl::MatrixTypeIterator -// { -// typedef typename CwiseUnaryViewImpl::Scalar Scalar; -// typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; -// public: -// -// EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) -// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) -// {} -// -// EIGEN_STRONG_INLINE InnerIterator& operator++() -// { Base::operator++(); return *this; } -// -// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } -// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } -// -// protected: -// const ViewOp m_functor; -// }; -// -// template -// class CwiseUnaryViewImpl::ReverseInnerIterator -// : public CwiseUnaryViewImpl::MatrixTypeReverseIterator -// { -// typedef typename CwiseUnaryViewImpl::Scalar Scalar; -// typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; -// public: -// -// EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) -// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) -// {} -// -// EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() -// { Base::operator--(); return *this; } -// -// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } -// EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } -// -// protected: -// const ViewOp m_functor; -// }; + + + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > +{ + public: + typedef CwiseUnaryView XprType; + + class InnerIterator; + class ReverseInnerIterator; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} + + protected: + typedef typename evaluator::InnerIterator EvalIterator; + typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; + + const ViewOp m_functor; + typename evaluator::nestedType m_argImpl; +}; + +template +class unary_evaluator, IteratorBased>::InnerIterator + : public unary_evaluator, IteratorBased>::EvalIterator +{ + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& unaryOp, typename XprType::Index outer) + : Base(unaryOp.m_argImpl,outer), m_functor(unaryOp.m_functor) + {} + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { Base::operator++(); return *this; } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(Base::valueRef()); } + + protected: + const ViewOp m_functor; +}; + +template +class unary_evaluator, IteratorBased>::ReverseInnerIterator + : public unary_evaluator, IteratorBased>::EvalReverseIterator +{ + typedef typename XprType::Scalar Scalar; + typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; + public: + + EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) + : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) + {} + + EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() + { Base::operator--(); return *this; } + + EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } + EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(Base::valueRef()); } + + protected: + const ViewOp m_functor; +}; + } // end namespace internal -- cgit v1.2.3 From 3b19b466a7609fd381db2c53569d4d1d1621dbfc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 17:22:12 +0200 Subject: Generalize static assertions on matching sizes to avoid the need for SizeAtCompileTime --- Eigen/src/Core/util/StaticAssert.h | 2 +- Eigen/src/Core/util/XprHelper.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index f5691826e..eff12486d 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -159,7 +159,7 @@ #define EIGEN_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \ ( \ - (int(TYPE0::SizeAtCompileTime)==0 && int(TYPE1::SizeAtCompileTime)==0) \ + (int(internal::size_of_xpr_at_compile_time::ret)==0 && int(internal::size_of_xpr_at_compile_time::ret)==0) \ || (\ (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \ || int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \ diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 5c4b9dbcd..19adbefd7 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -216,6 +216,11 @@ template struct size_at_compile_time enum { ret = (_Rows==Dynamic || _Cols==Dynamic) ? Dynamic : _Rows * _Cols }; }; +template struct size_of_xpr_at_compile_time +{ + enum { ret = size_at_compile_time::RowsAtCompileTime,traits::ColsAtCompileTime>::ret }; +}; + /* plain_matrix_type : the difference from eval is that plain_matrix_type is always a plain matrix type, * whereas eval is a const reference in the case of a matrix */ -- cgit v1.2.3 From b868bfb84a4a86231bb338e9bcf08afd882d32dc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 17:23:52 +0200 Subject: Make operator=(EigenBase<>) uses the new assignment mechanism and introduce a generic EigenBase to EigenBase assignment kind based on the previous evalTo mechanism. --- Eigen/src/Core/Assign.h | 2 +- Eigen/src/Core/AssignEvaluator.h | 21 ++++++++++++++++++++- Eigen/src/Core/BandMatrix.h | 23 +++++++++++++++++++++++ Eigen/src/Core/CoreEvaluators.h | 7 ++----- Eigen/src/Core/DiagonalMatrix.h | 21 +++++++++++++++++++++ Eigen/src/Core/PermutationMatrix.h | 2 ++ Eigen/src/Householder/HouseholderSequence.h | 12 ++++++++++++ Eigen/src/SparseCore/SparseAssign.h | 20 ++++++++++++++++++++ Eigen/src/SparseCore/SparseBlock.h | 16 ++++++++-------- Eigen/src/SparseCore/SparseMatrixBase.h | 2 ++ 10 files changed, 111 insertions(+), 15 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index abbba84c3..071cfbf7e 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -611,7 +611,7 @@ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { - other.derived().evalTo(derived()); + internal::call_assignment(derived(), other.derived()); return derived(); } diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 77b4dd9bc..c45ac96f2 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -663,7 +663,9 @@ template struct AssignmentKind; // Assignement kind defined in this file: struct Dense2Dense {}; +struct EigenBase2EigenBase {}; +template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; template<> struct AssignmentKind { typedef Dense2Dense Kind; }; // This is the main assignment class @@ -750,8 +752,12 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) // TODO check whether this is the right place to perform these checks: EIGEN_STATIC_ASSERT_LVALUE(Dst) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) - EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + // TODO this line is commented to allow matrix = permutation + // Actually, the "Scalar" type for a permutation matrix does not really make sense, + // perhaps it could be void, and EIGEN_CHECK_BINARY_COMPATIBILIY could allow micing void with anything...? +// EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + Assignment::run(actualDst, src, func); } template @@ -772,6 +778,19 @@ struct Assignment } }; +// Generic assignment through evalTo. +// TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + + src.evalTo(dst); + } +}; + } // namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index ffd7fe8b3..ba4749707 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -327,6 +327,29 @@ class TridiagonalMatrix : public BandMatrix +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; +#endif + + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 81b4d63bf..f9f229b09 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -32,10 +32,7 @@ struct storage_kind_to_evaluator_kind { template struct storage_kind_to_shape; -template<> -struct storage_kind_to_shape { - typedef DenseShape Shape; -}; +template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; // Evaluators have to be specialized with respect to various criteria such as: // - storage/structure/shape @@ -507,7 +504,7 @@ protected: // -------------------- CwiseUnaryView -------------------- template -struct unary_evaluator > +struct unary_evaluator, IndexBased> : evaluator_base > { typedef CwiseUnaryView XprType; diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index ba0042ba4..fc9ecf561 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -44,6 +44,8 @@ class DiagonalBase : public EigenBase EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } + +#ifndef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC void evalTo(MatrixBase &other) const; @@ -55,6 +57,7 @@ class DiagonalBase : public EigenBase EIGEN_DEVICE_FUNC void subTo(MatrixBase &other) const { other.diagonal() -= diagonal(); } +#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } @@ -122,6 +125,7 @@ class DiagonalBase : public EigenBase #endif }; +#ifndef EIGEN_TEST_EVALUATORS template template void DiagonalBase::evalTo(MatrixBase &other) const @@ -129,6 +133,8 @@ void DiagonalBase::evalTo(MatrixBase &other) const other.setZero(); other.diagonal() = diagonal(); } +#endif // EIGEN_TEST_EVALUATORS + #endif /** \class DiagonalMatrix @@ -376,6 +382,21 @@ struct evaluator_traits > static const int AssumeAliasing = 0; }; +struct Diagonal2Dense {}; + +template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; + +// Diagonal matrix to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + dst.setZero(); + dst.diagonal() = src.diagonal(); + } +}; + } // namespace internal #endif // EIGEN_ENABLE_EVALUATORS diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 61aa0ce31..4399e1d64 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -803,6 +803,8 @@ struct evaluator_traits > > static const int AssumeAliasing = 0; }; +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + } // end namespace internal #endif // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index d800ca1fa..99d3eb21f 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -73,6 +73,18 @@ struct traits > }; }; +#ifdef EIGEN_TEST_EVALUATORS + +struct HouseholderSequenceShape {}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef HouseholderSequenceShape Shape; +}; +#endif + template struct hseq_side_dependent_impl { diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index d4434e0ae..86a0b08c5 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -167,8 +167,10 @@ struct storage_kind_to_shape { }; struct Sparse2Sparse {}; +struct Sparse2Dense {}; template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; template @@ -242,6 +244,24 @@ struct Assignment } }; +// Sparse to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + typedef typename SrcXprType::Index Index; + + dst.setZero(); + typename internal::evaluator::type srcEval(src); + typename internal::evaluator::type dstEval(dst); + for (Index j=0; j::InnerIterator i(srcEval,j); i; ++i) + dstEval.coeffRef(i.row(),i.col()) = i.value(); + } +}; + } // end namespace internal #endif // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h index 4926f6923..f562b5479 100644 --- a/Eigen/src/SparseCore/SparseBlock.h +++ b/Eigen/src/SparseCore/SparseBlock.h @@ -67,7 +67,7 @@ public: Index nonZeros() const { #ifndef EIGEN_TEST_EVALUATORS - typedef typename internal::evaluator::type EvaluatorType; + Index nnz = 0; Index end = m_outerStart + m_outerSize.value(); for(int j=m_outerStart; j class unary_evaluator, IteratorBased>::OuterVectorInnerIterator { - const XprType& m_block; + const unary_evaluator& m_eval; Index m_outerPos; Index m_innerIndex; Scalar m_value; @@ -649,10 +649,10 @@ class unary_evaluator, IteratorBas public: EIGEN_STRONG_INLINE OuterVectorInnerIterator(const unary_evaluator& aEval, Index outer) - : m_block(aEval.m_block), - m_outerPos( (IsRowMajor ? aEval.startCol() : aEval.startRow()) - 1), // -1 so that operator++ finds the first non-zero entry - m_innerIndex(IsRowMajor ? aEval.startRow() : aEval.startCol()), - m_end(IsRowMajor ? aEval.startCol()+aEval.blockCols() : aEval.startRow()+aEval.blockRows()) + : m_eval(aEval), + m_outerPos( (IsRowMajor ? aEval.m_block.startCol() : aEval.m_block.startRow()) - 1), // -1 so that operator++ finds the first non-zero entry + m_innerIndex(IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol()), + m_end(IsRowMajor ? aEval.m_block.startCol()+aEval.m_block.blockCols() : aEval.m_block.startRow()+aEval.m_block.blockRows()) { EIGEN_UNUSED_VARIABLE(outer); eigen_assert(outer==0); @@ -660,7 +660,7 @@ public: ++(*this); } - inline Index index() const { return m_outerPos - (IsRowMajor ? m_block.startCol() : m_block.startRow()); } + inline Index index() const { return m_outerPos - (IsRowMajor ? m_eval.m_block.startCol() : m_eval.m_block.startRow()); } inline Index outer() const { return 0; } inline Index row() const { return IsRowMajor ? 0 : index(); } inline Index col() const { return IsRowMajor ? index() : 0; } @@ -673,7 +673,7 @@ public: while(m_outerPos class SparseMatrixBase : public EigenBase Block innerVectors(Index outerStart, Index outerSize); const Block innerVectors(Index outerStart, Index outerSize) const; +#ifndef EIGEN_TEST_EVALUATORS /** \internal use operator= */ template void evalTo(MatrixBase& dst) const @@ -346,6 +347,7 @@ template class SparseMatrixBase : public EigenBase for (typename Derived::InnerIterator i(derived(),j); i; ++i) dst.coeffRef(i.row(),i.col()) = i.value(); } +#endif Matrix toDense() const { -- cgit v1.2.3 From a7bd4c455acbf19166e91f2148c042c3f2ea946e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 17:24:43 +0200 Subject: Update sparse reduxions and sparse-vectors to evaluators. --- Eigen/SparseCore | 4 ++-- Eigen/src/SparseCore/SparseDot.h | 13 +++++++++++++ Eigen/src/SparseCore/SparseRedux.h | 6 ++++++ Eigen/src/SparseCore/SparseVector.h | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 4ad6f47a0..0433f4877 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -45,10 +45,10 @@ struct Sparse {}; #include "src/SparseCore/SparseCwiseBinaryOp.h" #include "src/SparseCore/SparseTranspose.h" #include "src/SparseCore/SparseBlock.h" -#ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparseDot.h" -#include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" +#ifndef EIGEN_TEST_EVALUATORS +#include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" #include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" diff --git a/Eigen/src/SparseCore/SparseDot.h b/Eigen/src/SparseCore/SparseDot.h index db39c9aec..a63cb003c 100644 --- a/Eigen/src/SparseCore/SparseDot.h +++ b/Eigen/src/SparseCore/SparseDot.h @@ -26,7 +26,12 @@ SparseMatrixBase::dot(const MatrixBase& other) const eigen_assert(size() == other.size()); eigen_assert(other.size()>0 && "you are using a non initialized vector"); +#ifndef EIGEN_TEST_EVALUATORS typename Derived::InnerIterator i(derived(),0); +#else + typename internal::evaluator::type thisEval(derived()); + typename internal::evaluator::InnerIterator i(thisEval, 0); +#endif Scalar res(0); while (i) { @@ -49,6 +54,7 @@ SparseMatrixBase::dot(const SparseMatrixBase& other) cons eigen_assert(size() == other.size()); +#ifndef EIGEN_TEST_EVALUATORS typedef typename Derived::Nested Nested; typedef typename OtherDerived::Nested OtherNested; typedef typename internal::remove_all::type NestedCleaned; @@ -59,6 +65,13 @@ SparseMatrixBase::dot(const SparseMatrixBase& other) cons typename NestedCleaned::InnerIterator i(nthis,0); typename OtherNestedCleaned::InnerIterator j(nother,0); +#else + typename internal::evaluator::type thisEval(derived()); + typename internal::evaluator::InnerIterator i(thisEval, 0); + + typename internal::evaluator::type otherEval(other.derived()); + typename internal::evaluator::InnerIterator j(otherEval, 0); +#endif Scalar res(0); while (i && j) { diff --git a/Eigen/src/SparseCore/SparseRedux.h b/Eigen/src/SparseCore/SparseRedux.h index f3da93a71..c6d0182d5 100644 --- a/Eigen/src/SparseCore/SparseRedux.h +++ b/Eigen/src/SparseCore/SparseRedux.h @@ -18,8 +18,14 @@ SparseMatrixBase::sum() const { eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); Scalar res(0); +#ifndef EIGEN_TEST_EVALUATORS for (Index j=0; j::type thisEval(derived()); + for (Index j=0; j::InnerIterator iter(thisEval,j); iter; ++iter) +#endif res += iter.value(); return res; } diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index cd22dfd49..81f5eb41d 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.h @@ -433,6 +433,28 @@ struct sparse_vector_assign_selector { } }; #else // EIGEN_TEST_EVALUATORS + +template +struct evaluator > + : evaluator_base > +{ + typedef SparseVector<_Scalar,_Options,_Index> SparseVectorType; + typedef typename SparseVectorType::InnerIterator InnerIterator; + typedef typename SparseVectorType::ReverseInnerIterator ReverseInnerIterator; + + enum { + CoeffReadCost = NumTraits<_Scalar>::ReadCost, + Flags = SparseVectorType::Flags + }; + + evaluator(const SparseVectorType &mat) : m_matrix(mat) {} + + operator SparseVectorType&() { return m_matrix.const_cast_derived(); } + operator const SparseVectorType&() const { return m_matrix; } + + const SparseVectorType &m_matrix; +}; + template< typename Dest, typename Src> struct sparse_vector_assign_selector { static void run(Dest& dst, const Src& src) { -- cgit v1.2.3 From 54607665ab1650cc1d63575b231fa15e514d8aa8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 25 Jun 2014 23:44:59 +0200 Subject: Fix inverse evaluator --- Eigen/src/Core/Inverse.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 2df36dbd5..1d167867f 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -109,8 +109,8 @@ struct unary_evaluator > typedef typename InverseType::PlainObject PlainObject; typedef typename evaluator::type Base; - typedef evaluator type; - typedef evaluator nestedType; + typedef evaluator type; + typedef evaluator nestedType; enum { Flags = Base::Flags | EvalBeforeNestingBit }; -- cgit v1.2.3 From f0648f886058a85930186bd935ffb2c9fa87b1f3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 26 Jun 2014 13:52:19 +0200 Subject: Implement evaluator for sparse views. --- Eigen/SparseCore | 2 +- Eigen/src/SparseCore/SparseUtil.h | 21 ++++++ Eigen/src/SparseCore/SparseView.h | 153 +++++++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 5 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 0433f4877..340ff7f52 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -47,6 +47,7 @@ struct Sparse {}; #include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparseRedux.h" +#include "src/SparseCore/SparseView.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" @@ -58,7 +59,6 @@ struct Sparse {}; #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/TriangularSolver.h" -#include "src/SparseCore/SparseView.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index e23576572..2a67af291 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -43,6 +43,8 @@ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) +#ifndef EIGEN_TEST_EVALUATORS + #define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ typedef typename Eigen::internal::traits::Scalar Scalar; \ @@ -59,6 +61,25 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) using Base::derived; \ using Base::const_cast_derived; +#else // EIGEN_TEST_EVALUATORS + +#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ + typedef BaseClass Base; \ + typedef typename Eigen::internal::traits::Scalar Scalar; \ + typedef typename Eigen::NumTraits::Real RealScalar; \ + typedef typename Eigen::internal::nested::type Nested; \ + typedef typename Eigen::internal::traits::StorageKind StorageKind; \ + typedef typename Eigen::internal::traits::Index Index; \ + enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ + ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ + Flags = Eigen::internal::traits::Flags, \ + SizeAtCompileTime = Base::SizeAtCompileTime, \ + IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ + using Base::derived; \ + using Base::const_cast_derived; + +#endif // EIGEN_TEST_EVALUATORS + #define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index fd8450463..96d0a849c 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -34,25 +34,36 @@ class SparseView : public SparseMatrixBase > typedef typename internal::remove_all::type _MatrixTypeNested; public: EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) + typedef typename internal::remove_all::type NestedExpression; SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), - typename NumTraits::Real m_epsilon = NumTraits::dummy_precision()) : + RealScalar m_epsilon = NumTraits::dummy_precision()) : m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} +#ifndef EIGEN_TEST_EVALUATORS class InnerIterator; +#endif // EIGEN_TEST_EVALUATORS inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } inline Index innerSize() const { return m_matrix.innerSize(); } inline Index outerSize() const { return m_matrix.outerSize(); } - + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_matrix; } + + Scalar reference() const { return m_reference; } + RealScalar epsilon() const { return m_epsilon; } + protected: MatrixTypeNested m_matrix; Scalar m_reference; - typename NumTraits::Real m_epsilon; + RealScalar m_epsilon; }; +#ifndef EIGEN_TEST_EVALUATORS template class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator { @@ -80,13 +91,147 @@ protected: private: void incrementToNonZero() { - while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.m_reference, m_view.m_epsilon)) + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.reference(), m_view.epsilon())) { IterBase::operator++(); } } }; +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +// TODO find a way to unify the two following variants +// This is tricky because implementing an inner iterator on top of an IndexBased evaluator is +// not easy because the evaluators do not expose the sizes of the underlying expression. + +template +struct unary_evaluator, IteratorBased> + : public evaluator_base > +{ + typedef typename evaluator::InnerIterator EvalIterator; + public: + typedef SparseView XprType; + + class InnerIterator : public EvalIterator + { + typedef typename XprType::Scalar Scalar; + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& sve, typename XprType::Index outer) + : EvalIterator(sve.m_argImpl,outer), m_view(sve.m_view) + { + incrementToNonZero(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + EvalIterator::operator++(); + incrementToNonZero(); + return *this; + } + + using EvalIterator::value; + + protected: + const XprType &m_view; + + private: + void incrementToNonZero() + { + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.reference(), m_view.epsilon())) + { + EvalIterator::operator++(); + } + } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + + protected: + typename evaluator::nestedType m_argImpl; + const XprType &m_view; +}; + +template +struct unary_evaluator, IndexBased> + : public evaluator_base > +{ + public: + typedef SparseView XprType; + protected: + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + public: + + class InnerIterator + { + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& sve, typename XprType::Index outer) + : m_sve(sve), m_inner(0), m_outer(outer), m_end(sve.m_view.innerSize()) + { + incrementToNonZero(); + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + m_inner++; + incrementToNonZero(); + return *this; + } + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_sve.m_argImpl.coeff(m_outer, m_inner) + : m_sve.m_argImpl.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + + protected: + const unary_evaluator &m_sve; + Index m_inner; + const Index m_outer; + const Index m_end; + + private: + void incrementToNonZero() + { + while((bool(*this)) && internal::isMuchSmallerThan(value(), m_sve.m_view.reference(), m_sve.m_view.epsilon())) + { + m_inner++; + } + } + }; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + + protected: + typename evaluator::nestedType m_argImpl; + const XprType &m_view; +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + template const SparseView MatrixBase::sparseView(const Scalar& m_reference, const typename NumTraits::Real& m_epsilon) const -- cgit v1.2.3 From ae039dde135a6af852d7028abd772316613a5249 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jun 2014 15:53:51 +0200 Subject: Add a NoPreferredStorageOrderBit flag for expression having no preferred storage order. It is currently only used in Product. --- Eigen/src/Core/DiagonalMatrix.h | 6 +++--- Eigen/src/Core/Product.h | 15 ++++++++++++++- Eigen/src/Core/util/Constants.h | 10 ++++++++++ Eigen/src/SparseCore/SparseAssign.h | 2 +- Eigen/src/SparseCore/SparseMatrix.h | 2 +- Eigen/src/SparseCore/SparseUtil.h | 2 +- 6 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index fc9ecf561..7a0b736f1 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -30,7 +30,7 @@ class DiagonalBase : public EigenBase MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, - Flags = 0 + Flags = NoPreferredStorageOrderBit }; typedef Matrix DenseMatrixType; @@ -159,7 +159,7 @@ struct traits > typedef Dense StorageKind; typedef DenseIndex Index; enum { - Flags = LvalueBit + Flags = LvalueBit | NoPreferredStorageOrderBit }; }; } @@ -287,7 +287,7 @@ struct traits > ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit + Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit #ifndef EIGEN_TEST_EVALUATORS , CoeffReadCost = traits<_DiagonalVectorType>::CoeffReadCost diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 626b737c7..e381ac46a 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -82,7 +82,10 @@ struct traits > #endif // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) + Flags = ( MaxRowsAtCompileTime==1 + || ((LhsCleaned::Flags&NoPreferredStorageOrderBit) && (RhsCleaned::Flags&RowMajorBit)) + || ((RhsCleaned::Flags&NoPreferredStorageOrderBit) && (LhsCleaned::Flags&RowMajorBit)) ) + ? RowMajorBit : (MaxColsAtCompileTime==1 ? 0 : NoPreferredStorageOrderBit) }; }; @@ -156,6 +159,16 @@ public: } // namespace internal +#ifdef EIGEN_TEST_EVALUATORS +// Generic API dispatcher +template +class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; +#endif + template class ProductImpl : public internal::dense_product_base diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index aae8625d1..131f5d793 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -154,6 +154,16 @@ const unsigned int AlignedBit = 0x80; const unsigned int NestByRefBit = 0x100; +/** \ingroup flags + * + * for an expression, this means that the storage order + * can be either row-major or column-major. + * The precise choice will be decided at evaluation time or when + * combined with other expressions. + * \sa \ref RowMajorBit, \ref TopicStorageOrders */ +const unsigned int NoPreferredStorageOrderBit = 0x200; + + // list of flags that are inherited by default const unsigned int HereditaryBits = RowMajorBit | EvalBeforeNestingBit diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 86a0b08c5..68a6ca20e 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -220,7 +220,7 @@ void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) for (Index j=0; j& SparseMatrix::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); + const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); if (needToTranspose) { // two passes algorithm: diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 2a67af291..0dfa15f7c 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -149,7 +149,7 @@ template struct plain_matrix_type { typedef typename traits::Scalar _Scalar; typedef typename traits::Index _Index; - enum { _Options = ((traits::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; + enum { _Options = ((evaluator::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor }; public: typedef SparseMatrix<_Scalar, _Options, _Index> type; }; -- cgit v1.2.3 From 73e686c6a44adfd54fe75a0d7581fd14bfa58f54 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jun 2014 15:54:44 +0200 Subject: Implement evaluators for sparse times diagonal products. --- Eigen/SparseCore | 2 +- Eigen/src/SparseCore/SparseDiagonalProduct.h | 126 ++++++++++++++++++++++++++- Eigen/src/SparseCore/SparseMatrixBase.h | 14 +++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 340ff7f52..b338950ca 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -48,6 +48,7 @@ struct Sparse {}; #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparseRedux.h" #include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparseDiagonalProduct.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" @@ -55,7 +56,6 @@ struct Sparse {}; #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" -#include "src/SparseCore/SparseDiagonalProduct.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/TriangularSolver.h" diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index 1bb590e64..cf0f77342 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -24,8 +24,10 @@ namespace Eigen { // for that particular case // The two other cases are symmetric. +#ifndef EIGEN_TEST_EVALUATORS + namespace internal { - + template struct traits > { @@ -100,9 +102,14 @@ class SparseDiagonalProduct LhsNested m_lhs; RhsNested m_rhs; }; +#endif namespace internal { +#ifndef EIGEN_TEST_EVALUATORS + + + template class sparse_diagonal_product_inner_iterator_selector @@ -179,10 +186,124 @@ class sparse_diagonal_product_inner_iterator_selector inline Index row() const { return m_outer; } }; +#else // EIGEN_TEST_EVALUATORS +enum { + SDP_AsScalarProduct, + SDP_AsCwiseProduct +}; + +template +struct sparse_diagonal_product_evaluator; + +template +struct product_evaluator, ProductTag, DiagonalShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public sparse_diagonal_product_evaluator +{ + typedef Product XprType; + typedef evaluator type; + typedef evaluator nestedType; + enum { CoeffReadCost = Dynamic, Flags = Rhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags + + typedef sparse_diagonal_product_evaluator Base; + product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} +}; + +template +struct product_evaluator, ProductTag, SparseShape, DiagonalShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> +{ + typedef Product XprType; + typedef evaluator type; + typedef evaluator nestedType; + enum { CoeffReadCost = Dynamic, Flags = Lhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags + + typedef sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> Base; + product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) {} +}; + +template +struct sparse_diagonal_product_evaluator +{ +protected: + typedef typename evaluator::InnerIterator SparseXprInnerIterator; + typedef typename SparseXprType::Scalar Scalar; + typedef typename SparseXprType::Index Index; + +public: + class InnerIterator : public SparseXprInnerIterator + { + public: + InnerIterator(const sparse_diagonal_product_evaluator &xprEval, Index outer) + : SparseXprInnerIterator(xprEval.m_sparseXprImpl, outer), + m_coeff(xprEval.m_diagCoeffImpl.coeff(outer)) + {} + + EIGEN_STRONG_INLINE Scalar value() const { return m_coeff * SparseXprInnerIterator::value(); } + protected: + typename DiagonalCoeffType::Scalar m_coeff; + }; + + sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagonalCoeffType &diagCoeff) + : m_sparseXprImpl(sparseXpr), m_diagCoeffImpl(diagCoeff) + {} + +protected: + typename evaluator::nestedType m_sparseXprImpl; + typename evaluator::nestedType m_diagCoeffImpl; +}; + + +template +struct sparse_diagonal_product_evaluator +{ + typedef typename SparseXprType::Scalar Scalar; + typedef typename SparseXprType::Index Index; + + typedef CwiseBinaryOp, + const typename SparseXprType::ConstInnerVectorReturnType, + const DiagCoeffType> CwiseProductType; + + typedef typename evaluator::type CwiseProductEval; + typedef typename evaluator::InnerIterator CwiseProductIterator; + + class InnerIterator : public CwiseProductIterator + { + public: + InnerIterator(const sparse_diagonal_product_evaluator &xprEval, Index outer) + : CwiseProductIterator(CwiseProductEval(xprEval.m_sparseXprNested.innerVector(outer).cwiseProduct(xprEval.m_diagCoeffNested)),0), + m_cwiseEval(xprEval.m_sparseXprNested.innerVector(outer).cwiseProduct(xprEval.m_diagCoeffNested)), + m_outer(outer) + { + ::new (static_cast(this)) CwiseProductIterator(m_cwiseEval,0); + } + + inline Index outer() const { return m_outer; } + inline Index col() const { return SparseXprType::IsRowMajor ? CwiseProductIterator::index() : m_outer; } + inline Index row() const { return SparseXprType::IsRowMajor ? m_outer : CwiseProductIterator::index(); } + + protected: + Index m_outer; + CwiseProductEval m_cwiseEval; + }; + + sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagCoeffType &diagCoeff) + : m_sparseXprNested(sparseXpr), m_diagCoeffNested(diagCoeff) + {} + +protected: + typename nested_eval::type m_sparseXprNested; + typename nested_eval::type m_diagCoeffNested; +}; + +#endif // EIGEN_TEST_EVALUATORS + + } // end namespace internal -// SparseMatrixBase functions +#ifndef EIGEN_TEST_EVALUATORS +// SparseMatrixBase functions template template const SparseDiagonalProduct @@ -190,6 +311,7 @@ SparseMatrixBase::operator*(const DiagonalBase &other) co { return SparseDiagonalProduct(this->derived(), other.derived()); } +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index 4c46008ae..c71244d3e 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -269,6 +269,7 @@ template class SparseMatrixBase : public EigenBase const typename SparseSparseProductReturnType::Type operator*(const SparseMatrixBase &other) const; +#ifndef EIGEN_TEST_EVALUATORS // sparse * diagonal template const SparseDiagonalProduct @@ -279,6 +280,19 @@ template class SparseMatrixBase : public EigenBase const SparseDiagonalProduct operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } +#else // EIGEN_TEST_EVALUATORS + // sparse * diagonal + template + const Product + operator*(const DiagonalBase &other) const + { return Product(derived(), other.derived()); } + + // diagonal * sparse + template friend + const Product + operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) + { return Product(lhs.derived(), rhs.derived()); } +#endif // EIGEN_TEST_EVALUATORS /** dense * sparse (return a dense object unless it is an outer product) */ template friend -- cgit v1.2.3 From c401167712e632a2739ceed26233a510238fc5fc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 27 Jun 2014 16:41:45 +0200 Subject: Fix double constructions of the nested CwiseBinaryOp evaluator in sparse*diagonal product iterator. --- Eigen/src/SparseCore/SparseBlock.h | 3 +-- Eigen/src/SparseCore/SparseDiagonalProduct.h | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h index f562b5479..3cbbfb185 100644 --- a/Eigen/src/SparseCore/SparseBlock.h +++ b/Eigen/src/SparseCore/SparseBlock.h @@ -607,7 +607,6 @@ struct unary_evaluator, IteratorBa protected: typedef typename evaluator::InnerIterator EvalIterator; - typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; typename evaluator::nestedType m_argImpl; const XprType &m_block; @@ -620,7 +619,7 @@ class unary_evaluator, IteratorBas const XprType& m_block; Index m_end; public: - + EIGEN_STRONG_INLINE InnerVectorInnerIterator(const unary_evaluator& aEval, Index outer) : EvalIterator(aEval.m_argImpl, outer + (IsRowMajor ? aEval.m_block.startRow() : aEval.m_block.startCol())), m_block(aEval.m_block), diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index cf0f77342..fd7fd1c24 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -266,24 +266,29 @@ struct sparse_diagonal_product_evaluator::type CwiseProductEval; typedef typename evaluator::InnerIterator CwiseProductIterator; - class InnerIterator : public CwiseProductIterator + class InnerIterator { public: InnerIterator(const sparse_diagonal_product_evaluator &xprEval, Index outer) - : CwiseProductIterator(CwiseProductEval(xprEval.m_sparseXprNested.innerVector(outer).cwiseProduct(xprEval.m_diagCoeffNested)),0), - m_cwiseEval(xprEval.m_sparseXprNested.innerVector(outer).cwiseProduct(xprEval.m_diagCoeffNested)), + : m_cwiseEval(xprEval.m_sparseXprNested.innerVector(outer).cwiseProduct(xprEval.m_diagCoeffNested)), + m_cwiseIter(m_cwiseEval, 0), m_outer(outer) - { - ::new (static_cast(this)) CwiseProductIterator(m_cwiseEval,0); - } + {} + inline Scalar value() const { return m_cwiseIter.value(); } + inline Index index() const { return m_cwiseIter.index(); } inline Index outer() const { return m_outer; } - inline Index col() const { return SparseXprType::IsRowMajor ? CwiseProductIterator::index() : m_outer; } - inline Index row() const { return SparseXprType::IsRowMajor ? m_outer : CwiseProductIterator::index(); } + inline Index col() const { return SparseXprType::IsRowMajor ? m_cwiseIter.index() : m_outer; } + inline Index row() const { return SparseXprType::IsRowMajor ? m_outer : m_cwiseIter.index(); } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { ++m_cwiseIter; return *this; } + inline operator bool() const { return m_cwiseIter; } protected: - Index m_outer; CwiseProductEval m_cwiseEval; + CwiseProductIterator m_cwiseIter; + Index m_outer; }; sparse_diagonal_product_evaluator(const SparseXprType &sparseXpr, const DiagCoeffType &diagCoeff) -- cgit v1.2.3 From 7ffd55c98034964f735e7d6f11c01dcc2cf883ee Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 11:48:49 +0200 Subject: Do not bypass aliasing in sparse e assignments --- Eigen/src/SparseCore/SparseAssign.h | 4 ++-- Eigen/src/SparseCore/SparseMatrix.h | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 68a6ca20e..c99f4b74e 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -143,7 +143,7 @@ template template inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) { - internal::call_assignment_no_alias(derived(), other.derived()); + internal::call_assignment/*_no_alias*/(derived(), other.derived()); return derived(); } @@ -184,7 +184,7 @@ void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) typedef typename internal::evaluator::type SrcEvaluatorType; SrcEvaluatorType srcEvaluator(src); - + const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit); const Index outerSize = (int(SrcEvaluatorType::Flags) & RowMajorBit) ? src.rows() : src.cols(); if ((!transpose) && src.isRValue()) diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 56bf5aaf1..6df4da51a 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -649,7 +649,13 @@ class SparseMatrix EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) check_template_parameters(); +#ifndef EIGEN_TEST_EVALUATORS *this = other.derived(); +#else + const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); + if (needToTranspose) *this = other.derived(); + else internal::call_assignment_no_alias(*this, other.derived()); +#endif } /** Constructs a sparse matrix from the sparse selfadjoint view \a other */ @@ -722,6 +728,7 @@ class SparseMatrix return *this; } +#ifndef EIGEN_TEST_EVALUATORS #ifndef EIGEN_PARSED_BY_DOXYGEN template inline SparseMatrix& operator=(const SparseSparseProduct& product) @@ -738,6 +745,7 @@ class SparseMatrix inline SparseMatrix& operator=(const EigenBase& other) { return Base::operator=(other.derived()); } #endif +#endif // EIGEN_TEST_EVALUATORS template EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other); @@ -1174,7 +1182,9 @@ EIGEN_DONT_INLINE SparseMatrix& SparseMatrix > Flags = SparseMatrixType::Flags }; - evaluator(const SparseMatrixType &mat) : m_matrix(mat) {} + evaluator() : m_matrix(0) {} + evaluator(const SparseMatrixType &mat) : m_matrix(&mat) {} - operator SparseMatrixType&() { return m_matrix.const_cast_derived(); } - operator const SparseMatrixType&() const { return m_matrix; } + operator SparseMatrixType&() { return m_matrix->const_cast_derived(); } + operator const SparseMatrixType&() const { return *m_matrix; } - const SparseMatrixType &m_matrix; + const SparseMatrixType *m_matrix; }; } -- cgit v1.2.3 From 0ad7a644df5c71b9a75c0300210ce17985b88044 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 11:49:46 +0200 Subject: Implement nonZeros() for Transpose --- Eigen/src/SparseCore/SparseTranspose.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Eigen/src/SparseCore/SparseTranspose.h b/Eigen/src/SparseCore/SparseTranspose.h index b20843dd3..f5eff6133 100644 --- a/Eigen/src/SparseCore/SparseTranspose.h +++ b/Eigen/src/SparseCore/SparseTranspose.h @@ -61,6 +61,17 @@ template class TransposeImpl::ReverseInn #else // EIGEN_TEST_EVALUATORS +// Implement nonZeros() for transpose. I'm not sure that's the best approach for that. +// Perhaps it should be implemented in Transpose<> itself. +template class TransposeImpl + : public SparseMatrixBase > +{ + protected: + typedef SparseMatrixBase > Base; + public: + inline typename MatrixType::Index nonZeros() const { return Base::derived().nestedExpression().nonZeros(); } +}; + namespace internal { template -- cgit v1.2.3 From 441f97b2df8465cb8d5c601e9f1ed324af71491e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 11:50:20 +0200 Subject: Implement evaluators for sparse * sparse products --- Eigen/SparseCore | 4 +- .../SparseCore/ConservativeSparseSparseProduct.h | 13 +++++ Eigen/src/SparseCore/SparseMatrixBase.h | 11 +++- Eigen/src/SparseCore/SparseProduct.h | 64 ++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index b338950ca..0c91c3b59 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -49,12 +49,12 @@ struct Sparse {}; #include "src/SparseCore/SparseRedux.h" #include "src/SparseCore/SparseView.h" #include "src/SparseCore/SparseDiagonalProduct.h" +#include "src/SparseCore/ConservativeSparseSparseProduct.h" +#include "src/SparseCore/SparseProduct.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" -#include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" -#include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 5c320e2d2..193d71ca9 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -36,6 +36,11 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r // per column of the lhs. // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); + +#ifdef EIGEN_TEST_EVALUATORS + typename evaluator::type lhsEval(lhs); + typename evaluator::type rhsEval(rhs); +#endif res.setZero(); res.reserve(Index(estimated_nnz_prod)); @@ -45,11 +50,19 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r res.startVec(j); Index nnz = 0; +#ifndef EIGEN_TEST_EVALUATORS for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt) +#else + for (typename evaluator::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) +#endif { Scalar y = rhsIt.value(); Index k = rhsIt.index(); +#ifndef EIGEN_TEST_EVALUATORS for (typename Lhs::InnerIterator lhsIt(lhs, k); lhsIt; ++lhsIt) +#else + for (typename evaluator::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt) +#endif { Index i = lhsIt.index(); Scalar x = lhsIt.value(); diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index c71244d3e..cebf3990d 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -190,8 +190,10 @@ template class SparseMatrixBase : public EigenBase public: +#ifndef EIGEN_TEST_EVALUATORS template inline Derived& operator=(const SparseSparseProduct& product); +#endif friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) { @@ -264,12 +266,12 @@ template class SparseMatrixBase : public EigenBase EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE cwiseProduct(const MatrixBase &other) const; +#ifndef EIGEN_TEST_EVALUATORS // sparse * sparse template const typename SparseSparseProductReturnType::Type operator*(const SparseMatrixBase &other) const; - -#ifndef EIGEN_TEST_EVALUATORS + // sparse * diagonal template const SparseDiagonalProduct @@ -292,6 +294,11 @@ template class SparseMatrixBase : public EigenBase const Product operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) { return Product(lhs.derived(), rhs.derived()); } + + // sparse * sparse + template + const Product + operator*(const SparseMatrixBase &other) const; #endif // EIGEN_TEST_EVALUATORS /** dense * sparse (return a dense object unless it is an outer product) */ diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index cf7663070..52c452f92 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -12,6 +12,8 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS + template struct SparseSparseProductReturnType { @@ -183,6 +185,68 @@ SparseMatrixBase::operator*(const SparseMatrixBase &other return typename SparseSparseProductReturnType::Type(derived(), other.derived()); } +#else // EIGEN_TEST_EVALUATORS + + +/** \returns an expression of the product of two sparse matrices. + * By default a conservative product preserving the symbolic non zeros is performed. + * The automatic pruning of the small values can be achieved by calling the pruned() function + * in which case a totally different product algorithm is employed: + * \code + * C = (A*B).pruned(); // supress numerical zeros (exact) + * C = (A*B).pruned(ref); + * C = (A*B).pruned(ref,epsilon); + * \endcode + * where \c ref is a meaningful non zero reference value. + * */ +template +template +inline const Product +SparseMatrixBase::operator*(const SparseMatrixBase &other) const +{ + return Product(derived(), other.derived()); +} + +namespace internal { + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + internal::conservative_sparse_sparse_product_selector::type, + typename remove_all::type, Dest>::run(lhsNested,rhsNested,dst); + } +}; + +template +struct product_evaluator, ProductTag, SparseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_SPARSEPRODUCT_H -- cgit v1.2.3 From 746d2db6ed5d1bb104757f2170e2018eda524a12 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 13:18:56 +0200 Subject: Implement evaluators for sparse * sparse with auto pruning. --- Eigen/SparseCore | 2 +- Eigen/src/SparseCore/SparseMatrixBase.h | 3 ++ Eigen/src/SparseCore/SparseProduct.h | 30 +++++++++++ .../SparseCore/SparseSparseProductWithPruning.h | 63 ++++++++++++++++++++++ Eigen/src/SparseCore/SparseView.h | 26 +++++++-- 5 files changed, 120 insertions(+), 4 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 0c91c3b59..f74df3038 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -50,11 +50,11 @@ struct Sparse {}; #include "src/SparseCore/SparseView.h" #include "src/SparseCore/SparseDiagonalProduct.h" #include "src/SparseCore/ConservativeSparseSparseProduct.h" +#include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" -#include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseDenseProduct.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index cebf3990d..3a81916fb 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -394,6 +394,9 @@ template class SparseMatrixBase : public EigenBase { return typename internal::eval::type(derived()); } Scalar sum() const; + + inline const SparseView + pruned(const Scalar& reference = Scalar(0), const RealScalar& epsilon = NumTraits::dummy_precision()) const; protected: diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index 52c452f92..8b9578836 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -242,7 +242,37 @@ struct product_evaluator, ProductTag, SparseSh protected: PlainObject m_result; }; + +template +struct evaluator > > + : public evaluator::PlainObject>::type +{ + typedef SparseView > XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + using std::abs; + ::new (static_cast(this)) Base(m_result); + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(xpr.nestedExpression().lhs()); + RhsNested rhsNested(xpr.nestedExpression().rhs()); + + internal::sparse_sparse_product_with_pruning_selector::type, + typename remove_all::type, PlainObject>::run(lhsNested,rhsNested,m_result, + abs(xpr.reference())*xpr.epsilon()); + } +protected: + PlainObject m_result; +}; + } // end namespace internal #endif // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h index fcc18f5c9..c33ec6bfd 100644 --- a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +++ b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h @@ -46,6 +46,11 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r res.resize(cols, rows); else res.resize(rows, cols); + + #ifdef EIGEN_TEST_EVALUATORS + typename evaluator::type lhsEval(lhs); + typename evaluator::type rhsEval(rhs); + #endif res.reserve(estimated_nnz_prod); double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols()); @@ -56,12 +61,20 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r // let's do a more accurate determination of the nnz ratio for the current column j of res tempVector.init(ratioColRes); tempVector.setZero(); +#ifndef EIGEN_TEST_EVALUATORS for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt) +#else + for (typename evaluator::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) +#endif { // FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index()) tempVector.restart(); Scalar x = rhsIt.value(); +#ifndef EIGEN_TEST_EVALUATORS for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt) +#else + for (typename evaluator::InnerIterator lhsIt(lhsEval, rhsIt.index()); lhsIt; ++lhsIt) +#endif { tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x; } @@ -140,8 +153,58 @@ struct sparse_sparse_product_with_pruning_selector +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix RowMajorMatrixLhs; + RowMajorMatrixLhs rowLhs(lhs); + sparse_sparse_product_with_pruning_selector(rowLhs,rhs,res,tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix RowMajorMatrixRhs; + RowMajorMatrixRhs rowRhs(rhs); + sparse_sparse_product_with_pruning_selector(lhs,rowRhs,res,tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix ColMajorMatrixRhs; + ColMajorMatrixRhs colRhs(rhs); + internal::sparse_sparse_product_with_pruning_impl(lhs, colRhs, res, tolerance); + } +}; + +template +struct sparse_sparse_product_with_pruning_selector +{ + typedef typename ResultType::RealScalar RealScalar; + static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) + { + typedef SparseMatrix ColMajorMatrixLhs; + ColMajorMatrixLhs colLhs(lhs); + internal::sparse_sparse_product_with_pruning_impl(colLhs, rhs, res, tolerance); + } +}; +#endif } // end namespace internal diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index 96d0a849c..7bffbb9cd 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -233,10 +233,30 @@ struct unary_evaluator, IndexBased> #endif // EIGEN_TEST_EVALUATORS template -const SparseView MatrixBase::sparseView(const Scalar& m_reference, - const typename NumTraits::Real& m_epsilon) const +const SparseView MatrixBase::sparseView(const Scalar& reference, + const typename NumTraits::Real& epsilon) const { - return SparseView(derived(), m_reference, m_epsilon); + return SparseView(derived(), reference, epsilon); +} + +/** \returns an expression of \c *this with values smaller than + * \a reference * \a epsilon are removed. + * + * This method is typically used in conjunction with the product of two sparse matrices + * to automatically prune the smallest values as follows: + * \code + * C = (A*B).pruned(); // suppress numerical zeros (exact) + * C = (A*B).pruned(ref); + * C = (A*B).pruned(ref,epsilon); + * \endcode + * where \c ref is a meaningful non zero reference value. + * */ +template +const SparseView +SparseMatrixBase::pruned(const Scalar& reference, + const RealScalar& epsilon) const +{ + return SparseView(derived(), reference, epsilon); } } // end namespace Eigen -- cgit v1.2.3 From 3c63446507dbbc891e44b58af07f12f6ef58a175 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 13:27:35 +0200 Subject: Update copyright dates --- Eigen/src/SparseCore/ConservativeSparseSparseProduct.h | 2 +- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 2 +- Eigen/src/SparseCore/SparseDiagonalProduct.h | 2 +- Eigen/src/SparseCore/SparseProduct.h | 2 +- Eigen/src/SparseCore/SparseRedux.h | 2 +- Eigen/src/SparseCore/SparseSparseProductWithPruning.h | 2 +- Eigen/src/SparseCore/SparseUtil.h | 2 +- Eigen/src/SparseCore/SparseVector.h | 2 +- Eigen/src/SparseCore/SparseView.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 193d71ca9..f6824a895 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index f43976641..dcb095dcf 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2014 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index fd7fd1c24..0998feba3 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index 8b9578836..4e181d471 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseRedux.h b/Eigen/src/SparseCore/SparseRedux.h index c6d0182d5..cf78d0e91 100644 --- a/Eigen/src/SparseCore/SparseRedux.h +++ b/Eigen/src/SparseCore/SparseRedux.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h index c33ec6bfd..b42b33e55 100644 --- a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +++ b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 0dfa15f7c..847dfe575 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index 81f5eb41d..ed78d7c1e 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index 7bffbb9cd..c1c50f6e9 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2010 Daniel Lowengrub // // This Source Code Form is subject to the terms of the Mozilla -- cgit v1.2.3 From 6f846ef9c6ef3e838d1361a30dc11f65ddff967d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 17:51:53 +0200 Subject: Split StorageKind promotion into two helpers: one for products, and one for coefficient-wise operations. --- Eigen/src/Core/CwiseBinaryOp.h | 15 +++++--- Eigen/src/Core/PermutationMatrix.h | 16 -------- Eigen/src/Core/Product.h | 15 +++++--- Eigen/src/Core/ProductBase.h | 5 ++- Eigen/src/Core/products/CoeffBasedProduct.h | 5 ++- Eigen/src/Core/util/Constants.h | 4 -- Eigen/src/Core/util/XprHelper.h | 60 ++++++++++++++++++++++++++--- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 6 --- 8 files changed, 78 insertions(+), 48 deletions(-) diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 355f3bdc8..b4662907e 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -56,8 +56,9 @@ struct traits > typename Rhs::Scalar ) >::type Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; + typedef typename cwise_promote_storage_type::StorageKind, + typename traits::StorageKind, + BinaryOp>::ret StorageKind; typedef typename promote_index_type::Index, typename traits::Index>::type Index; typedef typename Lhs::Nested LhsNested; @@ -98,8 +99,9 @@ template class CwiseBinaryOp : internal::no_assignment_operator, public CwiseBinaryOpImpl< BinaryOp, LhsType, RhsType, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret> { public: @@ -108,8 +110,9 @@ class CwiseBinaryOp : internal::no_assignment_operator, typedef typename CwiseBinaryOpImpl< BinaryOp, LhsType, RhsType, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret>::Base Base; + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) typedef typename internal::nested::type LhsNested; diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 4399e1d64..658473397 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -465,22 +465,6 @@ class Map, struct PermutationStorage {}; -#ifdef EIGEN_TEST_EVALUATORS - -// storage type of product of permutation wrapper with dense - -namespace internal { - -template<> struct promote_storage_type -{ typedef Dense ret; }; - -template<> struct promote_storage_type -{ typedef Dense ret; }; - -} // end namespace internal - -#endif // EIGEN_TEST_EVALUATORS - template class TranspositionsWrapper; namespace internal { template diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index e381ac46a..cb4d4c924 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -62,8 +62,9 @@ struct traits > typedef MatrixXpr XprKind; typedef typename product_result_scalar::Scalar Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; + typedef typename product_promote_storage_type::StorageKind, + typename traits::StorageKind, + internal::product_type::ret>::ret StorageKind; typedef typename promote_index_type::Index, typename traits::Index>::type Index; @@ -94,8 +95,9 @@ struct traits > template class Product : public ProductImpl<_Lhs,_Rhs,Option, - typename internal::promote_storage_type::StorageKind, - typename internal::traits<_Rhs>::StorageKind>::ret> + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind, + internal::product_type<_Lhs,_Rhs>::ret>::ret> { public: @@ -104,8 +106,9 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, typedef typename ProductImpl< Lhs, Rhs, Option, - typename internal::promote_storage_type::ret>::Base Base; + typename internal::product_promote_storage_type::ret>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) typedef typename internal::nested::type LhsNested; diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 3b2246fd8..4a54f5f81 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -27,8 +27,9 @@ struct traits > typedef typename remove_all<_Lhs>::type Lhs; typedef typename remove_all<_Rhs>::type Rhs; typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; + typedef typename product_promote_storage_type::StorageKind, + typename traits::StorageKind, + 0>::ret StorageKind; typedef typename promote_index_type::Index, typename traits::Index>::type Index; enum { diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 85e8ac2c7..76806fd62 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -42,8 +42,9 @@ struct traits > typedef typename remove_all::type _LhsNested; typedef typename remove_all::type _RhsNested; typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits<_RhsNested>::StorageKind>::ret StorageKind; + typedef typename product_promote_storage_type::StorageKind, + typename traits<_RhsNested>::StorageKind, + 0>::ret StorageKind; typedef typename promote_index_type::Index, typename traits<_RhsNested>::Index>::type Index; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 131f5d793..4b55b3a9a 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -449,8 +449,6 @@ struct MatrixXpr {}; /** The type used to identify an array expression */ struct ArrayXpr {}; - -#ifdef EIGEN_ENABLE_EVALUATORS // An evaluator must define its shape. By default, it can be one of the following: struct DenseShape { static std::string debugName() { return "DenseShape"; } }; struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; @@ -459,8 +457,6 @@ struct TriangularShape { static std::string debugName() { return "TriangularSha struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; struct SparseShape { static std::string debugName() { return "SparseShape"; } }; -#endif - } // end namespace Eigen diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 19adbefd7..70f2c566f 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -231,6 +231,10 @@ template struct plain_matrix_type { typedef typename plain_matrix_type_dense::XprKind>::type type; }; +template struct plain_matrix_type +{ + typedef typename T::PlainObject type; +}; template struct plain_matrix_type_dense { @@ -273,6 +277,11 @@ template struct eval // > type; }; +template struct eval +{ + typedef typename plain_matrix_type::type type; +}; + // for matrices, no need to evaluate, just use a const reference to avoid a useless copy template struct eval, Dense> @@ -515,12 +524,51 @@ template struct cast_return_type const XprType&,CastType>::type type; }; -template struct promote_storage_type; - -template struct promote_storage_type -{ - typedef A ret; -}; +/** \internal Specify the "storage kind" of applying a coefficient-wise + * binary operations between two expressions of kinds A and B respectively. + * The template parameter Functor permits to specialize the resulting storage kind wrt to + * the functor. + * The default rules are as follows: + * \code + * A op A -> A + * A op dense -> dense + * dense op B -> dense + * A * dense -> A + * dense * B -> B + * \endcode + */ +template struct cwise_promote_storage_type; + +template struct cwise_promote_storage_type { typedef A ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type > { typedef Dense ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type { typedef Dense ret; }; +template struct cwise_promote_storage_type > { typedef A ret; }; +template struct cwise_promote_storage_type > { typedef B ret; }; + +/** \internal Specify the "storage kind" of multiplying an expression of kind A with kind B. + * The template parameter ProductTag permits to specialize the resulting storage kind wrt to + * some compile-time properties of the product: GemmProduct, GemvProduct, OuterProduct, InnerProduct. + * The default rules are as follows: + * \code + * K * K -> K + * dense * K -> dense + * K * dense -> dense + * diag * K -> K + * K * diag -> K + * \endcode + */ +template struct product_promote_storage_type; + +template struct product_promote_storage_type { typedef A ret;}; +template struct product_promote_storage_type { typedef Dense ret;}; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef A ret; }; +template struct product_promote_storage_type { typedef B ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; /** \internal gives the plain matrix or array type to store a row/column/diagonal of a matrix type. * \param Scalar optional parameter allowing to pass a different scalar type than the one of the MatrixType. diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index dcb095dcf..68ea6cb11 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -31,12 +31,6 @@ namespace Eigen { namespace internal { -template<> struct promote_storage_type -{ typedef Sparse ret; }; - -template<> struct promote_storage_type -{ typedef Sparse ret; }; - template::StorageKind, typename _RhsStorageMode = typename traits::StorageKind> -- cgit v1.2.3 From 1e6f53e070ffb3d386bea3cda5e37569c0f11b37 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 17:52:58 +0200 Subject: Use DiagonalShape as the storage kind of DiagonalBase<>. --- Eigen/src/Core/DiagonalMatrix.h | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 7a0b736f1..e26d24eb2 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -156,7 +156,7 @@ struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; - typedef Dense StorageKind; + typedef DiagonalShape StorageKind; typedef DenseIndex Index; enum { Flags = LvalueBit | NoPreferredStorageOrderBit @@ -280,7 +280,7 @@ struct traits > typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::Index Index; - typedef typename DiagonalVectorType::StorageKind StorageKind; + typedef DiagonalShape StorageKind; typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -364,23 +364,8 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const #ifdef EIGEN_ENABLE_EVALUATORS namespace internal { - -// TODO currently a diagonal expression has the form DiagonalMatrix<> or DiagonalWrapper -// in the future diagonal-ness should be defined by the expression traits -template -struct evaluator_traits > -{ - typedef typename storage_kind_to_evaluator_kind::Kind Kind; - typedef DiagonalShape Shape; - static const int AssumeAliasing = 0; -}; -template -struct evaluator_traits > -{ - typedef typename storage_kind_to_evaluator_kind::Kind Kind; - typedef DiagonalShape Shape; - static const int AssumeAliasing = 0; -}; + +template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; struct Diagonal2Dense {}; -- cgit v1.2.3 From 7390af91b63e4f250bddd5971eab44bae3a89f32 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 17:53:18 +0200 Subject: Implement evaluators for sparse*dense products --- Eigen/SparseCore | 2 +- Eigen/src/SparseCore/SparseDenseProduct.h | 334 ++++++++++++++++++++---------- Eigen/src/SparseCore/SparseMatrixBase.h | 34 ++- 3 files changed, 252 insertions(+), 118 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index f74df3038..7cbfb47f2 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -52,10 +52,10 @@ struct Sparse {}; #include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" +#include "src/SparseCore/SparseDenseProduct.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" -#include "src/SparseCore/SparseDenseProduct.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/TriangularSolver.h" diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 610833f3b..2a23365c6 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,6 +12,152 @@ namespace Eigen { +namespace internal { + +template +struct sparse_time_dense_product_impl; + +template +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::Index Index; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename Lhs::InnerIterator LhsInnerIterator; +#else + typedef typename evaluator::InnerIterator LhsInnerIterator; +#endif + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) + { +#ifndef EIGEN_TEST_EVALUATORS + const Lhs &lhsEval(lhs); +#else + typename evaluator::type lhsEval(lhs); +#endif + for(Index c=0; c +struct scalar_product_traits > +{ + enum { + Defined = 1 + }; + typedef typename CwiseUnaryOp, T2>::PlainObject ReturnType; +}; +template +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::Index Index; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename Lhs::InnerIterator LhsInnerIterator; +#else + typedef typename evaluator::InnerIterator LhsInnerIterator; +#endif + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) + { +#ifndef EIGEN_TEST_EVALUATORS + const Lhs &lhsEval(lhs); +#else + typename evaluator::type lhsEval(lhs); +#endif + for(Index c=0; c::ReturnType rhs_j(alpha * rhs.coeff(j,c)); + for(LhsInnerIterator it(lhsEval,j); it ;++it) + res.coeffRef(it.index(),c) += it.value() * rhs_j; + } + } + } +}; + +template +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::Index Index; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename Lhs::InnerIterator LhsInnerIterator; +#else + typedef typename evaluator::InnerIterator LhsInnerIterator; +#endif + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) + { +#ifndef EIGEN_TEST_EVALUATORS + const Lhs &lhsEval(lhs); +#else + typename evaluator::type lhsEval(lhs); +#endif + for(Index j=0; j +struct sparse_time_dense_product_impl +{ + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + typedef typename internal::remove_all::type Res; + typedef typename Lhs::Index Index; +#ifndef EIGEN_TEST_EVALUATORS + typedef typename Lhs::InnerIterator LhsInnerIterator; +#else + typedef typename evaluator::InnerIterator LhsInnerIterator; +#endif + static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) + { +#ifndef EIGEN_TEST_EVALUATORS + const Lhs &lhsEval(lhs); +#else + typename evaluator::type lhsEval(lhs); +#endif + for(Index j=0; j +inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) +{ + sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); +} + +} // end namespace internal + +#ifndef EIGEN_TEST_EVALUATORS template struct SparseDenseProductReturnType { typedef SparseTimeDenseProduct Type; @@ -138,111 +284,6 @@ struct traits > typedef MatrixXpr XprKind; }; -template -struct sparse_time_dense_product_impl; - -template -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::Index Index; - typedef typename Lhs::InnerIterator LhsInnerIterator; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index c=0; c -struct scalar_product_traits > -{ - enum { - Defined = 1 - }; - typedef typename CwiseUnaryOp, T2>::PlainObject ReturnType; -}; -template -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) - { - for(Index c=0; c::ReturnType rhs_j(alpha * rhs.coeff(j,c)); - for(LhsInnerIterator it(lhs,j); it ;++it) - res.coeffRef(it.index(),c) += it.value() * rhs_j; - } - } - } -}; - -template -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index j=0; j -struct sparse_time_dense_product_impl -{ - typedef typename internal::remove_all::type Lhs; - typedef typename internal::remove_all::type Rhs; - typedef typename internal::remove_all::type Res; - typedef typename Lhs::InnerIterator LhsInnerIterator; - typedef typename Lhs::Index Index; - static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) - { - for(Index j=0; j -inline void sparse_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) -{ - sparse_time_dense_product_impl::run(lhs, rhs, res, alpha); -} - } // end namespace internal template @@ -305,6 +346,87 @@ SparseMatrixBase::operator*(const MatrixBase &other) cons { return typename SparseDenseProductReturnType::Type(derived(), other.derived()); } +#endif // EIGEN_TEST_EVALUATORS + +#ifdef EIGEN_TEST_EVALUATORS + +namespace internal { + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + + dst.setZero(); + internal::sparse_time_dense_product(lhsNested, rhsNested, dst, typename Dest::Scalar(1)); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhs); + + dst.setZero(); + // transpoe everything + Transpose dstT(dst); + internal::sparse_time_dense_product(rhsNested.transpose(), lhsNested.transpose(), dstT, typename Dest::Scalar(1)); + } +}; + +template +struct product_evaluator, ProductTag, SparseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, DenseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index 3a81916fb..3bc5af86d 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -282,6 +282,17 @@ template class SparseMatrixBase : public EigenBase const SparseDiagonalProduct operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } + + /** dense * sparse (return a dense object unless it is an outer product) */ + template friend + const typename DenseSparseProductReturnType::Type + operator*(const MatrixBase& lhs, const Derived& rhs) + { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } + + /** sparse * dense (returns a dense object unless it is an outer product) */ + template + const typename SparseDenseProductReturnType::Type + operator*(const MatrixBase &other) const; #else // EIGEN_TEST_EVALUATORS // sparse * diagonal template @@ -299,18 +310,19 @@ template class SparseMatrixBase : public EigenBase template const Product operator*(const SparseMatrixBase &other) const; -#endif // EIGEN_TEST_EVALUATORS - - /** dense * sparse (return a dense object unless it is an outer product) */ - template friend - const typename DenseSparseProductReturnType::Type - operator*(const MatrixBase& lhs, const Derived& rhs) - { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } - - /** sparse * dense (returns a dense object unless it is an outer product) */ + + // sparse * dense template - const typename SparseDenseProductReturnType::Type - operator*(const MatrixBase &other) const; + const Product + operator*(const MatrixBase &other) const + { return Product(derived(), other.derived()); } + + // dense * sparse + template friend + const Product + operator*(const MatrixBase &lhs, const SparseMatrixBase& rhs) + { return Product(lhs.derived(), rhs.derived()); } +#endif // EIGEN_TEST_EVALUATORS /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const -- cgit v1.2.3 From 8f4cdbbc8f9b2214b906412701722a150cba3460 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 1 Jul 2014 18:04:30 +0200 Subject: Fix typo in dense * diagonal evaluator. --- Eigen/src/Core/ProductEvaluators.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 7298c51b1..9436e200b 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -858,7 +858,7 @@ struct product_evaluator, ProductTag, DenseShape, typedef Product XprType; typedef typename XprType::PlainObject PlainObject; - enum { StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; + enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) -- cgit v1.2.3 From 2bdb3b1afdbc07d54fec43edff92138f82492941 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 15 Jul 2014 11:00:16 +0200 Subject: Extend dense*sparse product unit tests --- test/sparse_product.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index 7a76acf57..6d32132bc 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -77,17 +77,27 @@ template void sparse_product() m4 = m2; refMat4 = refMat2; VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3); - // sparse * dense + // sparse * dense matrix VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); VERIFY_IS_APPROX(dm4=m2*refMat3t.transpose(), refMat4=refMat2*refMat3t.transpose()); VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3, refMat4=refMat2t.transpose()*refMat3); VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); + VERIFY_IS_APPROX(dm4=dm4+m2*refMat3, refMat4=refMat4+refMat2*refMat3); VERIFY_IS_APPROX(dm4=m2*(refMat3+refMat3), refMat4=refMat2*(refMat3+refMat3)); VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5); + + // sparse * dense vector + VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3.col(0), refMat4.col(0)=refMat2*refMat3.col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3t.transpose().col(0), refMat4.col(0)=refMat2*refMat3t.transpose().col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3.col(0), refMat4.col(0)=refMat2t.transpose()*refMat3.col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3t.transpose().col(0), refMat4.col(0)=refMat2t.transpose()*refMat3t.transpose().col(0)); // dense * sparse VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3); + VERIFY_IS_APPROX(dm4=dm4+refMat2*m3, refMat4=refMat4+refMat2*refMat3); + VERIFY_IS_APPROX(dm4+=refMat2*m3, refMat4+=refMat2*refMat3); VERIFY_IS_APPROX(dm4=refMat2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose()); VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3); VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); -- cgit v1.2.3 From 36e6c9064fc68d5c47473f6d251da10e96ad42b3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 18 Jul 2014 14:19:18 +0200 Subject: bug #770: fix out of bounds access --- unsupported/Eigen/MPRealSupport | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unsupported/Eigen/MPRealSupport b/unsupported/Eigen/MPRealSupport index 35d77e5bd..0584e470e 100644 --- a/unsupported/Eigen/MPRealSupport +++ b/unsupported/Eigen/MPRealSupport @@ -157,9 +157,12 @@ int main() void operator()(mpreal* res, Index resStride, const mpreal* blockA, const mpreal* blockB, Index rows, Index depth, Index cols, mpreal alpha, Index strideA=-1, Index strideB=-1, Index offsetA=0, Index offsetB=0) { + if(rows==0 || cols==0 || depth==0) + return; + mpreal acc1(0,mpfr_get_prec(blockA[0].mpfr_srcptr())), tmp (0,mpfr_get_prec(blockA[0].mpfr_srcptr())); - + if(strideA==-1) strideA = depth; if(strideB==-1) strideB = depth; -- cgit v1.2.3 From 3eba5e1101d8652483e1cf232a06dccf49a8a530 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 19 Jul 2014 14:55:56 +0200 Subject: Implement evaluator for sparse outer products --- Eigen/src/Core/CoreEvaluators.h | 2 +- Eigen/src/SparseCore/SparseAssign.h | 11 ++- Eigen/src/SparseCore/SparseDenseProduct.h | 155 +++++++++++++++++++++++++++++- Eigen/src/SparseCore/SparseMatrix.h | 4 +- 4 files changed, 163 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index f9f229b09..b19a29e53 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -109,7 +109,7 @@ struct evaluator_base typedef evaluator type; typedef evaluator nestedType; - typedef typename ExpressionType::Index Index; + typedef typename traits::Index Index; // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. typedef traits ExpressionTraits; }; diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 066bc2de1..528d63e35 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -186,14 +186,14 @@ void assign_sparse_to_sparse(DstXprType &dst, const SrcXprType &src) SrcEvaluatorType srcEvaluator(src); const bool transpose = (DstEvaluatorType::Flags & RowMajorBit) != (SrcEvaluatorType::Flags & RowMajorBit); - const Index outerSize = (int(SrcEvaluatorType::Flags) & RowMajorBit) ? src.rows() : src.cols(); + const Index outerEvaluationSize = (SrcEvaluatorType::Flags&RowMajorBit) ? src.rows() : src.cols(); if ((!transpose) && src.isRValue()) { // eval without temporary dst.resize(src.rows(), src.cols()); dst.setZero(); dst.reserve((std::max)(src.rows(),src.cols())*2); - for (Index j=0; j dst.setZero(); typename internal::evaluator::type srcEval(src); typename internal::evaluator::type dstEval(dst); - for (Index j=0; j::Flags&RowMajorBit) ? src.rows() : src.cols(); + for (Index j=0; j::InnerIterator i(srcEval,j); i; ++i) dstEval.coeffRef(i.row(),i.col()) = i.value(); } diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 116edd62e..883e24acb 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -13,7 +13,10 @@ namespace Eigen { namespace internal { - + +template <> struct product_promote_storage_type { typedef Sparse ret; }; +template <> struct product_promote_storage_type { typedef Sparse ret; }; + template +// class sparse_dense_outer_product_iterator : public LhsIterator +// { +// typedef typename SparseDenseOuterProduct::Index Index; +// public: +// template +// EIGEN_STRONG_INLINE InnerIterator(const XprEval& prod, Index outer) +// : LhsIterator(prod.lhs(), 0), +// m_outer(outer), m_empty(false), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) +// {} +// +// inline Index outer() const { return m_outer; } +// inline Index row() const { return Transpose ? m_outer : Base::index(); } +// inline Index col() const { return Transpose ? Base::index() : m_outer; } +// +// inline Scalar value() const { return Base::value() * m_factor; } +// inline operator bool() const { return Base::operator bool() && !m_empty; } +// +// protected: +// Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) const +// { +// return rhs.coeff(outer); +// } +// +// Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) +// { +// typename Traits::_RhsNested::InnerIterator it(rhs, outer); +// if (it && it.index()==0 && it.value()!=Scalar(0)) +// return it.value(); +// m_empty = true; +// return Scalar(0); +// } +// +// Index m_outer; +// bool m_empty; +// Scalar m_factor; +// }; + +template +struct sparse_dense_outer_product_evaluator +{ +protected: + typedef typename conditional::type Lhs1; + typedef typename conditional::type Rhs; + typedef Product ProdXprType; + + // if the actual left-hand side is a dense vector, + // then build a sparse-view so that we can seamlessly iterator over it. + typedef typename conditional::StorageKind,Sparse>::value, + Lhs1, SparseView >::type Lhs; + typedef typename conditional::StorageKind,Sparse>::value, + Lhs1 const&, SparseView >::type LhsArg; + + typedef typename evaluator::type LhsEval; + typedef typename evaluator::type RhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename ProdXprType::Scalar Scalar; + typedef typename ProdXprType::Index Index; + +public: + enum { + Flags = Transpose ? RowMajorBit : 0, + CoeffReadCost = Dynamic + }; + + class InnerIterator : public LhsIterator + { + public: + InnerIterator(const sparse_dense_outer_product_evaluator &xprEval, Index outer) + : LhsIterator(xprEval.m_lhsXprImpl, 0), + m_outer(outer), + m_empty(false), + m_factor(get(xprEval.m_rhsXprImpl, outer, typename internal::traits::StorageKind() )) + {} + + EIGEN_STRONG_INLINE Index outer() const { return m_outer; } + EIGEN_STRONG_INLINE Index row() const { return Transpose ? m_outer : LhsIterator::index(); } + EIGEN_STRONG_INLINE Index col() const { return Transpose ? LhsIterator::index() : m_outer; } + + EIGEN_STRONG_INLINE Scalar value() const { return LhsIterator::value() * m_factor; } + EIGEN_STRONG_INLINE operator bool() const { return LhsIterator::operator bool() && (!m_empty); } + + + protected: + Scalar get(const RhsEval &rhs, Index outer, Dense = Dense()) const + { + return rhs.coeff(outer); + } + + Scalar get(const RhsEval &rhs, Index outer, Sparse = Sparse()) + { + typename RhsEval::InnerIterator it(rhs, outer); + if (it && it.index()==0 && it.value()!=Scalar(0)) + return it.value(); + m_empty = true; + return Scalar(0); + } + + Index m_outer; + bool m_empty; + Scalar m_factor; + }; + + sparse_dense_outer_product_evaluator(const Lhs &lhs, const Rhs &rhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + {} + + // transpose case + sparse_dense_outer_product_evaluator(const Rhs &rhs, const Lhs1 &lhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + {} + +protected: + const LhsArg m_lhs; + typename evaluator::nestedType m_lhsXprImpl; + typename evaluator::nestedType m_rhsXprImpl; +}; + +// sparse * dense outer product +template +struct product_evaluator, OuterProduct, SparseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : sparse_dense_outer_product_evaluator +{ + typedef sparse_dense_outer_product_evaluator Base; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs()) + {} + +}; + +template +struct product_evaluator, OuterProduct, DenseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : sparse_dense_outer_product_evaluator +{ + typedef sparse_dense_outer_product_evaluator Base; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs()) + {} + +}; + } // end namespace internal #endif // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 9d0d6c3ab..36a024cc7 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -1132,7 +1132,7 @@ EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - + const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); if (needToTranspose) { @@ -1140,7 +1140,7 @@ EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::type OtherCopy; + typedef typename internal::nested_eval::type >::type OtherCopy; typedef typename internal::remove_all::type _OtherCopy; typedef internal::evaluator<_OtherCopy> OtherCopyEval; OtherCopy otherCopy(other.derived()); -- cgit v1.2.3 From 62f332fc041a33a151617d93e60503a8a9bbf043 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sat, 19 Jul 2014 15:19:10 +0200 Subject: Make sure we evaluate into temporaries matching evaluator storage order requirements --- Eigen/src/Core/AssignEvaluator.h | 3 +-- Eigen/src/SparseCore/SparseMatrixBase.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index c45ac96f2..43755c2fd 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -695,9 +695,8 @@ void call_assignment(const Dst& dst, const Src& src) template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) { - #ifdef EIGEN_TEST_EVALUATORS - typename Src::PlainObject tmp(src); + typename plain_matrix_type::type tmp(src); #else typename Src::PlainObject tmp(src.rows(), src.cols()); call_assignment_no_alias(tmp, src, internal::assign_op()); diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index a6452fa4e..361a66067 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -102,10 +102,9 @@ template class SparseMatrixBase : public EigenBase Transpose >::type AdjointReturnType; - + // FIXME storage order do not match evaluator storage order typedef SparseMatrix PlainObject; - #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is the "real scalar" type; if the \a Scalar type is already real numbers * (e.g. int, float or double) then \a RealScalar is just the same as \a Scalar. If -- cgit v1.2.3 From 50eef6dfc399b3276005498fc84de6f519708725 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 20 Jul 2014 15:16:34 +0200 Subject: Compilation fixes --- Eigen/src/Core/ProductEvaluators.h | 20 ++++++++++---------- Eigen/src/Core/util/ForwardDeclarations.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 9436e200b..dc91ddd4d 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -889,8 +889,8 @@ struct product_evaluator, ProductTag, DenseShape, * Products with permutation matrices ***************************************************************************/ -template -struct generic_product_impl +template +struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) @@ -900,8 +900,8 @@ struct generic_product_impl } }; -template -struct generic_product_impl +template +struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) @@ -911,8 +911,8 @@ struct generic_product_impl } }; -template -struct generic_product_impl, Rhs, PermutationShape, DenseShape, ProductType> +template +struct generic_product_impl, Rhs, PermutationShape, DenseShape, ProductTag> { template static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) @@ -922,8 +922,8 @@ struct generic_product_impl, Rhs, PermutationShape, DenseShape, P } }; -template -struct generic_product_impl, DenseShape, PermutationShape, ProductType> +template +struct generic_product_impl, DenseShape, PermutationShape, ProductTag> { template static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) @@ -935,7 +935,7 @@ struct generic_product_impl, DenseShape, PermutationShape, P // TODO: left/right and self-adj/symmetric/permutation look the same ... Too much boilerplate? template -struct product_evaluator, ProductTag, PermutationShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> +struct product_evaluator, ProductTag, PermutationShape, DenseShape, typename traits::Scalar, typename traits::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; @@ -954,7 +954,7 @@ protected: }; template -struct product_evaluator, ProductTag, DenseShape, PermutationShape, typename Lhs::Scalar, typename Rhs::Scalar> +struct product_evaluator, ProductTag, DenseShape, PermutationShape, typename traits::Scalar, typename traits::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 274cfac00..99aa9b372 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -164,8 +164,8 @@ template< typename T, int ProductTag = internal::product_type::ret, typename LhsShape = typename evaluator_traits::Shape, typename RhsShape = typename evaluator_traits::Shape, - typename LhsScalar = typename T::Lhs::Scalar, - typename RhsScalar = typename T::Rhs::Scalar + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar > struct product_evaluator; } -- cgit v1.2.3 From 946b99dd5c537f7c93d477645c87fff079a58b6f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 21 Jul 2014 11:45:54 +0200 Subject: Extend qr unit test --- test/qr_fullpivoting.cpp | 6 +++++- test/vectorwiseop.cpp | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/qr_fullpivoting.cpp b/test/qr_fullpivoting.cpp index 511f2473f..601773404 100644 --- a/test/qr_fullpivoting.cpp +++ b/test/qr_fullpivoting.cpp @@ -40,7 +40,11 @@ template void qr() MatrixType c = qr.matrixQ() * r * qr.colsPermutation().inverse(); VERIFY_IS_APPROX(m1, c); - + + // stress the ReturnByValue mechanism + MatrixType tmp; + VERIFY_IS_APPROX(tmp.noalias() = qr.matrixQ() * r, (qr.matrixQ() * r).eval()); + MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); diff --git a/test/vectorwiseop.cpp b/test/vectorwiseop.cpp index 6cd1acdda..1631d54c4 100644 --- a/test/vectorwiseop.cpp +++ b/test/vectorwiseop.cpp @@ -104,8 +104,8 @@ template void vectorwiseop_array(const ArrayType& m) m2 = m1; // yes, there might be an aliasing issue there but ".rowwise() /=" - // is suppposed to evaluate " m2.colwise().sum()" into to temporary to avoid - // evaluating the reducions multiple times + // is supposed to evaluate " m2.colwise().sum()" into a temporary to avoid + // evaluating the reduction multiple times if(ArrayType::RowsAtCompileTime>2 || ArrayType::RowsAtCompileTime==Dynamic) { m2.rowwise() /= m2.colwise().sum(); -- cgit v1.2.3 From 9b729f93a10a43a498f4c10f8d80c31a94ae7a0c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 21 Jul 2014 11:46:47 +0200 Subject: Resizing is done by call_assignment_noalias, so no need to perform it when dealing with aliasing. --- Eigen/src/Core/AssignEvaluator.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 43755c2fd..1727a6a4a 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -702,8 +702,6 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable call_assignment_no_alias(tmp, src, internal::assign_op()); #endif - // resizing - dst.resize(tmp.rows(), tmp.cols()); call_assignment_no_alias(dst, tmp, func); } -- cgit v1.2.3 From 2a251ffab0f3abd1fcfe340a4bee61e352d83424 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 22 Jul 2014 09:32:40 +0200 Subject: Implement evaluator for sparse-selfadjoint products --- Eigen/SparseCore | 3 +- Eigen/src/Core/GeneralProduct.h | 16 +- Eigen/src/Core/Product.h | 24 +- Eigen/src/Core/SelfAdjointView.h | 1 + Eigen/src/SparseCore/SparseAssign.h | 3 + Eigen/src/SparseCore/SparseDenseProduct.h | 39 --- Eigen/src/SparseCore/SparseMatrix.h | 4 + Eigen/src/SparseCore/SparseSelfAdjointView.h | 397 +++++++++++++++++++++------ test/sparse_product.cpp | 10 +- 9 files changed, 352 insertions(+), 145 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 7cbfb47f2..69b413ec2 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -53,11 +53,12 @@ struct Sparse {}; #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" +#include "src/SparseCore/SparseSelfAdjointView.h" #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" #include "src/SparseCore/SparseTriangularView.h" -#include "src/SparseCore/SparseSelfAdjointView.h" + #include "src/SparseCore/TriangularSolver.h" #endif diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 4c1922741..76271a87d 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -62,14 +62,14 @@ template struct product_type typedef typename remove_all::type _Lhs; typedef typename remove_all::type _Rhs; enum { - MaxRows = _Lhs::MaxRowsAtCompileTime, - Rows = _Lhs::RowsAtCompileTime, - MaxCols = _Rhs::MaxColsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, - _Rhs::MaxRowsAtCompileTime), - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, - _Rhs::RowsAtCompileTime) + MaxRows = traits<_Lhs>::MaxRowsAtCompileTime, + Rows = traits<_Lhs>::RowsAtCompileTime, + MaxCols = traits<_Rhs>::MaxColsAtCompileTime, + Cols = traits<_Rhs>::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, + traits<_Rhs>::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, + traits<_Rhs>::RowsAtCompileTime) }; // the splitting into different lines of code here, introducing the _select enums and the typedef below, diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index cb4d4c924..9e5e47d13 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -58,24 +58,26 @@ struct traits > { typedef typename remove_all::type LhsCleaned; typedef typename remove_all::type RhsCleaned; + typedef traits LhsTraits; + typedef traits RhsTraits; typedef MatrixXpr XprKind; typedef typename product_result_scalar::Scalar Scalar; - typedef typename product_promote_storage_type::StorageKind, - typename traits::StorageKind, + typedef typename product_promote_storage_type::ret>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; + typedef typename promote_index_type::type Index; enum { - RowsAtCompileTime = LhsCleaned::RowsAtCompileTime, - ColsAtCompileTime = RhsCleaned::ColsAtCompileTime, - MaxRowsAtCompileTime = LhsCleaned::MaxRowsAtCompileTime, - MaxColsAtCompileTime = RhsCleaned::MaxColsAtCompileTime, + RowsAtCompileTime = LhsTraits::RowsAtCompileTime, + ColsAtCompileTime = RhsTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, // FIXME: only needed by GeneralMatrixMatrixTriangular - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsCleaned::ColsAtCompileTime, RhsCleaned::RowsAtCompileTime), + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), #ifndef EIGEN_TEST_EVALUATORS // dummy, for evaluators unit test only @@ -84,8 +86,8 @@ struct traits > // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. Flags = ( MaxRowsAtCompileTime==1 - || ((LhsCleaned::Flags&NoPreferredStorageOrderBit) && (RhsCleaned::Flags&RowMajorBit)) - || ((RhsCleaned::Flags&NoPreferredStorageOrderBit) && (LhsCleaned::Flags&RowMajorBit)) ) + || ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) + || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit : (MaxColsAtCompileTime==1 ? 0 : NoPreferredStorageOrderBit) }; }; diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 9319ad87c..c8bdec5d4 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -328,6 +328,7 @@ struct triangular_assignment_selector // in the future selfadjoint-ness should be defined by the expression traits // such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 528d63e35..f3da8c6c4 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -127,6 +127,7 @@ template template Derived& SparseMatrixBase::operator=(const EigenBase &other) { + // TODO use the evaluator mechanism other.derived().evalTo(derived()); return derived(); } @@ -135,6 +136,7 @@ template template Derived& SparseMatrixBase::operator=(const ReturnByValue& other) { + // TODO use the evaluator mechanism other.evalTo(derived()); return derived(); } @@ -143,6 +145,7 @@ template template inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) { + // FIXME, by default sparse evaluation do not alias, so we should be able to bypass the generic call_assignment internal::call_assignment/*_no_alias*/(derived(), other.derived()); return derived(); } diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 883e24acb..8864b7308 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -448,45 +448,6 @@ protected: PlainObject m_result; }; - -// template -// class sparse_dense_outer_product_iterator : public LhsIterator -// { -// typedef typename SparseDenseOuterProduct::Index Index; -// public: -// template -// EIGEN_STRONG_INLINE InnerIterator(const XprEval& prod, Index outer) -// : LhsIterator(prod.lhs(), 0), -// m_outer(outer), m_empty(false), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) -// {} -// -// inline Index outer() const { return m_outer; } -// inline Index row() const { return Transpose ? m_outer : Base::index(); } -// inline Index col() const { return Transpose ? Base::index() : m_outer; } -// -// inline Scalar value() const { return Base::value() * m_factor; } -// inline operator bool() const { return Base::operator bool() && !m_empty; } -// -// protected: -// Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) const -// { -// return rhs.coeff(outer); -// } -// -// Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) -// { -// typename Traits::_RhsNested::InnerIterator it(rhs, outer); -// if (it && it.index()==0 && it.value()!=Scalar(0)) -// return it.value(); -// m_empty = true; -// return Scalar(0); -// } -// -// Index m_outer; -// bool m_empty; -// Scalar m_factor; -// }; - template struct sparse_dense_outer_product_evaluator { diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 36a024cc7..5f0c3d0a7 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -664,7 +664,11 @@ class SparseMatrix : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) { check_template_parameters(); +#ifndef EIGEN_TEST_EVALUATORS *this = other; +#else + Base::operator=(other); +#endif } /** Copy constructor (it performs a deep copy) */ diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 56c922929..8bd836883 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,13 +12,23 @@ namespace Eigen { +#ifndef EIGEN_TEST_EVALUATORS + +template +class SparseSelfAdjointTimeDenseProduct; + +template +class DenseTimeSparseSelfAdjointProduct; + +#endif // #ifndef EIGEN_TEST_EVALUATORS + /** \ingroup SparseCore_Module * \class SparseSelfAdjointView * * \brief Pseudo expression to manipulate a triangular sparse matrix as a selfadjoint matrix. * * \param MatrixType the type of the dense matrix storing the coefficients - * \param UpLo can be either \c #Lower or \c #Upper + * \param Mode can be either \c #Lower or \c #Upper * * This class is an expression of a sefladjoint matrix from a triangular part of a matrix * with given dense storage of the coefficients. It is the return type of MatrixBase::selfadjointView() @@ -26,37 +36,33 @@ namespace Eigen { * * \sa SparseMatrixBase::selfadjointView() */ -template -class SparseSelfAdjointTimeDenseProduct; - -template -class DenseTimeSparseSelfAdjointProduct; - namespace internal { -template -struct traits > : traits { +template +struct traits > : traits { }; -template +template void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); -template +template void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm = 0); } -template class SparseSelfAdjointView - : public EigenBase > +template class SparseSelfAdjointView + : public EigenBase > { public: + + enum { Mode = _Mode }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; typedef Matrix VectorI; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename internal::remove_all::type _MatrixTypeNested; - + inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) { eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); @@ -74,40 +80,76 @@ template class SparseSelfAdjointView * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ +#ifndef EIGEN_TEST_EVALUATORS template SparseSparseProduct operator*(const SparseMatrixBase& rhs) const { return SparseSparseProduct(*this, rhs.derived()); } +#else + template + Product + operator*(const SparseMatrixBase& rhs) const + { + return Product(*this, rhs.derived()); + } +#endif /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs. * * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ +#ifndef EIGEN_TEST_EVALUATORS template friend SparseSparseProduct operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) { return SparseSparseProduct(lhs.derived(), rhs); } +#else // EIGEN_TEST_EVALUATORS + template friend + Product + operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) + { + return Product(lhs.derived(), rhs); + } +#endif // EIGEN_TEST_EVALUATORS /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ +#ifndef EIGEN_TEST_EVALUATORS template - SparseSelfAdjointTimeDenseProduct + SparseSelfAdjointTimeDenseProduct operator*(const MatrixBase& rhs) const { - return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); + return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); } +#else + template + Product + operator*(const MatrixBase& rhs) const + { + return Product(*this, rhs.derived()); + } +#endif /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ +#ifndef EIGEN_TEST_EVALUATORS + template friend + DenseTimeSparseSelfAdjointProduct + operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) + { + return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); + } +#else template friend - DenseTimeSparseSelfAdjointProduct + Product operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) { - return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); + return Product(lhs.derived(), rhs); } +#endif /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. @@ -123,30 +165,31 @@ template class SparseSelfAdjointView /** \internal triggered by sparse_matrix = SparseSelfadjointView; */ template void evalTo(SparseMatrix& _dest) const { - internal::permute_symm_to_fullsymm(m_matrix, _dest); + internal::permute_symm_to_fullsymm(m_matrix, _dest); } template void evalTo(DynamicSparseMatrix& _dest) const { // TODO directly evaluate into _dest; SparseMatrix tmp(_dest.rows(),_dest.cols()); - internal::permute_symm_to_fullsymm(m_matrix, tmp); + internal::permute_symm_to_fullsymm(m_matrix, tmp); _dest = tmp; } /** \returns an expression of P H P^-1 */ - SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo> twistedBy(const PermutationMatrix& perm) const +#ifndef EIGEN_TEST_EVALUATORS + SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode> twistedBy(const PermutationMatrix& perm) const { - return SparseSymmetricPermutationProduct<_MatrixTypeNested,UpLo>(m_matrix, perm); + return SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode>(m_matrix, perm); } - - template - SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) + + template + SparseSelfAdjointView& operator=(const SparseSymmetricPermutationProduct& permutedMatrix) { permutedMatrix.evalTo(*this); return *this; } - +#endif // EIGEN_TEST_EVALUATORS SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { @@ -154,22 +197,18 @@ template class SparseSelfAdjointView return *this = src.twistedBy(pnull); } - template - SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) + template + SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { PermutationMatrix pnull; return *this = src.twistedBy(pnull); } - - // const SparseLLT llt() const; - // const SparseLDLT ldlt() const; - protected: typename MatrixType::Nested m_matrix; - mutable VectorI m_countPerRow; - mutable VectorI m_countPerCol; + //mutable VectorI m_countPerRow; + //mutable VectorI m_countPerCol; }; /*************************************************************************** @@ -177,15 +216,15 @@ template class SparseSelfAdjointView ***************************************************************************/ template -template -const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const +template +const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const { return derived(); } template -template -SparseSelfAdjointView SparseMatrixBase::selfadjointView() +template +SparseSelfAdjointView SparseMatrixBase::selfadjointView() { return derived(); } @@ -194,16 +233,16 @@ SparseSelfAdjointView SparseMatrixBase::selfadjointView( * Implementation of SparseSelfAdjointView methods ***************************************************************************/ -template +template template -SparseSelfAdjointView& -SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) +SparseSelfAdjointView& +SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) { SparseMatrix tmp = u * u.adjoint(); if(alpha==Scalar(0)) - m_matrix.const_cast_derived() = tmp.template triangularView(); + m_matrix.const_cast_derived() = tmp.template triangularView(); else - m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); + m_matrix.const_cast_derived() += alpha * tmp.template triangularView(); return *this; } @@ -212,18 +251,19 @@ SparseSelfAdjointView::rankUpdate(const SparseMatrixBase -struct traits > - : traits, Lhs, Rhs> > +template +struct traits > + : traits, Lhs, Rhs> > { typedef Dense StorageKind; }; } -template +template class SparseSelfAdjointTimeDenseProduct - : public ProductBase, Lhs, Rhs> + : public ProductBase, Lhs, Rhs> { public: EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) @@ -241,9 +281,9 @@ class SparseSelfAdjointTimeDenseProduct enum { LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, ProcessFirstHalf = - ((UpLo&(Upper|Lower))==(Upper|Lower)) - || ( (UpLo&Upper) && !LhsIsRowMajor) - || ( (UpLo&Lower) && LhsIsRowMajor), + ((Mode&(Upper|Lower))==(Upper|Lower)) + || ( (Mode&Upper) && !LhsIsRowMajor) + || ( (Mode&Lower) && LhsIsRowMajor), ProcessSecondHalf = !ProcessFirstHalf }; for (typename _Lhs::Index j=0; j -struct traits > - : traits, Lhs, Rhs> > +template +struct traits > + : traits, Lhs, Rhs> > {}; } -template +template class DenseTimeSparseSelfAdjointProduct - : public ProductBase, Lhs, Rhs> + : public ProductBase, Lhs, Rhs> { public: EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) @@ -301,16 +341,197 @@ class DenseTimeSparseSelfAdjointProduct DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); }; +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +template +inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) +{ + EIGEN_ONLY_USED_FOR_DEBUG(alpha); + // TODO use alpha + eigen_assert(alpha==AlphaType(1) && "alpha != 1 is not implemented yet, sorry"); + + typedef typename evaluator::type LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + typedef typename SparseLhsType::Index Index; + typedef typename SparseLhsType::Scalar LhsScalar; + + enum { + LhsIsRowMajor = (LhsEval::Flags&RowMajorBit)==RowMajorBit, + ProcessFirstHalf = + ((Mode&(Upper|Lower))==(Upper|Lower)) + || ( (Mode&Upper) && !LhsIsRowMajor) + || ( (Mode&Lower) && LhsIsRowMajor), + ProcessSecondHalf = !ProcessFirstHalf + }; + + LhsEval lhsEval(lhs); + + for (Index j=0; j +// in the future selfadjoint-ness should be defined by the expression traits +// such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef SparseSelfAdjointShape Shape; + + static const int AssumeAliasing = 0; +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const LhsView& lhsView, const Rhs& rhs) + { + typedef typename LhsView::_MatrixTypeNested Lhs; + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhsView.matrix()); + RhsNested rhsNested(rhs); + + dst.setZero(); + internal::sparse_selfadjoint_time_dense_product(lhsNested, rhsNested, dst, typename Dest::Scalar(1)); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const RhsView& rhsView) + { + typedef typename RhsView::_MatrixTypeNested Rhs; + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + LhsNested lhsNested(lhs); + RhsNested rhsNested(rhsView.matrix()); + + dst.setZero(); + // transpoe everything + Transpose dstT(dst); + internal::sparse_selfadjoint_time_dense_product(rhsNested.transpose(), lhsNested.transpose(), dstT, typename Dest::Scalar(1)); + } +}; + +template +struct product_evaluator, ProductTag, SparseSelfAdjointShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, DenseShape, SparseSelfAdjointShape, typename Lhs::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, SparseSelfAdjointShape, SparseShape, typename LhsView::Scalar, typename Rhs::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : /*m_lhs(xpr.lhs()),*/ m_result(xpr.rows(), xpr.cols()) + { + m_lhs = xpr.lhs(); + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, m_lhs, xpr.rhs()); + } + +protected: + typename Rhs::PlainObject m_lhs; + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, SparseShape, SparseSelfAdjointShape, typename Lhs::Scalar, typename RhsView::Scalar> + : public evaluator::PlainObject>::type +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_rhs(xpr.rhs()), m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), m_rhs); + } + +protected: + typename Lhs::PlainObject m_rhs; + PlainObject m_result; +}; + +} // namespace internal + +#endif // EIGEN_TEST_EVALUATORS + /*************************************************************************** * Implementation of symmetric copies and permutations ***************************************************************************/ namespace internal { - -template -struct traits > : traits { -}; -template +template void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) { typedef typename MatrixType::Index Index; @@ -337,11 +558,11 @@ void permute_symm_to_fullsymm(const MatrixType& mat, SparseMatrixc) || ( UpLo==Upper && rc) || ( Mode==Upper && rc) || ( (UpLo&Upper)==Upper && rc) || ( (Mode&Upper)==Upper && r +template void permute_symm_to_symm(const MatrixType& mat, SparseMatrix& _dest, const typename MatrixType::Index* perm) { typedef typename MatrixType::Index Index; @@ -407,8 +628,8 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrixj)) + if((int(SrcMode)==int(Lower) && ij)) continue; Index ip = perm ? perm[i] : i; - count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; } } dest.outerIndexPtr()[0] = 0; @@ -441,17 +662,17 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrixj)) + if((int(SrcMode)==int(Lower) && ij)) continue; Index jp = perm ? perm[j] : j; Index ip = perm? perm[i] : i; - Index k = count[int(DstUpLo)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; - dest.innerIndexPtr()[k] = int(DstUpLo)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); + Index k = count[int(DstMode)==int(Lower) ? (std::min)(ip,jp) : (std::max)(ip,jp)]++; + dest.innerIndexPtr()[k] = int(DstMode)==int(Lower) ? (std::max)(ip,jp) : (std::min)(ip,jp); if(!StorageOrderMatch) std::swap(ip,jp); - if( ((int(DstUpLo)==int(Lower) && ipjp))) + if( ((int(DstMode)==int(Lower) && ipjp))) dest.valuePtr()[k] = numext::conj(it.value()); else dest.valuePtr()[k] = it.value(); @@ -461,9 +682,19 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrix +#ifndef EIGEN_TEST_EVALUATORS + +namespace internal { + +template +struct traits > : traits { +}; + +} + +template class SparseSymmetricPermutationProduct - : public EigenBase > + : public EigenBase > { public: typedef typename MatrixType::Scalar Scalar; @@ -485,15 +716,15 @@ class SparseSymmetricPermutationProduct template void evalTo(SparseMatrix& _dest) const { -// internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); +// internal::permute_symm_to_fullsymm(m_matrix,_dest,m_perm.indices().data()); SparseMatrix tmp; - internal::permute_symm_to_fullsymm(m_matrix,tmp,m_perm.indices().data()); + internal::permute_symm_to_fullsymm(m_matrix,tmp,m_perm.indices().data()); _dest = tmp; } - template void evalTo(SparseSelfAdjointView& dest) const + template void evalTo(SparseSelfAdjointView& dest) const { - internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); + internal::permute_symm_to_symm(m_matrix,dest.matrix(),m_perm.indices().data()); } protected: @@ -502,6 +733,10 @@ class SparseSymmetricPermutationProduct }; +#else // EIGEN_TEST_EVALUATORS + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index 27bc548f8..fa9be5440 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -19,7 +19,7 @@ template void sparse_product() typedef typename SparseMatrixType::Scalar Scalar; enum { Flags = SparseMatrixType::Flags }; - double density = (std::max)(8./(rows*cols), 0.1); + double density = (std::max)(8./(rows*cols), 0.2); typedef Matrix DenseMatrix; typedef Matrix DenseVector; typedef Matrix RowDenseVector; @@ -109,7 +109,7 @@ template void sparse_product() Index c1 = internal::random(0,cols-1); Index r1 = internal::random(0,depth-1); DenseMatrix dm5 = DenseMatrix::Random(depth, cols); - + VERIFY_IS_APPROX( m4=m2.col(c)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose()); VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); VERIFY_IS_APPROX( m4=m2.middleCols(c,1)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose()); @@ -153,11 +153,11 @@ template void sparse_product() RowSpVector rv0(depth), rv1; RowDenseVector drv0(depth), drv1(rv1); initSparse(2*density,drv0, rv0); - - VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3); + + VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0); VERIFY_IS_APPROX(rv1=rv0*m3, drv1=drv0*refMat3); - VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0); VERIFY_IS_APPROX(cv1=m3t.adjoint()*cv0, dcv1=refMat3t.adjoint()*dcv0); + VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3); VERIFY_IS_APPROX(rv1=m3*cv0, drv1=refMat3*dcv0); } -- cgit v1.2.3 From 6daa6a0d164ac3c225645e47f55238e9ba2a32cc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 22 Jul 2014 11:35:56 +0200 Subject: Refactor TriangularView to handle both dense and sparse objects. Introduce a glu_shape helper to assemble sparse/dense shapes with triagular/seladjoint views. --- Eigen/SparseCore | 6 +- Eigen/src/Core/SolveTriangular.h | 10 +- Eigen/src/Core/TriangularMatrix.h | 303 ++++++++++++--------- .../Core/products/GeneralMatrixMatrixTriangular.h | 13 +- Eigen/src/Core/products/TriangularMatrixMatrix.h | 2 + Eigen/src/Core/products/TriangularMatrixVector.h | 4 +- Eigen/src/Core/util/Constants.h | 14 +- Eigen/src/Core/util/XprHelper.h | 3 + Eigen/src/SparseCholesky/SimplicialCholesky.h | 8 +- Eigen/src/SparseCore/MappedSparseMatrix.h | 28 ++ Eigen/src/SparseCore/SparseMatrixBase.h | 2 +- Eigen/src/SparseCore/SparseSelfAdjointView.h | 2 - Eigen/src/SparseCore/SparseTriangularView.h | 62 +++-- Eigen/src/SparseCore/SparseUtil.h | 7 +- Eigen/src/SparseCore/TriangularSolver.h | 176 +++++++++++- 15 files changed, 438 insertions(+), 202 deletions(-) diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 69b413ec2..578469c1c 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -54,12 +54,12 @@ struct Sparse {}; #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" #include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/SparseTriangularView.h" +#include "src/SparseCore/TriangularSolver.h" + #ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" -#include "src/SparseCore/SparseTriangularView.h" - -#include "src/SparseCore/TriangularSolver.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h index ef17f288e..0f17e3a89 100644 --- a/Eigen/src/Core/SolveTriangular.h +++ b/Eigen/src/Core/SolveTriangular.h @@ -171,10 +171,10 @@ struct triangular_solver_selector { */ template template -void TriangularView::solveInPlace(const MatrixBase& _other) const +void TriangularViewImpl::solveInPlace(const MatrixBase& _other) const { OtherDerived& other = _other.const_cast_derived(); - eigen_assert( cols() == rows() && ((Side==OnTheLeft && cols() == other.rows()) || (Side==OnTheRight && cols() == other.cols())) ); + eigen_assert( derived().cols() == derived().rows() && ((Side==OnTheLeft && derived().cols() == other.rows()) || (Side==OnTheRight && derived().cols() == other.cols())) ); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); enum { copy = internal::traits::Flags & RowMajorBit && OtherDerived::IsVectorAtCompileTime }; @@ -183,7 +183,7 @@ void TriangularView::solveInPlace(const MatrixBase::type, - Side, Mode>::run(nestedExpression(), otherCopy); + Side, Mode>::run(derived().nestedExpression(), otherCopy); if (copy) other = otherCopy; @@ -213,9 +213,9 @@ void TriangularView::solveInPlace(const MatrixBase template const internal::triangular_solve_retval,Other> -TriangularView::solve(const MatrixBase& other) const +TriangularViewImpl::solve(const MatrixBase& other) const { - return internal::triangular_solve_retval(*this, other.derived()); + return internal::triangular_solve_retval(derived(), other.derived()); } namespace internal { diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 69bbaf6a9..25dab0e77 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -49,7 +49,7 @@ template class TriangularBase : public EigenBase typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; + typedef typename internal::traits::FullMatrixType DenseMatrixType; typedef DenseMatrixType DenseType; typedef Derived const& Nested; @@ -172,8 +172,8 @@ struct traits > : traits typedef typename nested::type MatrixTypeNested; typedef typename remove_reference::type MatrixTypeNestedNonRef; typedef typename remove_all::type MatrixTypeNestedCleaned; + typedef typename MatrixType::PlainObject FullMatrixType; typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; enum { Mode = _Mode, Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode @@ -185,22 +185,23 @@ struct traits > : traits }; } +#ifndef EIGEN_TEST_EVALUATORS template struct TriangularProduct; +#endif + +template class TriangularViewImpl; template class TriangularView - : public TriangularBase > + : public TriangularViewImpl<_MatrixType, _Mode, typename internal::traits<_MatrixType>::StorageKind > { public: - typedef TriangularBase Base; + typedef TriangularViewImpl<_MatrixType, _Mode, typename internal::traits<_MatrixType>::StorageKind > Base; typedef typename internal::traits::Scalar Scalar; - typedef _MatrixType MatrixType; - typedef typename internal::traits::DenseMatrixType DenseMatrixType; - typedef DenseMatrixType PlainObject; protected: typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; @@ -210,8 +211,6 @@ template class TriangularView typedef typename internal::remove_all::type MatrixConjugateReturnType; public: - using Base::evalToLazy; - typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; @@ -228,63 +227,163 @@ template class TriangularView EIGEN_DEVICE_FUNC inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) {} + + using Base::operator=; EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } + + EIGEN_DEVICE_FUNC + const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } + EIGEN_DEVICE_FUNC + MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } + + /** \sa MatrixBase::conjugate() */ + EIGEN_DEVICE_FUNC + inline TriangularView conjugate() + { return m_matrix.conjugate(); } + /** \sa MatrixBase::conjugate() const */ + EIGEN_DEVICE_FUNC + inline const TriangularView conjugate() const + { return m_matrix.conjugate(); } + + /** \sa MatrixBase::adjoint() const */ EIGEN_DEVICE_FUNC - inline Index outerStride() const { return m_matrix.outerStride(); } + inline const TriangularView adjoint() const + { return m_matrix.adjoint(); } + + /** \sa MatrixBase::transpose() */ EIGEN_DEVICE_FUNC - inline Index innerStride() const { return m_matrix.innerStride(); } + inline TriangularView,TransposeMode> transpose() + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.const_cast_derived().transpose(); + } + /** \sa MatrixBase::transpose() const */ + EIGEN_DEVICE_FUNC + inline const TriangularView,TransposeMode> transpose() const + { + return m_matrix.transpose(); + } + +#ifdef EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + inline const Solve + solve(const MatrixBase& other) const + { return Solve(*this, other.derived()); } + + using Base::solve; +#endif // EIGEN_TEST_EVALUATORS + + EIGEN_DEVICE_FUNC + const SelfAdjointView selfadjointView() const + { + EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); + return SelfAdjointView(m_matrix); + } + EIGEN_DEVICE_FUNC + SelfAdjointView selfadjointView() + { + EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); + return SelfAdjointView(m_matrix); + } + + EIGEN_DEVICE_FUNC + Scalar determinant() const + { + if (Mode & UnitDiag) + return 1; + else if (Mode & ZeroDiag) + return 0; + else + return m_matrix.diagonal().prod(); + } + + protected: + + MatrixTypeNested m_matrix; +}; + +template class TriangularViewImpl<_MatrixType,_Mode,Dense> + : public TriangularBase > +{ + public: + + typedef TriangularView<_MatrixType, _Mode> TriangularViewType; + typedef TriangularBase Base; + typedef typename internal::traits::Scalar Scalar; + + typedef _MatrixType MatrixType; + typedef typename MatrixType::PlainObject DenseMatrixType; + typedef DenseMatrixType PlainObject; + + public: + using Base::evalToLazy; + using Base::derived; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + enum { + Mode = _Mode, + Flags = internal::traits::Flags + }; + + EIGEN_DEVICE_FUNC + inline Index outerStride() const { return derived().nestedExpression().outerStride(); } + EIGEN_DEVICE_FUNC + inline Index innerStride() const { return derived().nestedExpression().innerStride(); } #ifdef EIGEN_TEST_EVALUATORS /** \sa MatrixBase::operator+=() */ template EIGEN_DEVICE_FUNC - TriangularView& operator+=(const DenseBase& other) { - internal::call_assignment_no_alias(*this, other.derived(), internal::add_assign_op()); - return *this; + TriangularViewType& operator+=(const DenseBase& other) { + internal::call_assignment_no_alias(derived(), other.derived(), internal::add_assign_op()); + return derived(); } /** \sa MatrixBase::operator-=() */ template EIGEN_DEVICE_FUNC - TriangularView& operator-=(const DenseBase& other) { - internal::call_assignment_no_alias(*this, other.derived(), internal::sub_assign_op()); - return *this; + TriangularViewType& operator-=(const DenseBase& other) { + internal::call_assignment_no_alias(derived(), other.derived(), internal::sub_assign_op()); + return derived(); } #else /** \sa MatrixBase::operator+=() */ template EIGEN_DEVICE_FUNC - TriangularView& operator+=(const DenseBase& other) { return *this = m_matrix + other.derived(); } + TriangularViewType& operator+=(const DenseBase& other) { return *this = derived().nestedExpression() + other.derived(); } /** \sa MatrixBase::operator-=() */ template EIGEN_DEVICE_FUNC - TriangularView& operator-=(const DenseBase& other) { return *this = m_matrix - other.derived(); } + TriangularViewType& operator-=(const DenseBase& other) { return *this = derived().nestedExpression() - other.derived(); } #endif /** \sa MatrixBase::operator*=() */ EIGEN_DEVICE_FUNC - TriangularView& operator*=(const typename internal::traits::Scalar& other) { return *this = m_matrix * other; } + TriangularViewType& operator*=(const typename internal::traits::Scalar& other) { return *this = derived().nestedExpression() * other; } /** \sa MatrixBase::operator/=() */ EIGEN_DEVICE_FUNC - TriangularView& operator/=(const typename internal::traits::Scalar& other) { return *this = m_matrix / other; } + TriangularViewType& operator/=(const typename internal::traits::Scalar& other) { return *this = derived().nestedExpression() / other; } /** \sa MatrixBase::fill() */ EIGEN_DEVICE_FUNC void fill(const Scalar& value) { setConstant(value); } /** \sa MatrixBase::setConstant() */ EIGEN_DEVICE_FUNC - TriangularView& setConstant(const Scalar& value) - { return *this = MatrixType::Constant(rows(), cols(), value); } + TriangularViewType& setConstant(const Scalar& value) + { return *this = MatrixType::Constant(derived().rows(), derived().cols(), value); } /** \sa MatrixBase::setZero() */ EIGEN_DEVICE_FUNC - TriangularView& setZero() { return setConstant(Scalar(0)); } + TriangularViewType& setZero() { return setConstant(Scalar(0)); } /** \sa MatrixBase::setOnes() */ EIGEN_DEVICE_FUNC - TriangularView& setOnes() { return setConstant(Scalar(1)); } + TriangularViewType& setOnes() { return setConstant(Scalar(1)); } /** \sa MatrixBase::coeff() * \warning the coordinates must fit into the referenced triangular part @@ -293,7 +392,7 @@ template class TriangularView inline Scalar coeff(Index row, Index col) const { Base::check_coordinates_internal(row, col); - return m_matrix.coeff(row, col); + return derived().nestedExpression().coeff(row, col); } /** \sa MatrixBase::coeffRef() @@ -303,25 +402,20 @@ template class TriangularView inline Scalar& coeffRef(Index row, Index col) { Base::check_coordinates_internal(row, col); - return m_matrix.const_cast_derived().coeffRef(row, col); + return derived().nestedExpression().const_cast_derived().coeffRef(row, col); } - EIGEN_DEVICE_FUNC - const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - EIGEN_DEVICE_FUNC - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } - /** Assigns a triangular matrix to a triangular part of a dense matrix */ template EIGEN_DEVICE_FUNC - TriangularView& operator=(const TriangularBase& other); + TriangularViewType& operator=(const TriangularBase& other); template EIGEN_DEVICE_FUNC - TriangularView& operator=(const MatrixBase& other); + TriangularViewType& operator=(const MatrixBase& other); EIGEN_DEVICE_FUNC - TriangularView& operator=(const TriangularView& other) + TriangularViewType& operator=(const TriangularViewImpl& other) { return *this = other.nestedExpression(); } template @@ -331,53 +425,25 @@ template class TriangularView template EIGEN_DEVICE_FUNC void lazyAssign(const MatrixBase& other); - - /** \sa MatrixBase::conjugate() */ - EIGEN_DEVICE_FUNC - inline TriangularView conjugate() - { return m_matrix.conjugate(); } - /** \sa MatrixBase::conjugate() const */ - EIGEN_DEVICE_FUNC - inline const TriangularView conjugate() const - { return m_matrix.conjugate(); } - - /** \sa MatrixBase::adjoint() const */ - EIGEN_DEVICE_FUNC - inline const TriangularView adjoint() const - { return m_matrix.adjoint(); } - - /** \sa MatrixBase::transpose() */ - EIGEN_DEVICE_FUNC - inline TriangularView,TransposeMode> transpose() - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().transpose(); - } - /** \sa MatrixBase::transpose() const */ - EIGEN_DEVICE_FUNC - inline const TriangularView,TransposeMode> transpose() const - { - return m_matrix.transpose(); - } #ifdef EIGEN_TEST_EVALUATORS /** Efficient triangular matrix times vector/matrix product */ template EIGEN_DEVICE_FUNC - const Product + const Product operator*(const MatrixBase& rhs) const { - return Product(*this, rhs.derived()); + return Product(derived(), rhs.derived()); } /** Efficient vector/matrix times triangular matrix product */ template friend EIGEN_DEVICE_FUNC - const Product - operator*(const MatrixBase& lhs, const TriangularView& rhs) + const Product + operator*(const MatrixBase& lhs, const TriangularViewImpl& rhs) { - return Product(lhs.derived(),rhs); + return Product(lhs.derived(),rhs.derived()); } #else // EIGEN_TEST_EVALUATORS @@ -389,40 +455,34 @@ template class TriangularView { return TriangularProduct - (m_matrix, rhs.derived()); + (derived().nestedExpression(), rhs.derived()); } /** Efficient vector/matrix times triangular matrix product */ template friend EIGEN_DEVICE_FUNC TriangularProduct - operator*(const MatrixBase& lhs, const TriangularView& rhs) + operator*(const MatrixBase& lhs, const TriangularVieImplw& rhs) { return TriangularProduct - (lhs.derived(),rhs.m_matrix); + (lhs.derived(),rhs.nestedExpression()); } #endif template EIGEN_DEVICE_FUNC - inline const internal::triangular_solve_retval + inline const internal::triangular_solve_retval solve(const MatrixBase& other) const; template EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const; -#ifdef EIGEN_TEST_EVALUATORS - template - EIGEN_DEVICE_FUNC - inline const Solve - solve(const MatrixBase& other) const - { return Solve(*this, other.derived()); } -#else // EIGEN_TEST_EVALUATORS +#ifndef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC - inline const internal::triangular_solve_retval + inline const internal::triangular_solve_retval solve(const MatrixBase& other) const { return solve(other); } #endif // EIGEN_TEST_EVALUATORS @@ -432,27 +492,14 @@ template class TriangularView void solveInPlace(const MatrixBase& other) const { return solveInPlace(other); } - EIGEN_DEVICE_FUNC - const SelfAdjointView selfadjointView() const - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - EIGEN_DEVICE_FUNC - SelfAdjointView selfadjointView() - { - EIGEN_STATIC_ASSERT((Mode&UnitDiag)==0,PROGRAMMING_ERROR); - return SelfAdjointView(m_matrix); - } - template EIGEN_DEVICE_FUNC void swap(TriangularBase const & other) { #ifdef EIGEN_TEST_EVALUATORS - call_assignment(*this, other.const_cast_derived(), internal::swap_assign_op()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); #else - TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.const_cast_derived().nestedExpression()); + TriangularView,Mode>(const_cast(derived().nestedExpression())).lazyAssign(other.const_cast_derived().nestedExpression()); #endif } @@ -462,30 +509,19 @@ template class TriangularView void swap(MatrixBase const & other) { #ifdef EIGEN_TEST_EVALUATORS - call_assignment(*this, other.const_cast_derived(), internal::swap_assign_op()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); #else - SwapWrapper swaper(const_cast(m_matrix)); + SwapWrapper swaper(const_cast(derived().nestedExpression())); TriangularView,Mode>(swaper).lazyAssign(other.derived()); #endif } - - EIGEN_DEVICE_FUNC - Scalar determinant() const - { - if (Mode & UnitDiag) - return 1; - else if (Mode & ZeroDiag) - return 0; - else - return m_matrix.diagonal().prod(); - } #ifndef EIGEN_TEST_EVALUATORS // TODO simplify the following: template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase& other) + EIGEN_STRONG_INLINE TriangularViewType& operator=(const ProductBase& other) { setZero(); return assignProduct(other,1); @@ -493,14 +529,14 @@ template class TriangularView template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase& other) + EIGEN_STRONG_INLINE TriangularViewType& operator+=(const ProductBase& other) { return assignProduct(other,1); } template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase& other) + EIGEN_STRONG_INLINE TriangularViewType& operator-=(const ProductBase& other) { return assignProduct(other,-1); } @@ -508,7 +544,7 @@ template class TriangularView template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct& other) + EIGEN_STRONG_INLINE TriangularViewType& operator=(const ScaledProduct& other) { setZero(); return assignProduct(other,other.alpha()); @@ -516,14 +552,14 @@ template class TriangularView template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct& other) + EIGEN_STRONG_INLINE TriangularViewType& operator+=(const ScaledProduct& other) { return assignProduct(other,other.alpha()); } template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct& other) + EIGEN_STRONG_INLINE TriangularViewType& operator-=(const ScaledProduct& other) { return assignProduct(other,-other.alpha()); } @@ -542,16 +578,15 @@ template class TriangularView template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& _assignProduct(const ProductType& prod, const Scalar& alpha); + EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha); protected: #else protected: template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase& prod, const Scalar& alpha); + EIGEN_STRONG_INLINE TriangularViewType& assignProduct(const ProductBase& prod, const Scalar& alpha); #endif - MatrixTypeNested m_matrix; }; /*************************************************************************** @@ -736,18 +771,18 @@ struct triangular_assignment_selector template inline TriangularView& -TriangularView::operator=(const MatrixBase& other) +TriangularViewImpl::operator=(const MatrixBase& other) { - internal::call_assignment_no_alias(*this, other.derived(), internal::assign_op()); - return *this; + internal::call_assignment_no_alias(derived(), other.derived(), internal::assign_op()); + return derived(); } // FIXME should we keep that possibility template template -void TriangularView::lazyAssign(const MatrixBase& other) +void TriangularViewImpl::lazyAssign(const MatrixBase& other) { - internal::call_assignment(this->noalias(), other.template triangularView()); + internal::call_assignment(derived().noalias(), other.template triangularView()); } @@ -755,19 +790,19 @@ void TriangularView::lazyAssign(const MatrixBase template template inline TriangularView& -TriangularView::operator=(const TriangularBase& other) +TriangularViewImpl::operator=(const TriangularBase& other) { eigen_assert(Mode == int(OtherDerived::Mode)); - internal::call_assignment(*this, other.derived()); - return *this; + internal::call_assignment(derived(), other.derived()); + return derived(); } template template -void TriangularView::lazyAssign(const TriangularBase& other) +void TriangularViewImpl::lazyAssign(const TriangularBase& other) { eigen_assert(Mode == int(OtherDerived::Mode)); - internal::call_assignment(this->noalias(), other.derived()); + internal::call_assignment(derived().noalias(), other.derived()); } #else @@ -776,7 +811,7 @@ void TriangularView::lazyAssign(const TriangularBase template inline TriangularView& -TriangularView::operator=(const MatrixBase& other) +TriangularViewImpl::operator=(const MatrixBase& other) { if(OtherDerived::Flags & EvalBeforeAssigningBit) { @@ -786,13 +821,13 @@ TriangularView::operator=(const MatrixBase& othe } else lazyAssign(other.derived()); - return *this; + return derived(); } // FIXME should we keep that possibility template template -void TriangularView::lazyAssign(const MatrixBase& other) +void TriangularViewImp::lazyAssign(const MatrixBase& other) { enum { unroll = MatrixType::SizeAtCompileTime != Dynamic @@ -813,7 +848,7 @@ void TriangularView::lazyAssign(const MatrixBase template template inline TriangularView& -TriangularView::operator=(const TriangularBase& other) +TriangularViewImpl::operator=(const TriangularBase& other) { eigen_assert(Mode == int(OtherDerived::Mode)); if(internal::traits::Flags & EvalBeforeAssigningBit) @@ -824,12 +859,12 @@ TriangularView::operator=(const TriangularBase& } else lazyAssign(other.derived().nestedExpression()); - return *this; + return derived(); } template template -void TriangularView::lazyAssign(const TriangularBase& other) +void TriangularViewImpl::lazyAssign(const TriangularBase& other) { enum { unroll = MatrixType::SizeAtCompileTime != Dynamic @@ -1000,7 +1035,7 @@ template struct evaluator_traits > { typedef typename storage_kind_to_evaluator_kind::Kind Kind; - typedef TriangularShape Shape; + typedef typename glue_shapes::Shape, TriangularShape>::type Shape; // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a // temporary; 0 if not. diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index b28f07bdc..a9d8352a9 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -264,22 +264,23 @@ struct general_product_to_triangular_selector #ifdef EIGEN_TEST_EVALUATORS template template -TriangularView& TriangularView::_assignProduct(const ProductType& prod, const Scalar& alpha) +TriangularView& TriangularViewImpl::_assignProduct(const ProductType& prod, const Scalar& alpha) { - eigen_assert(m_matrix.rows() == prod.rows() && m_matrix.cols() == prod.cols()); + eigen_assert(derived().nestedExpression().rows() == prod.rows() && derived().cols() == prod.cols()); - general_product_to_triangular_selector::InnerSize==1>::run(m_matrix.const_cast_derived(), prod, alpha); + general_product_to_triangular_selector::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha); return *this; } #else template template -TriangularView& TriangularView::assignProduct(const ProductBase& prod, const Scalar& alpha) +TriangularView& TriangularViewImpl::assignProduct(const ProductBase& prod, const Scalar& alpha) { - eigen_assert(m_matrix.rows() == prod.rows() && m_matrix.cols() == prod.cols()); + eigen_assert(derived().rows() == prod.rows() && derived().cols() == prod.cols()); - general_product_to_triangular_selector::run(m_matrix.const_cast_derived(), prod.derived(), alpha); + general_product_to_triangular_selector + ::run(derived().nestedExpression().const_cast_derived(), prod.derived(), alpha); return *this; } diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix.h b/Eigen/src/Core/products/TriangularMatrixMatrix.h index d93277cb8..fda6e2486 100644 --- a/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -368,10 +368,12 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix struct traits > : traits, Lhs, Rhs> > {}; +#endif } // end namespace internal diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index 399de3092..19167c232 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h @@ -157,6 +157,8 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product struct traits > : traits, Lhs, Rhs> > @@ -166,7 +168,7 @@ template struct traits > : traits, Lhs, Rhs> > {}; - +#endif template struct trmv_selector; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 4b55b3a9a..3ab8d0ed3 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -450,13 +450,13 @@ struct MatrixXpr {}; struct ArrayXpr {}; // An evaluator must define its shape. By default, it can be one of the following: -struct DenseShape { static std::string debugName() { return "DenseShape"; } }; -struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; -struct BandShape { static std::string debugName() { return "BandShape"; } }; -struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; -struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; -struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; -struct SparseShape { static std::string debugName() { return "SparseShape"; } }; +struct DenseShape { static std::string debugName() { return "DenseShape"; } }; +struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; +struct BandShape { static std::string debugName() { return "BandShape"; } }; +struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; +struct SelfAdjointShape { static std::string debugName() { return "SelfAdjointShape"; } }; +struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; +struct SparseShape { static std::string debugName() { return "SparseShape"; } }; } // end namespace Eigen diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 70f2c566f..7779fb3fa 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -638,6 +638,9 @@ template struct is_diagonal > template struct is_diagonal > { enum { ret = true }; }; +template struct glue_shapes; +template<> struct glue_shapes { typedef TriangularShape type; }; + } // end namespace internal // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index f41d7e010..21c7e0b39 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -253,8 +253,8 @@ template struct traits CholMatrixType; - typedef SparseTriangularView MatrixL; - typedef SparseTriangularView MatrixU; + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return m; } static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; @@ -266,8 +266,8 @@ template struct traits CholMatrixType; - typedef SparseTriangularView MatrixL; - typedef SparseTriangularView MatrixU; + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return m; } static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; diff --git a/Eigen/src/SparseCore/MappedSparseMatrix.h b/Eigen/src/SparseCore/MappedSparseMatrix.h index ab1a266a9..9205b906f 100644 --- a/Eigen/src/SparseCore/MappedSparseMatrix.h +++ b/Eigen/src/SparseCore/MappedSparseMatrix.h @@ -176,6 +176,34 @@ class MappedSparseMatrix::ReverseInnerIterator const Index m_end; }; +#ifdef EIGEN_ENABLE_EVALUATORS +namespace internal { + +template +struct evaluator > + : evaluator_base > +{ + typedef MappedSparseMatrix<_Scalar,_Options,_Index> MappedSparseMatrixType; + typedef typename MappedSparseMatrixType::InnerIterator InnerIterator; + typedef typename MappedSparseMatrixType::ReverseInnerIterator ReverseInnerIterator; + + enum { + CoeffReadCost = NumTraits<_Scalar>::ReadCost, + Flags = MappedSparseMatrixType::Flags + }; + + evaluator() : m_matrix(0) {} + evaluator(const MappedSparseMatrixType &mat) : m_matrix(&mat) {} + + operator MappedSparseMatrixType&() { return m_matrix->const_cast_derived(); } + operator const MappedSparseMatrixType&() const { return *m_matrix; } + + const MappedSparseMatrixType *m_matrix; +}; + +} +#endif + } // end namespace Eigen #endif // EIGEN_MAPPED_SPARSEMATRIX_H diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index 361a66067..4c5563755 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -333,7 +333,7 @@ template class SparseMatrixBase : public EigenBase Derived& operator*=(const SparseMatrixBase& other); template - inline const SparseTriangularView triangularView() const; + inline const TriangularView triangularView() const; template inline const SparseSelfAdjointView selfadjointView() const; template inline SparseSelfAdjointView selfadjointView(); diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 8bd836883..ff51fc435 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -392,8 +392,6 @@ inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, cons res.row(j) += i.value() * rhs.row(j); } } - -struct SparseSelfAdjointShape { static std::string debugName() { return "SparseSelfAdjointShape"; } }; // TODO currently a selfadjoint expression has the form SelfAdjointView<.,.> // in the future selfadjoint-ness should be defined by the expression traits diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 333127b78..ad184208b 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -15,15 +15,15 @@ namespace Eigen { namespace internal { -template -struct traits > -: public traits -{}; +// template +// struct traits > +// : public traits +// {}; } // namespace internal -template class SparseTriangularView - : public SparseMatrixBase > +template class TriangularViewImpl + : public SparseMatrixBase > { enum { SkipFirst = ((Mode&Lower) && !(MatrixType::Flags&RowMajorBit)) || ((Mode&Upper) && (MatrixType::Flags&RowMajorBit)), @@ -31,45 +31,51 @@ template class SparseTriangularView SkipDiag = (Mode&ZeroDiag) ? 1 : 0, HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 }; + + typedef TriangularView TriangularViewType; + +protected: + // dummy solve function to make TriangularView happy. + void solve() const; public: - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseTriangularView) - + EIGEN_SPARSE_PUBLIC_INTERFACE(TriangularViewType) + class InnerIterator; class ReverseInnerIterator; - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - typedef typename MatrixType::Nested MatrixTypeNested; typedef typename internal::remove_reference::type MatrixTypeNestedNonRef; typedef typename internal::remove_all::type MatrixTypeNestedCleaned; - inline SparseTriangularView(const MatrixType& matrix) : m_matrix(matrix) {} - - /** \internal */ - inline const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } - +#ifndef EIGEN_TEST_EVALUATORS template typename internal::plain_matrix_type_column_major::type solve(const MatrixBase& other) const; +#else // EIGEN_TEST_EVALUATORS + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { + if(!(internal::is_same::value && internal::extract_data(dst) == internal::extract_data(rhs))) + dst = rhs; + this->template solveInPlace(dst); + } +#endif // EIGEN_TEST_EVALUATORS template void solveInPlace(MatrixBase& other) const; template void solveInPlace(SparseMatrixBase& other) const; - - protected: - MatrixTypeNested m_matrix; + }; -template -class SparseTriangularView::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator +template +class TriangularViewImpl::InnerIterator : public MatrixTypeNestedCleaned::InnerIterator { typedef typename MatrixTypeNestedCleaned::InnerIterator Base; - typedef typename SparseTriangularView::Index Index; + typedef typename TriangularViewType::Index Index; public: - EIGEN_STRONG_INLINE InnerIterator(const SparseTriangularView& view, Index outer) + EIGEN_STRONG_INLINE InnerIterator(const TriangularViewImpl& view, Index outer) : Base(view.nestedExpression(), outer), m_returnOne(false) { if(SkipFirst) @@ -132,14 +138,14 @@ class SparseTriangularView::InnerIterator : public MatrixTypeNe bool m_returnOne; }; -template -class SparseTriangularView::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator +template +class TriangularViewImpl::ReverseInnerIterator : public MatrixTypeNestedCleaned::ReverseInnerIterator { typedef typename MatrixTypeNestedCleaned::ReverseInnerIterator Base; - typedef typename SparseTriangularView::Index Index; + typedef typename TriangularViewImpl::Index Index; public: - EIGEN_STRONG_INLINE ReverseInnerIterator(const SparseTriangularView& view, Index outer) + EIGEN_STRONG_INLINE ReverseInnerIterator(const TriangularViewType& view, Index outer) : Base(view.nestedExpression(), outer) { eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal"); @@ -168,7 +174,7 @@ class SparseTriangularView::ReverseInnerIterator : public Matri template template -inline const SparseTriangularView +inline const TriangularView SparseMatrixBase::triangularView() const { return derived(); diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 6e1db0ce8..686be6c92 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -94,7 +94,6 @@ template class Dynamic template class SparseVector; template class MappedSparseMatrix; -template class SparseTriangularView; template class SparseSelfAdjointView; template class SparseDiagonalProduct; template class SparseView; @@ -163,6 +162,12 @@ struct generic_xpr_base typedef SparseMatrixBase type; }; +struct SparseTriangularShape { static std::string debugName() { return "SparseTriangularShape"; } }; +struct SparseSelfAdjointShape { static std::string debugName() { return "SparseSelfAdjointShape"; } }; + +template<> struct glue_shapes { typedef SparseSelfAdjointShape type; }; +template<> struct glue_shapes { typedef SparseTriangularShape type; }; + } // end namespace internal /** \ingroup SparseCore_Module diff --git a/Eigen/src/SparseCore/TriangularSolver.h b/Eigen/src/SparseCore/TriangularSolver.h index dd55522a7..012a1bb75 100644 --- a/Eigen/src/SparseCore/TriangularSolver.h +++ b/Eigen/src/SparseCore/TriangularSolver.h @@ -23,6 +23,7 @@ template::Flags) & RowMajorBit> struct sparse_solve_triangular_selector; +#ifndef EIGEN_TEST_EVALUATORS // forward substitution, row-major template struct sparse_solve_triangular_selector @@ -163,13 +164,166 @@ struct sparse_solve_triangular_selector } }; +#else // EIGEN_TEST_EVALUATORS + +// forward substitution, row-major +template +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + typedef typename Lhs::Index Index; + typedef typename evaluator::type LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + static void run(const Lhs& lhs, Rhs& other) + { + LhsEval lhsEval(lhs); + for(Index col=0 ; col +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + typedef typename Lhs::Index Index; + typedef typename evaluator::type LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + static void run(const Lhs& lhs, Rhs& other) + { + LhsEval lhsEval(lhs); + for(Index col=0 ; col=0 ; --i) + { + Scalar tmp = other.coeff(i,col); + Scalar l_ii = 0; + LhsIterator it(lhsEval, i); + while(it && it.index() +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + typedef typename Lhs::Index Index; + typedef typename evaluator::type LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + static void run(const Lhs& lhs, Rhs& other) + { + LhsEval lhsEval(lhs); + for(Index col=0 ; col +struct sparse_solve_triangular_selector +{ + typedef typename Rhs::Scalar Scalar; + typedef typename Lhs::Index Index; + typedef typename evaluator::type LhsEval; + typedef typename evaluator::InnerIterator LhsIterator; + static void run(const Lhs& lhs, Rhs& other) + { + LhsEval lhsEval(lhs); + for(Index col=0 ; col=0; --i) + { + Scalar& tmp = other.coeffRef(i,col); + if (tmp!=Scalar(0)) // optimization when other is actually sparse + { + if(!(Mode & UnitDiag)) + { + // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements + LhsIterator it(lhsEval, i); + while(it && it.index()!=i) + ++it; + eigen_assert(it && it.index()==i); + other.coeffRef(i,col) /= it.value(); + } + LhsIterator it(lhsEval, i); + for(; it && it.index() +template template -void SparseTriangularView::solveInPlace(MatrixBase& other) const +void TriangularViewImpl::solveInPlace(MatrixBase& other) const { - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); enum { copy = internal::traits::Flags & RowMajorBit }; @@ -178,21 +332,23 @@ void SparseTriangularView::solveInPlace(MatrixBase::type, OtherDerived&>::type OtherCopy; OtherCopy otherCopy(other.derived()); - internal::sparse_solve_triangular_selector::type, Mode>::run(m_matrix, otherCopy); + internal::sparse_solve_triangular_selector::type, Mode>::run(derived().nestedExpression(), otherCopy); if (copy) other = otherCopy; } -template +#ifndef EIGEN_TEST_EVALUATORS +template template typename internal::plain_matrix_type_column_major::type -SparseTriangularView::solve(const MatrixBase& other) const +TriangularViewImpl::solve(const MatrixBase& other) const { typename internal::plain_matrix_type_column_major::type res(other); solveInPlace(res); return res; } +#endif // pure sparse path @@ -290,11 +446,11 @@ struct sparse_solve_triangular_sparse_selector } // end namespace internal -template +template template -void SparseTriangularView::solveInPlace(SparseMatrixBase& other) const +void TriangularViewImpl::solveInPlace(SparseMatrixBase& other) const { - eigen_assert(m_matrix.cols() == m_matrix.rows() && m_matrix.cols() == other.rows()); + eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); eigen_assert( (!(Mode & ZeroDiag)) && bool(Mode & (Upper|Lower))); // enum { copy = internal::traits::Flags & RowMajorBit }; @@ -303,7 +459,7 @@ void SparseTriangularView::solveInPlace(SparseMatrixBase::type, OtherDerived&>::type OtherCopy; // OtherCopy otherCopy(other.derived()); - internal::sparse_solve_triangular_sparse_selector::run(m_matrix, other.derived()); + internal::sparse_solve_triangular_sparse_selector::run(derived().nestedExpression(), other.derived()); // if (copy) // other = otherCopy; -- cgit v1.2.3 From 4aac87251f16094c01e9c5c8bbf094cd471a2306 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 22 Jul 2014 12:54:03 +0200 Subject: Re-enable a couple of unit tests with evaluators. --- Eigen/src/Core/SelfAdjointView.h | 2 +- Eigen/src/SparseCore/SparseMatrix.h | 12 ++++++++++-- test/CMakeLists.txt | 4 +++- test/main.h | 1 + test/sparse_basic.cpp | 9 +++++---- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index c8bdec5d4..546f61252 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -35,7 +35,7 @@ struct traits > : traits typedef typename nested::type MatrixTypeNested; typedef typename remove_all::type MatrixTypeNestedCleaned; typedef MatrixType ExpressionType; - typedef typename MatrixType::PlainObject DenseMatrixType; + typedef typename MatrixType::PlainObject FullMatrixType; enum { Mode = UpLo | SelfAdjoint, Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 5f0c3d0a7..6080c272a 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -52,7 +52,9 @@ struct traits > MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic, Flags = _Options | NestByRefBit | LvalueBit, +#ifndef EIGEN_TEST_EVALUATORS CoeffReadCost = NumTraits::ReadCost, +#endif SupportedAccessPatterns = InnerRandomAccessPattern }; }; @@ -74,8 +76,10 @@ struct traits, DiagIndex> ColsAtCompileTime = 1, MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = 1, - Flags = 0, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 + Flags = 0 +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 +#endif }; }; @@ -1343,6 +1347,8 @@ template struct evaluator > : evaluator_base > { + typedef _Scalar Scalar; + typedef _Index Index; typedef SparseMatrix<_Scalar,_Options,_Index> SparseMatrixType; typedef typename SparseMatrixType::InnerIterator InnerIterator; typedef typename SparseMatrixType::ReverseInnerIterator ReverseInnerIterator; @@ -1358,6 +1364,8 @@ struct evaluator > operator SparseMatrixType&() { return m_matrix->const_cast_derived(); } operator const SparseMatrixType&() const { return *m_matrix; } + Scalar coeff(Index row, Index col) const { return m_matrix->coeff(row,col); } + const SparseMatrixType *m_matrix; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 154e62424..5b5b55c60 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -229,10 +229,12 @@ if(NOT EIGEN_TEST_EVALUATORS) ei_add_test(stdvector_overload) ei_add_test(stdlist) ei_add_test(stddeque) - ei_add_test(sparse_vector) +endif(NOT EIGEN_TEST_EVALUATORS) ei_add_test(sparse_basic) + ei_add_test(sparse_vector) ei_add_test(sparse_product) ei_add_test(sparse_solvers) +if(NOT EIGEN_TEST_EVALUATORS) ei_add_test(sparse_permutations) ei_add_test(simplicial_cholesky) ei_add_test(conjugate_gradient) diff --git a/test/main.h b/test/main.h index a3c157126..57996956d 100644 --- a/test/main.h +++ b/test/main.h @@ -72,6 +72,7 @@ namespace Eigen } #define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl +// #define TRACK while() #define EI_PP_MAKE_STRING2(S) #S #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 4c9b9111e..c86534bad 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -201,9 +201,9 @@ template void sparse_basic(const SparseMatrixType& re VERIFY(m3.innerVector(j0).nonZeros() == m3.transpose().innerVector(j0).nonZeros()); - //m2.innerVector(j0) = 2*m2.innerVector(j1); - //refMat2.col(j0) = 2*refMat2.col(j1); - //VERIFY_IS_APPROX(m2, refMat2); +// m2.innerVector(j0) = 2*m2.innerVector(j1); +// refMat2.col(j0) = 2*refMat2.col(j1); +// VERIFY_IS_APPROX(m2, refMat2); } // test innerVectors() @@ -239,7 +239,7 @@ template void sparse_basic(const SparseMatrixType& re VERIFY_IS_APPROX(m2, refMat2); } - + // test basic computations { DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); @@ -255,6 +255,7 @@ template void sparse_basic(const SparseMatrixType& re initSparse(density, refM3, m3); initSparse(density, refM4, m4); + VERIFY_IS_APPROX(m1*s1, refM1*s1); VERIFY_IS_APPROX(m1+m2, refM1+refM2); VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3); VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2)); -- cgit v1.2.3 From baa77ffe3878ec80f1b136856dbc31d21eac2a1e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 22 Jul 2014 16:13:56 +0200 Subject: Fix max sizes at compile time of DiagonalWrapper --- Eigen/src/Core/DiagonalMatrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 5f7e5fe33..801131b54 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -270,8 +270,8 @@ struct traits > enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit #ifndef EIGEN_TEST_EVALUATORS , -- cgit v1.2.3 From 929e77192cb8c0839238ff95e7eb1b310c627176 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 30 Jul 2014 11:39:52 +0200 Subject: Various minor fixes --- Eigen/src/Core/ProductEvaluators.h | 4 +- Eigen/src/Core/TriangularMatrix.h | 32 +++--- .../Core/products/GeneralMatrixMatrixTriangular.h | 4 +- Eigen/src/SparseCore/SparseAssign.h | 1 + Eigen/src/SparseCore/SparseSelfAdjointView.h | 2 +- Eigen/src/SparseCore/SparseTriangularView.h | 124 +++++++++++++++++++-- Eigen/src/SparseCore/SparseUtil.h | 4 +- test/CMakeLists.txt | 1 - 8 files changed, 137 insertions(+), 35 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index dc91ddd4d..b04df00e7 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -602,7 +602,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - triangular_product_impl + triangular_product_impl ::run(dst, lhs.nestedExpression(), rhs, alpha); } }; @@ -636,7 +636,7 @@ struct generic_product_impl template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { - triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); } }; diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 25dab0e77..0383ca9f5 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -176,7 +176,7 @@ struct traits > : traits typedef MatrixType ExpressionType; enum { Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode + Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) #ifndef EIGEN_TEST_EVALUATORS , CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost @@ -206,7 +206,6 @@ template class TriangularView protected: typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::MatrixTypeNestedNonRef MatrixTypeNestedNonRef; - typedef typename internal::traits::MatrixTypeNestedCleaned MatrixTypeNestedCleaned; typedef typename internal::remove_all::type MatrixConjugateReturnType; @@ -214,6 +213,7 @@ template class TriangularView typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Index Index; + typedef typename internal::traits::MatrixTypeNestedCleaned NestedExpression; enum { Mode = _Mode, @@ -229,6 +229,8 @@ template class TriangularView {} using Base::operator=; + TriangularView& operator=(const TriangularView &other) + { return Base::operator=(other); } EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } @@ -236,9 +238,9 @@ template class TriangularView inline Index cols() const { return m_matrix.cols(); } EIGEN_DEVICE_FUNC - const MatrixTypeNestedCleaned& nestedExpression() const { return m_matrix; } + const NestedExpression& nestedExpression() const { return m_matrix; } EIGEN_DEVICE_FUNC - MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } + NestedExpression& nestedExpression() { return *const_cast(&m_matrix); } /** \sa MatrixBase::conjugate() */ EIGEN_DEVICE_FUNC @@ -416,7 +418,7 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC TriangularViewType& operator=(const TriangularViewImpl& other) - { return *this = other.nestedExpression(); } + { return *this = other.derived().nestedExpression(); } template EIGEN_DEVICE_FUNC @@ -462,11 +464,11 @@ template class TriangularViewImpl<_Mat template friend EIGEN_DEVICE_FUNC TriangularProduct - operator*(const MatrixBase& lhs, const TriangularVieImplw& rhs) + operator*(const MatrixBase& lhs, const TriangularViewImpl& rhs) { return TriangularProduct - (lhs.derived(),rhs.nestedExpression()); + (lhs.derived(),rhs.derived().nestedExpression()); } #endif @@ -827,20 +829,20 @@ TriangularViewImpl::operator=(const MatrixBase template -void TriangularViewImp::lazyAssign(const MatrixBase& other) +void TriangularViewImpl::lazyAssign(const MatrixBase& other) { enum { unroll = MatrixType::SizeAtCompileTime != Dynamic && internal::traits::CoeffReadCost != Dynamic && MatrixType::SizeAtCompileTime*internal::traits::CoeffReadCost/2 <= EIGEN_UNROLLING_LIMIT }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); + eigen_assert(derived().rows() == other.rows() && derived().cols() == other.cols()); internal::triangular_assignment_selector ::run(m_matrix.const_cast_derived(), other.derived()); + >::run(derived().nestedExpression().const_cast_derived(), other.derived()); } @@ -872,13 +874,13 @@ void TriangularViewImpl::lazyAssign(const TriangularBas && MatrixType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT }; - eigen_assert(m_matrix.rows() == other.rows() && m_matrix.cols() == other.cols()); + eigen_assert(derived().rows() == other.rows() && derived().cols() == other.cols()); internal::triangular_assignment_selector ::run(m_matrix.const_cast_derived(), other.derived().nestedExpression()); + >::run(derived().nestedExpression().const_cast_derived(), other.derived().nestedExpression()); } #endif // EIGEN_TEST_EVALUATORS @@ -1043,13 +1045,13 @@ struct evaluator_traits > }; template -struct evaluator > +struct unary_evaluator, IndexBased> : evaluator::type> { typedef TriangularView XprType; typedef evaluator::type> Base; - typedef evaluator type; - evaluator(const XprType &xpr) : Base(xpr.nestedExpression()) {} + typedef evaluator type; + unary_evaluator(const XprType &xpr) : Base(xpr.nestedExpression()) {} }; // Additional assignment kinds: diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index a9d8352a9..06c64714a 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -270,7 +270,7 @@ TriangularView& TriangularViewImpl::_ass general_product_to_triangular_selector::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha); - return *this; + return derived(); } #else template @@ -282,7 +282,7 @@ TriangularView& TriangularViewImpl::assi general_product_to_triangular_selector ::run(derived().nestedExpression().const_cast_derived(), prod.derived(), alpha); - return *this; + return derived(); } #endif } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index f3da8c6c4..c2091ee49 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -173,6 +173,7 @@ struct Sparse2Sparse {}; struct Sparse2Dense {}; template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index ff51fc435..10cd755a4 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -238,7 +238,7 @@ template SparseSelfAdjointView& SparseSelfAdjointView::rankUpdate(const SparseMatrixBase& u, const Scalar& alpha) { - SparseMatrix tmp = u * u.adjoint(); + SparseMatrix tmp = u * u.adjoint(); if(alpha==Scalar(0)) m_matrix.const_cast_derived() = tmp.template triangularView(); else diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index ad184208b..7586a0a6e 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.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-2014 Gael Guennebaud // Copyright (C) 2012 Désiré Nuentsa-Wakam // // This Source Code Form is subject to the terms of the Mozilla @@ -13,15 +13,6 @@ namespace Eigen { -namespace internal { - -// template -// struct traits > -// : public traits -// {}; - -} // namespace internal - template class TriangularViewImpl : public SparseMatrixBase > { @@ -76,7 +67,7 @@ class TriangularViewImpl::InnerIterator : public MatrixT public: EIGEN_STRONG_INLINE InnerIterator(const TriangularViewImpl& view, Index outer) - : Base(view.nestedExpression(), outer), m_returnOne(false) + : Base(view.derived().nestedExpression(), outer), m_returnOne(false) { if(SkipFirst) { @@ -146,7 +137,7 @@ class TriangularViewImpl::ReverseInnerIterator : public public: EIGEN_STRONG_INLINE ReverseInnerIterator(const TriangularViewType& view, Index outer) - : Base(view.nestedExpression(), outer) + : Base(view.derived().nestedExpression(), outer) { eigen_assert((!HasUnitDiag) && "ReverseInnerIterator does not support yet triangular views with a unit diagonal"); if(SkipLast) { @@ -172,6 +163,115 @@ class TriangularViewImpl::ReverseInnerIterator : public } }; +#ifdef EIGEN_TEST_EVALUATORS +namespace internal { + +template +struct unary_evaluator, IteratorBased> + : evaluator_base > +{ + typedef TriangularView XprType; + +protected: + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::Index Index; + typedef typename evaluator::InnerIterator EvalIterator; + + enum { SkipFirst = ((Mode&Lower) && !(ArgType::Flags&RowMajorBit)) + || ((Mode&Upper) && (ArgType::Flags&RowMajorBit)), + SkipLast = !SkipFirst, + SkipDiag = (Mode&ZeroDiag) ? 1 : 0, + HasUnitDiag = (Mode&UnitDiag) ? 1 : 0 + }; + +public: + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = XprType::Flags + }; + + unary_evaluator(const XprType &xpr) : m_argImpl(xpr.nestedExpression()) {} + + class InnerIterator : public EvalIterator + { + typedef EvalIterator Base; + public: + + EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& xprEval, Index outer) + : Base(xprEval.m_argImpl,outer) + { + if(SkipFirst) + { + while((*this) && ((HasUnitDiag||SkipDiag) ? this->index()<=outer : this->index()=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = true; + } + } + + EIGEN_STRONG_INLINE InnerIterator& operator++() + { + if(HasUnitDiag && m_returnOne) + m_returnOne = false; + else + { + Base::operator++(); + if(HasUnitDiag && (!SkipFirst) && ((!Base::operator bool()) || Base::index()>=Base::outer())) + { + if((!SkipFirst) && Base::operator bool()) + Base::operator++(); + m_returnOne = true; + } + } + return *this; + } + + EIGEN_STRONG_INLINE operator bool() const + { + if(HasUnitDiag && m_returnOne) + return true; + if(SkipFirst) return Base::operator bool(); + else + { + if (SkipDiag) return (Base::operator bool() && this->index() < this->outer()); + else return (Base::operator bool() && this->index() <= this->outer()); + } + } + +// inline Index row() const { return (ArgType::Flags&RowMajorBit ? Base::outer() : this->index()); } +// inline Index col() const { return (ArgType::Flags&RowMajorBit ? this->index() : Base::outer()); } + inline Index index() const + { + if(HasUnitDiag && m_returnOne) return Base::outer(); + else return Base::index(); + } + inline Scalar value() const + { + if(HasUnitDiag && m_returnOne) return Scalar(1); + else return Base::value(); + } + + protected: + bool m_returnOne; + private: + Scalar& valueRef(); + }; + +protected: + typename evaluator::type m_argImpl; +}; + +} // end namespace internal +#endif + template template inline const TriangularView diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 686be6c92..0183907a1 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -54,7 +54,7 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) typedef typename Eigen::internal::traits::Index Index; \ enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ + Flags = Eigen::internal::traits::Flags, \ CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ SizeAtCompileTime = Base::SizeAtCompileTime, \ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ @@ -72,7 +72,7 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) typedef typename Eigen::internal::traits::Index Index; \ enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ + Flags = Eigen::internal::traits::Flags, \ SizeAtCompileTime = Base::SizeAtCompileTime, \ IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ using Base::derived; \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5b5b55c60..a53ce22f5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -216,7 +216,6 @@ ei_add_test(jacobi) ei_add_test(jacobisvd) ei_add_test(householder) if(NOT EIGEN_TEST_EVALUATORS) - ei_add_test(cwiseop) # Eigen2 related ei_add_test(geo_orthomethods) ei_add_test(geo_homogeneous) ei_add_test(geo_quaternion) -- cgit v1.2.3 From cd0ff253ec906f0b4604ec084df3d7e7cc6811d1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 30 Jul 2014 15:22:50 +0200 Subject: Make permutation compatible with sparse matrices --- CMakeLists.txt | 2 +- Eigen/SparseCore | 3 - Eigen/src/Core/PermutationMatrix.h | 9 +- Eigen/src/Core/util/Constants.h | 3 + Eigen/src/Core/util/XprHelper.h | 24 +++-- Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 92 +++++++++---------- Eigen/src/SparseCore/SparseMatrix.h | 8 +- Eigen/src/SparseCore/SparsePermutation.h | 131 ++++++++++++++++++++++++++- Eigen/src/SparseCore/SparseSelfAdjointView.h | 12 +-- test/CMakeLists.txt | 2 +- 10 files changed, 213 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 470095680..cc3988196 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,7 +143,7 @@ if(NOT MSVC) ei_add_cxx_compiler_flag("-Wpointer-arith") ei_add_cxx_compiler_flag("-Wwrite-strings") ei_add_cxx_compiler_flag("-Wformat-security") - ei_add_cxx_compiler_flag("-Wshorten-64-to-32") +# ei_add_cxx_compiler_flag("-Wshorten-64-to-32") ei_add_cxx_compiler_flag("-Wenum-conversion") ei_add_cxx_compiler_flag("-Wc++11-extensions") diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 578469c1c..41cae58b0 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -56,11 +56,8 @@ struct Sparse {}; #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/TriangularSolver.h" - -#ifndef EIGEN_TEST_EVALUATORS #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" -#endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 5d648c68c..84d64edb3 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -13,7 +13,8 @@ namespace Eigen { -template class PermutedImpl; +// TODO: this does not seems to be needed at all: +// template class PermutedImpl; /** \class PermutationBase * \ingroup Core_Module @@ -276,6 +277,7 @@ template > : traits > { + typedef PermutationStorage StorageKind; typedef Matrix<_StorageIndexType, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; typedef typename IndicesType::Index Index; typedef _StorageIndexType StorageIndexType; @@ -397,6 +399,7 @@ template,_PacketAccess> > : traits > { + typedef PermutationStorage StorageKind; typedef Map, _PacketAccess> IndicesType; typedef typename IndicesType::Index Index; typedef _StorageIndexType StorageIndexType; @@ -468,8 +471,6 @@ class Map class TranspositionsWrapper; namespace internal { template @@ -665,6 +666,8 @@ struct traits > > } // end namespace internal +// TODO: the specificties should be handled by the evaluator, +// at the very least we should only specialize TransposeImpl template class Transpose > : public EigenBase > > diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 3ab8d0ed3..c0463583d 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -443,6 +443,9 @@ enum Action {GetAction, SetAction}; /** The type used to identify a dense storage. */ struct Dense {}; +/** The type used to identify a permutation storage. */ +struct PermutationStorage {}; + /** The type used to identify a matrix expression */ struct MatrixXpr {}; diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 7779fb3fa..5ed3b39b7 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -557,18 +557,26 @@ template struct cwise_promote_s * K * dense -> dense * diag * K -> K * K * diag -> K + * Perm * K -> K + * K * Perm -> K * \endcode */ template struct product_promote_storage_type; -template struct product_promote_storage_type { typedef A ret;}; -template struct product_promote_storage_type { typedef Dense ret;}; -template struct product_promote_storage_type { typedef Dense ret; }; -template struct product_promote_storage_type { typedef Dense ret; }; -template struct product_promote_storage_type { typedef A ret; }; -template struct product_promote_storage_type { typedef B ret; }; -template struct product_promote_storage_type { typedef Dense ret; }; -template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef A ret;}; +template struct product_promote_storage_type { typedef Dense ret;}; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; + +template struct product_promote_storage_type { typedef A ret; }; +template struct product_promote_storage_type { typedef B ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; + +template struct product_promote_storage_type { typedef A ret; }; +template struct product_promote_storage_type { typedef B ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; +template struct product_promote_storage_type { typedef Dense ret; }; /** \internal gives the plain matrix or array type to store a row/column/diagonal of a matrix type. * \param Scalar optional parameter allowing to pass a different scalar type than the one of the MatrixType. diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index 7a849c822..0e0f9f5f5 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -152,7 +152,7 @@ struct unary_evaluator, IteratorBased> typedef CwiseUnaryOp XprType; class InnerIterator; - class ReverseInnerIterator; +// class ReverseInnerIterator; enum { CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, @@ -163,7 +163,7 @@ struct unary_evaluator, IteratorBased> protected: typedef typename evaluator::InnerIterator EvalIterator; - typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; +// typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; const UnaryOp m_functor; typename evaluator::nestedType m_argImpl; @@ -192,28 +192,28 @@ class unary_evaluator, IteratorBased>::InnerIterat Scalar& valueRef(); }; -template -class unary_evaluator, IteratorBased>::ReverseInnerIterator - : public unary_evaluator, IteratorBased>::EvalReverseIterator -{ - typedef typename XprType::Scalar Scalar; - typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - Scalar& valueRef(); -}; +// template +// class unary_evaluator, IteratorBased>::ReverseInnerIterator +// : public unary_evaluator, IteratorBased>::EvalReverseIterator +// { +// typedef typename XprType::Scalar Scalar; +// typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; +// public: +// +// EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) +// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) +// {} +// +// EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() +// { Base::operator--(); return *this; } +// +// EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } +// +// protected: +// const UnaryOp m_functor; +// private: +// Scalar& valueRef(); +// }; @@ -238,7 +238,7 @@ struct unary_evaluator, IteratorBased> protected: typedef typename evaluator::InnerIterator EvalIterator; - typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; +// typedef typename evaluator::ReverseInnerIterator EvalReverseIterator; const ViewOp m_functor; typename evaluator::nestedType m_argImpl; @@ -266,27 +266,27 @@ class unary_evaluator, IteratorBased>::InnerItera const ViewOp m_functor; }; -template -class unary_evaluator, IteratorBased>::ReverseInnerIterator - : public unary_evaluator, IteratorBased>::EvalReverseIterator -{ - typedef typename XprType::Scalar Scalar; - typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; +// template +// class unary_evaluator, IteratorBased>::ReverseInnerIterator +// : public unary_evaluator, IteratorBased>::EvalReverseIterator +// { +// typedef typename XprType::Scalar Scalar; +// typedef typename unary_evaluator, IteratorBased>::EvalReverseIterator Base; +// public: +// +// EIGEN_STRONG_INLINE ReverseInnerIterator(const XprType& unaryOp, typename XprType::Index outer) +// : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) +// {} +// +// EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() +// { Base::operator--(); return *this; } +// +// EIGEN_STRONG_INLINE Scalar value() const { return m_functor(Base::value()); } +// EIGEN_STRONG_INLINE Scalar& valueRef() { return m_functor(Base::valueRef()); } +// +// protected: +// const ViewOp m_functor; +// }; } // end namespace internal diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 6080c272a..9e2dae1b3 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -736,8 +736,8 @@ class SparseMatrix return *this; } +#ifndef EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_TEST_EVALUATORS - #ifndef EIGEN_PARSED_BY_DOXYGEN template inline SparseMatrix& operator=(const SparseSparseProduct& product) { return Base::operator=(product); } @@ -748,12 +748,12 @@ class SparseMatrix initAssignment(other); return Base::operator=(other.derived()); } - +#endif // EIGEN_TEST_EVALUATORS + template inline SparseMatrix& operator=(const EigenBase& other) { return Base::operator=(other.derived()); } - #endif -#endif // EIGEN_TEST_EVALUATORS +#endif // EIGEN_PARSED_BY_DOXYGEN template EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase& other); diff --git a/Eigen/src/SparseCore/SparsePermutation.h b/Eigen/src/SparseCore/SparsePermutation.h index b85be93f6..ebfefab98 100644 --- a/Eigen/src/SparseCore/SparsePermutation.h +++ b/Eigen/src/SparseCore/SparsePermutation.h @@ -103,7 +103,7 @@ struct permut_sparsematrix_product_retval } - +#ifndef EIGEN_TEST_EVALUATORS /** \returns the matrix with the permutation applied to the columns */ @@ -143,6 +143,135 @@ operator*(const Transpose >& tperm, const SparseMat return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived()); } +#else // EIGEN_TEST_EVALUATORS + +namespace internal { + +template struct product_promote_storage_type { typedef Sparse ret; }; +template struct product_promote_storage_type { typedef Sparse ret; }; + +// TODO, the following need cleaning, this is just a copy-past of the dense case + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permut_sparsematrix_product_retval pmpr(lhs, rhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permut_sparsematrix_product_retval pmpr(rhs, lhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, SparseShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + permut_sparsematrix_product_retval pmpr(lhs.nestedPermutation(), rhs); + pmpr.evalTo(dst); + } +}; + +template +struct generic_product_impl, SparseShape, PermutationShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + permut_sparsematrix_product_retval pmpr(rhs.nestedPermutation(), lhs); + pmpr.evalTo(dst); + } +}; + +template +struct product_evaluator, ProductTag, PermutationShape, SparseShape, typename traits::Scalar, typename traits::Scalar> + : public evaluator >::ReturnType>::type +{ + typedef Product XprType; + typedef typename traits >::ReturnType PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, ProductTag, SparseShape, PermutationShape, typename traits::Scalar, typename traits::Scalar> + : public evaluator >::ReturnType>::type +{ + typedef Product XprType; + typedef typename traits >::ReturnType PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +/** \returns the matrix with the permutation applied to the columns + */ +template +inline const Product +operator*(const SparseMatrixBase& matrix, const PermutationBase& perm) +{ return Product(matrix.derived(), perm.derived()); } + +/** \returns the matrix with the permutation applied to the rows + */ +template +inline const Product +operator*( const PermutationBase& perm, const SparseMatrixBase& matrix) +{ return Product(perm.derived(), matrix.derived()); } + + +// TODO, the following specializations should not be needed as Transpose should be a PermutationBase. +/** \returns the matrix with the inverse permutation applied to the columns. + */ +template +inline const Product > > +operator*(const SparseMatrixBase& matrix, const Transpose >& tperm) +{ + return Product > >(matrix.derived(), tperm); +} + +/** \returns the matrix with the inverse permutation applied to the rows. + */ +template +inline const Product >, SparseDerived> +operator*(const Transpose >& tperm, const SparseMatrixBase& matrix) +{ + return Product >, SparseDerived>(tperm, matrix.derived()); +} + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace Eigen #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 10cd755a4..530ff27bf 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -20,7 +20,7 @@ class SparseSelfAdjointTimeDenseProduct; template class DenseTimeSparseSelfAdjointProduct; -#endif // #ifndef EIGEN_TEST_EVALUATORS +#endif // EIGEN_TEST_EVALUATORS /** \ingroup SparseCore_Module * \class SparseSelfAdjointView @@ -177,7 +177,7 @@ template class SparseSelfAdjointView } /** \returns an expression of P H P^-1 */ -#ifndef EIGEN_TEST_EVALUATORS +// #ifndef EIGEN_TEST_EVALUATORS SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode> twistedBy(const PermutationMatrix& perm) const { return SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode>(m_matrix, perm); @@ -189,7 +189,7 @@ template class SparseSelfAdjointView permutedMatrix.evalTo(*this); return *this; } -#endif // EIGEN_TEST_EVALUATORS +// #endif // EIGEN_TEST_EVALUATORS SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { @@ -680,7 +680,7 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrix Date: Thu, 31 Jul 2014 13:35:49 +0200 Subject: Call product_generic_impl by default, and remove lot of boilerplate code --- Eigen/src/Core/CoreEvaluators.h | 4 +- Eigen/src/Core/Product.h | 4 +- Eigen/src/Core/ProductEvaluators.h | 130 ++------------------ Eigen/src/Geometry/Homogeneous.h | 175 ++++++++++++++++++++++++++- Eigen/src/Geometry/Transform.h | 22 ++++ Eigen/src/SparseCore/SparseDenseProduct.h | 42 +------ Eigen/src/SparseCore/SparseDiagonalProduct.h | 12 +- Eigen/src/SparseCore/SparsePermutation.h | 4 + Eigen/src/SparseCore/SparseProduct.h | 19 --- Eigen/src/SparseCore/SparseSelfAdjointView.h | 46 +------ test/main.h | 6 - 11 files changed, 223 insertions(+), 241 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index b19a29e53..66984e378 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -67,8 +67,8 @@ struct evaluator_traits_base // typedef evaluator nestedType; // by default, get evaluator kind and shape from storage - typedef typename storage_kind_to_evaluator_kind::Kind Kind; - typedef typename storage_kind_to_shape::Shape Shape; + typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; + typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; // 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a // temporary; 0 if not. diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 9e5e47d13..0cf20f2e2 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -108,8 +108,8 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, typedef typename ProductImpl< Lhs, Rhs, Option, - typename internal::product_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, internal::product_type::ret>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index b04df00e7..8a63384a7 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -90,9 +90,10 @@ struct evaluator_traits > enum { AssumeAliasing = 1 }; }; -// The evaluator for default dense products creates a temporary and call generic_product_impl -template -struct product_evaluator, ProductTag, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> +// This is the default evaluator implementation for products: +// It creates a temporary and call generic_product_impl +template +struct product_evaluator, ProductTag, LhsShape, RhsShape, typename traits::Scalar, typename traits::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; @@ -118,7 +119,7 @@ struct product_evaluator, ProductTag, DenseSha // // generic_product_impl::evalTo(m_result, lhs, rhs); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } protected: @@ -501,8 +502,8 @@ protected: }; template -struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar > - : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar > +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar > + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar > { typedef Product XprType; typedef Product BaseProduct; @@ -607,26 +608,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, TriangularShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - - template struct generic_product_impl : generic_product_impl_base > @@ -640,26 +621,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, DenseShape, TriangularShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - - /*************************************************************************** * SelfAdjoint products @@ -681,26 +642,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, SelfAdjointShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - - template struct generic_product_impl : generic_product_impl_base > @@ -714,24 +655,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, DenseShape, SelfAdjointShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; /*************************************************************************** * Diagonal products @@ -933,45 +856,6 @@ struct generic_product_impl, DenseShape, PermutationShape, P } }; -// TODO: left/right and self-adj/symmetric/permutation look the same ... Too much boilerplate? -template -struct product_evaluator, ProductTag, PermutationShape, DenseShape, typename traits::Scalar, typename traits::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - -template -struct product_evaluator, ProductTag, DenseShape, PermutationShape, typename traits::Scalar, typename traits::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 00e71d190..07bc22154 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -48,8 +48,10 @@ struct traits > TmpFlags = _MatrixTypeNested::Flags & HereditaryBits, Flags = ColsAtCompileTime==1 ? (TmpFlags & ~RowMajorBit) : RowsAtCompileTime==1 ? (TmpFlags | RowMajorBit) - : TmpFlags, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + : TmpFlags +#ifndef EIGEN_TEST_EVALUATORS + , CoeffReadCost = _MatrixTypeNested::CoeffReadCost +#endif // EIGEN_TEST_EVALUATORS }; }; @@ -63,6 +65,7 @@ template class Homogeneous { public: + typedef MatrixType NestedExpression; enum { Direction = _Direction }; typedef MatrixBase Base; @@ -74,7 +77,10 @@ template class Homogeneous inline Index rows() const { return m_matrix.rows() + (int(Direction)==Vertical ? 1 : 0); } inline Index cols() const { return m_matrix.cols() + (int(Direction)==Horizontal ? 1 : 0); } + + const NestedExpression& nestedExpression() const { return m_matrix; } +#ifndef EIGEN_TEST_EVALUATORS inline Scalar coeff(Index row, Index col) const { if( (int(Direction)==Vertical && row==m_matrix.rows()) @@ -106,6 +112,31 @@ template class Homogeneous eigen_assert(int(Direction)==Vertical); return internal::homogeneous_left_product_impl >(lhs,rhs.m_matrix); } +#else + template + inline const Product + operator* (const MatrixBase& rhs) const + { + eigen_assert(int(Direction)==Horizontal); + return Product(*this,rhs.derived()); + } + + template friend + inline const Product + operator* (const MatrixBase& lhs, const Homogeneous& rhs) + { + eigen_assert(int(Direction)==Vertical); + return Product(lhs.derived(),rhs); + } + + template friend + inline const Product, Homogeneous > + operator* (const Transform& lhs, const Homogeneous& rhs) + { + eigen_assert(int(Direction)==Vertical); + return Product, Homogeneous>(lhs,rhs); + } +#endif protected: typename MatrixType::Nested m_matrix; @@ -300,6 +331,146 @@ struct homogeneous_right_product_impl,Rhs> typename Rhs::Nested m_rhs; }; +#ifdef EIGEN_TEST_EVALUATORS +template +struct unary_evaluator, IndexBased> + : evaluator::PlainObject >::type +{ + typedef Homogeneous XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + unary_evaluator(const XprType& op) + : Base(), m_temp(op) + { + ::new (static_cast(this)) Base(m_temp); + } + +protected: + PlainObject m_temp; +}; + +// dense = homogeneous +template< typename DstXprType, typename ArgType, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Homogeneous SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst.template topRows(src.nestedExpression().rows()) = src.nestedExpression(); +// dst.topRows(src.nestedExpression().rows()) = src.nestedExpression(); + dst.row(dst.rows()-1).setOnes(); + } +}; + +// dense = homogeneous +template< typename DstXprType, typename ArgType, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Homogeneous SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + dst.template leftCols(src.nestedExpression().cols()) = src.nestedExpression(); +// dst.leftCols(src.nestedExpression().cols()) = src.nestedExpression(); + dst.col(dst.cols()-1).setOnes(); + } +}; + +template +struct generic_product_impl, Rhs, DenseShape, DenseShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Homogeneous& lhs, const Rhs& rhs) + { + homogeneous_right_product_impl, Rhs>(lhs.nestedExpression(), rhs).evalTo(dst); + } +}; + +template +struct generic_product_impl, DenseShape, DenseShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Homogeneous& rhs) + { + homogeneous_left_product_impl, Lhs>(rhs.nestedExpression(), lhs).evalTo(dst); + } +}; + +template +struct generic_product_impl, Homogeneous, DenseShape, DenseShape, ProductTag> +{ + typedef Transform TransformType; + template + static void evalTo(Dest& dst, const TransformType& lhs, const Homogeneous& rhs) + { + homogeneous_left_product_impl, TransformType>(rhs.nestedExpression(), lhs).evalTo(dst); + } +}; + + +template +struct product_evaluator, Rhs, DefaultProduct>, ProductTag, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar> + : public evaluator, Rhs, DefaultProduct>::PlainObject>::type +{ + typedef Homogeneous Lhs; + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, DefaultProduct>, ProductTag, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar> + : public evaluator, DefaultProduct>::PlainObject>::type +{ + typedef Homogeneous Rhs; + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +template +struct product_evaluator, Homogeneous, DefaultProduct>, ProductTag, DenseShape, DenseShape, Scalar, typename traits::Scalar> + : public evaluator, Homogeneous, DefaultProduct>::PlainObject>::type +{ + typedef Transform Lhs; + typedef Homogeneous Rhs; + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +#endif // EIGEN_TEST_EVALUATORS + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index cb93acf6b..54d05f9cf 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -62,6 +62,23 @@ struct transform_construct_from_matrix; template struct transform_take_affine_part; +#ifdef EIGEN_TEST_EVALUATORS +template +struct traits > +{ + typedef _Scalar Scalar; + typedef DenseIndex Index; + typedef Dense StorageKind; + enum { + RowsAtCompileTime = _Dim, + ColsAtCompileTime = _Dim, + MaxRowsAtCompileTime = _Dim, + MaxColsAtCompileTime = _Dim, + Flags = 0 + }; +}; +#endif + } // end namespace internal /** \geometry_module \ingroup Geometry_Module @@ -355,6 +372,11 @@ public: inline Transform& operator=(const QTransform& other); inline QTransform toQTransform(void) const; #endif + +#ifdef EIGEN_TEST_EVALUATORS + Index rows() const { return m_matrix.cols(); } + Index cols() const { return m_matrix.cols(); } +#endif /** shortcut for m_matrix(row,col); * \sa MatrixBase::operator(Index,Index) const */ diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 8864b7308..a715b8bde 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -410,44 +410,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, SparseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - -template -struct product_evaluator, ProductTag, DenseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - template struct sparse_dense_outer_product_evaluator { @@ -530,7 +492,7 @@ protected: // sparse * dense outer product template -struct product_evaluator, OuterProduct, SparseShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> +struct product_evaluator, OuterProduct, SparseShape, DenseShape, typename traits::Scalar, typename traits::Scalar> : sparse_dense_outer_product_evaluator { typedef sparse_dense_outer_product_evaluator Base; @@ -545,7 +507,7 @@ struct product_evaluator, OuterProduct, Sparse }; template -struct product_evaluator, OuterProduct, DenseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> +struct product_evaluator, OuterProduct, DenseShape, SparseShape, typename traits::Scalar, typename traits::Scalar> : sparse_dense_outer_product_evaluator { typedef sparse_dense_outer_product_evaluator Base; diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index 4c51881e0..9f465a828 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -197,11 +197,11 @@ enum { template struct sparse_diagonal_product_evaluator; -template -struct product_evaluator, ProductTag, DiagonalShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> +template +struct product_evaluator, ProductTag, DiagonalShape, SparseShape, typename traits::Scalar, typename traits::Scalar> : public sparse_diagonal_product_evaluator { - typedef Product XprType; + typedef Product XprType; typedef evaluator type; typedef evaluator nestedType; enum { CoeffReadCost = Dynamic, Flags = Rhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags @@ -210,11 +210,11 @@ struct product_evaluator, ProductTag, DiagonalShape, product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} }; -template -struct product_evaluator, ProductTag, SparseShape, DiagonalShape, typename Lhs::Scalar, typename Rhs::Scalar> +template +struct product_evaluator, ProductTag, SparseShape, DiagonalShape, typename traits::Scalar, typename traits::Scalar> : public sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> { - typedef Product XprType; + typedef Product XprType; typedef evaluator type; typedef evaluator nestedType; enum { CoeffReadCost = Dynamic, Flags = Lhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags diff --git a/Eigen/src/SparseCore/SparsePermutation.h b/Eigen/src/SparseCore/SparsePermutation.h index ebfefab98..a888ae9e1 100644 --- a/Eigen/src/SparseCore/SparsePermutation.h +++ b/Eigen/src/SparseCore/SparsePermutation.h @@ -196,6 +196,10 @@ struct generic_product_impl, SparseShape, PermutationShape, } }; +// TODO, the following two overloads are only needed to define the right temporary type through +// typename traits >::ReturnType +// while it should be correctly handled by traits >::PlainObject + template struct product_evaluator, ProductTag, PermutationShape, SparseShape, typename traits::Scalar, typename traits::Scalar> : public evaluator >::ReturnType>::type diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index 4e181d471..18f40b9d9 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -224,25 +224,6 @@ struct generic_product_impl } }; -template -struct product_evaluator, ProductTag, SparseShape, SparseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - template struct evaluator > > : public evaluator::PlainObject>::type diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 530ff27bf..4235d6c4c 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -441,46 +441,11 @@ struct generic_product_impl -struct product_evaluator, ProductTag, SparseSelfAdjointShape, DenseShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - -template -struct product_evaluator, ProductTag, DenseShape, SparseSelfAdjointShape, typename Lhs::Scalar, typename Rhs::Scalar> - : public evaluator::PlainObject>::type -{ - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; +// NOTE: these two overloads are needed to evaluate the sparse sefladjoint view into a full sparse matrix +// TODO: maybe the copy could be handled by generic_product_impl so that these overloads would not be needed anymore template -struct product_evaluator, ProductTag, SparseSelfAdjointShape, SparseShape, typename LhsView::Scalar, typename Rhs::Scalar> +struct product_evaluator, ProductTag, SparseSelfAdjointShape, SparseShape, typename traits::Scalar, typename traits::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; @@ -488,9 +453,8 @@ struct product_evaluator, ProductTag, Spar typedef typename evaluator::type Base; product_evaluator(const XprType& xpr) - : /*m_lhs(xpr.lhs()),*/ m_result(xpr.rows(), xpr.cols()) + : m_lhs(xpr.lhs()), m_result(xpr.rows(), xpr.cols()) { - m_lhs = xpr.lhs(); ::new (static_cast(this)) Base(m_result); generic_product_impl::evalTo(m_result, m_lhs, xpr.rhs()); } @@ -501,7 +465,7 @@ protected: }; template -struct product_evaluator, ProductTag, SparseShape, SparseSelfAdjointShape, typename Lhs::Scalar, typename RhsView::Scalar> +struct product_evaluator, ProductTag, SparseShape, SparseSelfAdjointShape, typename traits::Scalar, typename traits::Scalar> : public evaluator::PlainObject>::type { typedef Product XprType; diff --git a/test/main.h b/test/main.h index 57996956d..e89b5a305 100644 --- a/test/main.h +++ b/test/main.h @@ -279,13 +279,7 @@ inline bool test_isApproxOrLessThan(const long double& a, const long double& b) template inline bool test_isApprox(const Type1& a, const Type2& b) { -#ifdef EIGEN_TEST_EVALUATORS - typename internal::eval::type a_eval(a); - typename internal::eval::type b_eval(b); - return a_eval.isApprox(b_eval, test_precision()); -#else return a.isApprox(b, test_precision()); -#endif } // The idea behind this function is to compare the two scalars a and b where -- cgit v1.2.3 From 5f5a8d97c02deeab6dbf977d40170197c75adc83 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 31 Jul 2014 13:43:19 +0200 Subject: Re-enable main unit tests which are now compiling and running fine with evaluators --- test/CMakeLists.txt | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a9d0ed490..c7614e1af 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -215,32 +215,30 @@ ei_add_test(eigensolver_generalized_real) ei_add_test(jacobi) ei_add_test(jacobisvd) ei_add_test(householder) +ei_add_test(geo_orthomethods) +ei_add_test(geo_quaternion) +ei_add_test(geo_eulerangles) +ei_add_test(geo_parametrizedline) +ei_add_test(geo_alignedbox) if(NOT EIGEN_TEST_EVALUATORS) - ei_add_test(geo_orthomethods) - ei_add_test(geo_homogeneous) - ei_add_test(geo_quaternion) - ei_add_test(geo_transformations) - ei_add_test(geo_eulerangles) ei_add_test(geo_hyperplane) - ei_add_test(geo_parametrizedline) - ei_add_test(geo_alignedbox) - ei_add_test(stdvector) - ei_add_test(stdvector_overload) - ei_add_test(stdlist) - ei_add_test(stddeque) -endif(NOT EIGEN_TEST_EVALUATORS) - ei_add_test(sparse_basic) - ei_add_test(sparse_vector) - ei_add_test(sparse_product) - ei_add_test(sparse_solvers) - ei_add_test(sparse_permutations) - ei_add_test(simplicial_cholesky) - ei_add_test(conjugate_gradient) - ei_add_test(bicgstab) - ei_add_test(sparselu) - ei_add_test(sparseqr) -if(NOT EIGEN_TEST_EVALUATORS) + ei_add_test(geo_transformations) + ei_add_test(geo_homogeneous) endif(NOT EIGEN_TEST_EVALUATORS) +ei_add_test(stdvector) +ei_add_test(stdvector_overload) +ei_add_test(stdlist) +ei_add_test(stddeque) +ei_add_test(sparse_basic) +ei_add_test(sparse_vector) +ei_add_test(sparse_product) +ei_add_test(sparse_solvers) +ei_add_test(sparse_permutations) +ei_add_test(simplicial_cholesky) +ei_add_test(conjugate_gradient) +ei_add_test(bicgstab) +ei_add_test(sparselu) +ei_add_test(sparseqr) ei_add_test(umeyama) ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}") ei_add_test(zerosized) -- cgit v1.2.3 From 702a3c17db753b4ceaa234eac6591d0d1737015a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 31 Jul 2014 14:54:00 +0200 Subject: Make Transform exposes sizes: Dim+1 x Dim+1 for projective transform, and Dim x Dim+1 for all others --- Eigen/src/Geometry/Transform.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index 54d05f9cf..a62548f12 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -70,10 +70,11 @@ struct traits > typedef DenseIndex Index; typedef Dense StorageKind; enum { - RowsAtCompileTime = _Dim, - ColsAtCompileTime = _Dim, - MaxRowsAtCompileTime = _Dim, - MaxColsAtCompileTime = _Dim, + Dim1 = _Dim==Dynamic ? _Dim : _Dim + 1, + RowsAtCompileTime = _Mode==Projective ? Dim1 : _Dim, + ColsAtCompileTime = Dim1, + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, Flags = 0 }; }; @@ -374,7 +375,7 @@ public: #endif #ifdef EIGEN_TEST_EVALUATORS - Index rows() const { return m_matrix.cols(); } + Index rows() const { return Mode==Projective ? m_matrix.cols() : m_matrix.cols()-1; } Index cols() const { return m_matrix.cols(); } #endif -- cgit v1.2.3 From db183ca7b31a366fa1a870927d68c3bf6de15c4d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 31 Jul 2014 14:54:54 +0200 Subject: Make minimal changes to make homogenous compatible with evaluators --- Eigen/src/Core/util/Constants.h | 1 + Eigen/src/Geometry/Homogeneous.h | 94 +++++++++++----------------------------- test/geo_homogeneous.cpp | 3 +- 3 files changed, 27 insertions(+), 71 deletions(-) diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index c0463583d..86817a989 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -454,6 +454,7 @@ struct ArrayXpr {}; // An evaluator must define its shape. By default, it can be one of the following: struct DenseShape { static std::string debugName() { return "DenseShape"; } }; +struct HomogeneousShape { static std::string debugName() { return "HomogeneousShape"; } }; struct DiagonalShape { static std::string debugName() { return "DiagonalShape"; } }; struct BandShape { static std::string debugName() { return "BandShape"; } }; struct TriangularShape { static std::string debugName() { return "TriangularShape"; } }; diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 07bc22154..7a3b5de80 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -332,6 +332,18 @@ struct homogeneous_right_product_impl,Rhs> }; #ifdef EIGEN_TEST_EVALUATORS + +template +struct evaluator_traits > +{ + typedef typename storage_kind_to_evaluator_kind::Kind Kind; + typedef HomogeneousShape Shape; + static const int AssumeAliasing = 0; +}; + +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + + template struct unary_evaluator, IndexBased> : evaluator::PlainObject >::type @@ -355,10 +367,13 @@ template< typename DstXprType, typename ArgType, typename Scalar> struct Assignment, internal::assign_op, Dense2Dense, Scalar> { typedef Homogeneous SrcXprType; + // TODO clang generates garbage if this function is inlined. no valgrind error though. +#ifdef __clang__ + EIGEN_DONT_INLINE +#endif static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { dst.template topRows(src.nestedExpression().rows()) = src.nestedExpression(); -// dst.topRows(src.nestedExpression().rows()) = src.nestedExpression(); dst.row(dst.rows()-1).setOnes(); } }; @@ -368,16 +383,19 @@ template< typename DstXprType, typename ArgType, typename Scalar> struct Assignment, internal::assign_op, Dense2Dense, Scalar> { typedef Homogeneous SrcXprType; + // TODO clang generates garbage if this function is inlined. no valgrind error though. +#ifdef __clang__ + EIGEN_DONT_INLINE +#endif static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { dst.template leftCols(src.nestedExpression().cols()) = src.nestedExpression(); -// dst.leftCols(src.nestedExpression().cols()) = src.nestedExpression(); dst.col(dst.cols()-1).setOnes(); } }; template -struct generic_product_impl, Rhs, DenseShape, DenseShape, ProductTag> +struct generic_product_impl, Rhs, HomogeneousShape, DenseShape, ProductTag> { template static void evalTo(Dest& dst, const Homogeneous& lhs, const Rhs& rhs) @@ -387,86 +405,24 @@ struct generic_product_impl, Rhs, DenseShape, Den }; template -struct generic_product_impl, DenseShape, DenseShape, ProductTag> +struct generic_product_impl, DenseShape, HomogeneousShape, ProductTag> { template static void evalTo(Dest& dst, const Lhs& lhs, const Homogeneous& rhs) { - homogeneous_left_product_impl, Lhs>(rhs.nestedExpression(), lhs).evalTo(dst); + homogeneous_left_product_impl, Lhs>(lhs, rhs.nestedExpression()).evalTo(dst); } }; template -struct generic_product_impl, Homogeneous, DenseShape, DenseShape, ProductTag> +struct generic_product_impl, Homogeneous, DenseShape, HomogeneousShape, ProductTag> { typedef Transform TransformType; template static void evalTo(Dest& dst, const TransformType& lhs, const Homogeneous& rhs) { - homogeneous_left_product_impl, TransformType>(rhs.nestedExpression(), lhs).evalTo(dst); - } -}; - - -template -struct product_evaluator, Rhs, DefaultProduct>, ProductTag, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar> - : public evaluator, Rhs, DefaultProduct>::PlainObject>::type -{ - typedef Homogeneous Lhs; - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - -template -struct product_evaluator, DefaultProduct>, ProductTag, DenseShape, DenseShape, typename traits::Scalar, typename traits::Scalar> - : public evaluator, DefaultProduct>::PlainObject>::type -{ - typedef Homogeneous Rhs; - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); - } - -protected: - PlainObject m_result; -}; - -template -struct product_evaluator, Homogeneous, DefaultProduct>, ProductTag, DenseShape, DenseShape, Scalar, typename traits::Scalar> - : public evaluator, Homogeneous, DefaultProduct>::PlainObject>::type -{ - typedef Transform Lhs; - typedef Homogeneous Rhs; - typedef Product XprType; - typedef typename XprType::PlainObject PlainObject; - typedef typename evaluator::type Base; - - product_evaluator(const XprType& xpr) - : m_result(xpr.rows(), xpr.cols()) - { - ::new (static_cast(this)) Base(m_result); - generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + homogeneous_left_product_impl, TransformType>(lhs, rhs.nestedExpression()).evalTo(dst); } - -protected: - PlainObject m_result; }; #endif // EIGEN_TEST_EVALUATORS diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp index c91bde819..078894035 100644 --- a/test/geo_homogeneous.cpp +++ b/test/geo_homogeneous.cpp @@ -57,7 +57,6 @@ template void homogeneous(void) VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t2, v0.transpose().rowwise().homogeneous() * t2); - m0.transpose().rowwise().homogeneous().eval(); VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t2, m0.transpose().rowwise().homogeneous() * t2); @@ -82,7 +81,7 @@ template void homogeneous(void) VERIFY_IS_APPROX(aff * pts.colwise().homogeneous(), (aff * pts1).colwise().hnormalized()); VERIFY_IS_APPROX(caff * pts.colwise().homogeneous(), (caff * pts1).colwise().hnormalized()); VERIFY_IS_APPROX(proj * pts.colwise().homogeneous(), (proj * pts1)); - + VERIFY_IS_APPROX((aff * pts1).colwise().hnormalized(), aff * pts); VERIFY_IS_APPROX((caff * pts1).colwise().hnormalized(), caff * pts); -- cgit v1.2.3 From 26d2cdefd4dc291ba6613d5fd4127f6f1a6b5fa1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 31 Jul 2014 16:24:29 +0200 Subject: Fix 4x4 inverse via SSE for submatrices --- Eigen/src/LU/arch/Inverse_SSE.h | 11 ++++++++--- test/CMakeLists.txt | 8 +++----- test/inverse.cpp | 8 ++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Eigen/src/LU/arch/Inverse_SSE.h b/Eigen/src/LU/arch/Inverse_SSE.h index 60b7a2376..1f62ef14e 100644 --- a/Eigen/src/LU/arch/Inverse_SSE.h +++ b/Eigen/src/LU/arch/Inverse_SSE.h @@ -39,9 +39,11 @@ struct compute_inverse_size4 ResultAlignment = bool(ResultType::Flags&AlignedBit), StorageOrdersMatch = (MatrixType::Flags&RowMajorBit) == (ResultType::Flags&RowMajorBit) }; + typedef typename conditional<(MatrixType::Flags&LinearAccessBit),MatrixType const &,typename MatrixType::PlainObject>::type ActualMatrixType; - static void run(const MatrixType& matrix, ResultType& result) + static void run(const MatrixType& mat, ResultType& result) { + ActualMatrixType matrix(mat); EIGEN_ALIGN16 const unsigned int _Sign_PNNP[4] = { 0x00000000, 0x80000000, 0x80000000, 0x00000000 }; // Load the full matrix into registers @@ -167,14 +169,17 @@ struct compute_inverse_size4 ResultAlignment = bool(ResultType::Flags&AlignedBit), StorageOrdersMatch = (MatrixType::Flags&RowMajorBit) == (ResultType::Flags&RowMajorBit) }; - static void run(const MatrixType& matrix, ResultType& result) + typedef typename conditional<(MatrixType::Flags&LinearAccessBit),MatrixType const &,typename MatrixType::PlainObject>::type ActualMatrixType; + + static void run(const MatrixType& mat, ResultType& result) { + ActualMatrixType matrix(mat); const __m128d _Sign_NP = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0)); const __m128d _Sign_PN = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0)); // The inverse is calculated using "Divide and Conquer" technique. The // original matrix is divide into four 2x2 sub-matrices. Since each - // register of the matrix holds two element, the smaller matrices are + // register of the matrix holds two elements, the smaller matrices are // consisted of two registers. Hence we get a better locality of the // calculations. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c7614e1af..000d16c45 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -220,11 +220,9 @@ ei_add_test(geo_quaternion) ei_add_test(geo_eulerangles) ei_add_test(geo_parametrizedline) ei_add_test(geo_alignedbox) -if(NOT EIGEN_TEST_EVALUATORS) - ei_add_test(geo_hyperplane) - ei_add_test(geo_transformations) - ei_add_test(geo_homogeneous) -endif(NOT EIGEN_TEST_EVALUATORS) +ei_add_test(geo_hyperplane) +ei_add_test(geo_transformations) +ei_add_test(geo_homogeneous) ei_add_test(stdvector) ei_add_test(stdvector_overload) ei_add_test(stdlist) diff --git a/test/inverse.cpp b/test/inverse.cpp index 8187b088d..1195bcc76 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -68,6 +68,14 @@ template void inverse(const MatrixType& m) VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1)); m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); + + // check with submatrices + { + Matrix m3; + m3.setRandom(); + m2 = m3.template topLeftCorner().inverse(); + VERIFY_IS_APPROX( (m3.template topLeftCorner()), m2.inverse() ); + } #endif // check in-place inversion -- cgit v1.2.3 From fc13b37c552c6661c81f135cf94edc3de09d2000 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 14:47:33 +0200 Subject: Make cross product uses nested/nested_eval --- Eigen/src/Geometry/OrthoMethods.h | 30 ++++++++++++++++++++++++------ test/geo_orthomethods.cpp | 9 +++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Geometry/OrthoMethods.h b/Eigen/src/Geometry/OrthoMethods.h index 26be3ee5b..98e7a9bfc 100644 --- a/Eigen/src/Geometry/OrthoMethods.h +++ b/Eigen/src/Geometry/OrthoMethods.h @@ -30,8 +30,13 @@ MatrixBase::cross(const MatrixBase& other) const // Note that there is no need for an expression here since the compiler // optimize such a small temporary very well (even within a complex expression) +#ifndef EIGEN_TEST_EVALUATORS typename internal::nested::type lhs(derived()); typename internal::nested::type rhs(other.derived()); +#else + typename internal::nested_eval::type lhs(derived()); + typename internal::nested_eval::type rhs(other.derived()); +#endif return typename cross_product_return_type::type( numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)), numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)), @@ -76,8 +81,13 @@ MatrixBase::cross3(const MatrixBase& other) const EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,4) EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,4) +#ifndef EIGEN_TEST_EVALUATORS typedef typename internal::nested::type DerivedNested; typedef typename internal::nested::type OtherDerivedNested; +#else + typedef typename internal::nested_eval::type DerivedNested; + typedef typename internal::nested_eval::type OtherDerivedNested; +#endif DerivedNested lhs(derived()); OtherDerivedNested rhs(other.derived()); @@ -103,21 +113,29 @@ VectorwiseOp::cross(const MatrixBase& ot EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3) EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + +#ifndef EIGEN_TEST_EVALUATORS + typename internal::nested::type mat(_expression()); + typename internal::nested::type vec(other.derived()); +#else + typename internal::nested_eval::type mat(_expression()); + typename internal::nested_eval::type vec(other.derived()); +#endif CrossReturnType res(_expression().rows(),_expression().cols()); if(Direction==Vertical) { eigen_assert(CrossReturnType::RowsAtCompileTime==3 && "the matrix must have exactly 3 rows"); - res.row(0) = (_expression().row(1) * other.coeff(2) - _expression().row(2) * other.coeff(1)).conjugate(); - res.row(1) = (_expression().row(2) * other.coeff(0) - _expression().row(0) * other.coeff(2)).conjugate(); - res.row(2) = (_expression().row(0) * other.coeff(1) - _expression().row(1) * other.coeff(0)).conjugate(); + res.row(0) = (mat.row(1) * vec.coeff(2) - mat.row(2) * vec.coeff(1)).conjugate(); + res.row(1) = (mat.row(2) * vec.coeff(0) - mat.row(0) * vec.coeff(2)).conjugate(); + res.row(2) = (mat.row(0) * vec.coeff(1) - mat.row(1) * vec.coeff(0)).conjugate(); } else { eigen_assert(CrossReturnType::ColsAtCompileTime==3 && "the matrix must have exactly 3 columns"); - res.col(0) = (_expression().col(1) * other.coeff(2) - _expression().col(2) * other.coeff(1)).conjugate(); - res.col(1) = (_expression().col(2) * other.coeff(0) - _expression().col(0) * other.coeff(2)).conjugate(); - res.col(2) = (_expression().col(0) * other.coeff(1) - _expression().col(1) * other.coeff(0)).conjugate(); + res.col(0) = (mat.col(1) * vec.coeff(2) - mat.col(2) * vec.coeff(1)).conjugate(); + res.col(1) = (mat.col(2) * vec.coeff(0) - mat.col(0) * vec.coeff(2)).conjugate(); + res.col(2) = (mat.col(0) * vec.coeff(1) - mat.col(1) * vec.coeff(0)).conjugate(); } return res; } diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp index c836dae40..2b50c16e7 100644 --- a/test/geo_orthomethods.cpp +++ b/test/geo_orthomethods.cpp @@ -33,6 +33,7 @@ template void orthomethods_3() VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1)); VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1)); VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1)); Matrix3 mat3; mat3 << v0.normalized(), (v0.cross(v1)).normalized(), @@ -47,6 +48,13 @@ template void orthomethods_3() int i = internal::random(0,2); mcross = mat3.colwise().cross(vec3); VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3)); + + VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1)); + + VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + mcross = mat3.rowwise().cross(vec3); VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3)); @@ -57,6 +65,7 @@ template void orthomethods_3() v40.w() = v41.w() = v42.w() = 0; v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>()); VERIFY_IS_APPROX(v40.cross3(v41), v42); + VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1)); // check mixed product typedef Matrix RealVector3; -- cgit v1.2.3 From 2a3c3c49a19572b544b22820065c673cfac9bc04 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 14:48:22 +0200 Subject: Fix numerous nested versus nested_eval shortcomings --- Eigen/src/Core/Dot.h | 5 +++++ Eigen/src/Geometry/AlignedBox.h | 4 ++++ Eigen/src/LU/InverseImpl.h | 4 ++++ test/CMakeLists.txt | 4 ---- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index d18b0099a..d6441c6a5 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -211,8 +211,13 @@ template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { +#ifndef EIGEN_TEST_EVALUATORS typename internal::nested::type nested(derived()); typename internal::nested::type otherNested(other.derived()); +#else + typename internal::nested_eval::type nested(derived()); + typename internal::nested_eval::type otherNested(other.derived()); +#endif return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index b6a2f0e24..1d1daaa61 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -71,7 +71,11 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) template inline explicit AlignedBox(const MatrixBase& a_p) { +#ifndef EIGEN_TEST_EVALUATORS typename internal::nested::type p(a_p.derived()); +#else + typename internal::nested_eval::type p(a_p.derived()); +#endif m_min = p; m_max = p; } diff --git a/Eigen/src/LU/InverseImpl.h b/Eigen/src/LU/InverseImpl.h index 174dfbac5..e10fee48f 100644 --- a/Eigen/src/LU/InverseImpl.h +++ b/Eigen/src/LU/InverseImpl.h @@ -422,7 +422,11 @@ inline void MatrixBase::computeInverseAndDetWithCheck( // for larger sizes, evaluating has negligible cost and limits code size. typedef typename internal::conditional< RowsAtCompileTime == 2, +#ifndef EIGEN_TEST_EVALUATORS typename internal::remove_all::type>::type, +#else + typename internal::remove_all::type>::type, +#endif PlainObject >::type MatrixType; internal::compute_inverse_and_det_with_check::run diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 000d16c45..7555aaa38 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -251,8 +251,6 @@ ei_add_test(dense_storage) # # ei_add_test(denseLM) -if(NOT EIGEN_TEST_EVALUATORS) - if(QT4_FOUND) ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}") endif(QT4_FOUND) @@ -285,8 +283,6 @@ if(METIS_FOUND) ei_add_test(metis_support "" "${METIS_LIBRARIES}") endif() -endif(NOT EIGEN_TEST_EVALUATORS) - string(TOLOWER "${CMAKE_CXX_COMPILER}" cmake_cxx_compiler_tolower) if(cmake_cxx_compiler_tolower MATCHES "qcc") set(CXX_IS_QCC "ON") -- cgit v1.2.3 From c2ff44cbf3c58045a38120d28316a992c0cc0d57 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 16:23:30 +0200 Subject: Make assignment from general EigenBase object call evaluator, and support dense X= sparse --- Eigen/src/Core/EigenBase.h | 12 ++++++++++++ Eigen/src/SparseCore/SparseAssign.h | 25 +++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/EigenBase.h b/Eigen/src/Core/EigenBase.h index 1a577c2dc..986e2a196 100644 --- a/Eigen/src/Core/EigenBase.h +++ b/Eigen/src/Core/EigenBase.h @@ -121,7 +121,11 @@ template template Derived& DenseBase::operator=(const EigenBase &other) { +#ifndef EIGEN_TEST_EVALUATORS other.derived().evalTo(derived()); +#else + call_assignment(derived(), other.derived()); +#endif return derived(); } @@ -129,7 +133,11 @@ template template Derived& DenseBase::operator+=(const EigenBase &other) { +#ifndef EIGEN_TEST_EVALUATORS other.derived().addTo(derived()); +#else + call_assignment(derived(), other.derived(), internal::add_assign_op()); +#endif return derived(); } @@ -137,7 +145,11 @@ template template Derived& DenseBase::operator-=(const EigenBase &other) { +#ifndef EIGEN_TEST_EVALUATORS other.derived().subTo(derived()); +#else + call_assignment(derived(), other.derived(), internal::sub_assign_op()); +#endif return derived(); } diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index c2091ee49..0a29cb32f 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -172,9 +172,9 @@ struct storage_kind_to_shape { struct Sparse2Sparse {}; struct Sparse2Dense {}; -template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; -template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; -template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Sparse Kind; }; +template<> struct AssignmentKind { typedef Sparse2Dense Kind; }; template @@ -252,7 +252,24 @@ struct Assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + typedef typename SrcXprType::Index Index; + + typename internal::evaluator::type srcEval(src); + typename internal::evaluator::type dstEval(dst); + const Index outerEvaluationSize = (internal::evaluator::Flags&RowMajorBit) ? src.rows() : src.cols(); + for (Index j=0; j::InnerIterator i(srcEval,j); i; ++i) + func.assignCoeff(dstEval.coeffRef(i.row(),i.col()), i.value()); + } +}; + +template< typename DstXprType, typename SrcXprType, typename Scalar> +struct Assignment, Sparse2Dense, Scalar> +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); typedef typename SrcXprType::Index Index; -- cgit v1.2.3 From 107bb308c376a5a4b7f11f2792396d2fa0d12904 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 16:24:23 +0200 Subject: Fix various small issues detected by gcc --- Eigen/src/Core/CoreEvaluators.h | 2 +- Eigen/src/Geometry/Transform.h | 2 +- Eigen/src/SparseCore/SparseBlock.h | 6 +++--- Eigen/src/SparseCore/SparseTriangularView.h | 2 +- Eigen/src/SparseQR/SparseQR.h | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 66984e378..8c9190a0e 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -965,7 +965,7 @@ struct evaluator > typedef PartialReduxExpr XprType; typedef typename XprType::Scalar InputScalar; enum { - TraversalSize = Direction==Vertical ? ArgType::RowsAtCompileTime : XprType::ColsAtCompileTime + TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(XprType::ColsAtCompileTime) }; typedef typename MemberOp::template Cost CostOpType; enum { diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index a62548f12..bcf3e2723 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -375,7 +375,7 @@ public: #endif #ifdef EIGEN_TEST_EVALUATORS - Index rows() const { return Mode==Projective ? m_matrix.cols() : m_matrix.cols()-1; } + Index rows() const { return int(Mode)==int(Projective) ? m_matrix.cols() : (m_matrix.cols()-1); } Index cols() const { return m_matrix.cols(); } #endif diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h index 39e636437..21445b645 100644 --- a/Eigen/src/SparseCore/SparseBlock.h +++ b/Eigen/src/SparseCore/SparseBlock.h @@ -577,7 +577,7 @@ namespace internal { #ifdef EIGEN_TEST_EVALUATORS // -template +template struct unary_evaluator, IteratorBased > : public evaluator_base > { @@ -615,7 +615,7 @@ struct unary_evaluator, IteratorBa const XprType &m_block; }; -template +template class unary_evaluator, IteratorBased>::InnerVectorInnerIterator : public EvalIterator { @@ -640,7 +640,7 @@ public: inline operator bool() const { return EvalIterator::operator bool() && EvalIterator::index() < m_end; } }; -template +template class unary_evaluator, IteratorBased>::OuterVectorInnerIterator { const unary_evaluator& m_eval; diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 7586a0a6e..87f4ab18d 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -200,7 +200,7 @@ public: public: EIGEN_STRONG_INLINE InnerIterator(const unary_evaluator& xprEval, Index outer) - : Base(xprEval.m_argImpl,outer) + : Base(xprEval.m_argImpl,outer), m_returnOne(false) { if(SkipFirst) { diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 4c6553bf2..e8d7b8607 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -178,7 +178,7 @@ class SparseQR y.resize((std::max)(cols(),Index(y.rows())),y.cols()); y.topRows(rank) = this->matrixR().topLeftCorner(rank, rank).template triangularView().solve(b.topRows(rank)); y.bottomRows(y.rows()-rank).setZero(); - + // Apply the column permutation if (m_perm_c.size()) dest = colsPermutation() * y.topRows(cols()); else dest = y.topRows(cols()); @@ -447,7 +447,7 @@ void SparseQR::factorize(const MatrixType& mat) } } // End update current column - Scalar tau; + Scalar tau = 0; RealScalar beta = 0; if(nonzeroCol < diagSize) -- cgit v1.2.3 From 51357a6622d30aa8cb799cf2ed69c96cf94007b7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 16:26:23 +0200 Subject: Fix geo_orthomethods unit test for complexes --- test/geo_orthomethods.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp index 2b50c16e7..7f8beb205 100644 --- a/test/geo_orthomethods.cpp +++ b/test/geo_orthomethods.cpp @@ -49,11 +49,11 @@ template void orthomethods_3() mcross = mat3.colwise().cross(vec3); VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3)); - VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1)); - VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1)); - VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); - VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); mcross = mat3.rowwise().cross(vec3); VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3)); -- cgit v1.2.3 From f25338f4d76dff13a9810996165ad7b465a15c88 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 16:49:44 +0200 Subject: Fix nesting of Homogenous evaluator --- Eigen/src/Geometry/Homogeneous.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 7a3b5de80..8f3e5f419 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -351,6 +351,9 @@ struct unary_evaluator, IndexBased> typedef Homogeneous XprType; typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; unary_evaluator(const XprType& op) : Base(), m_temp(op) @@ -367,10 +370,6 @@ template< typename DstXprType, typename ArgType, typename Scalar> struct Assignment, internal::assign_op, Dense2Dense, Scalar> { typedef Homogeneous SrcXprType; - // TODO clang generates garbage if this function is inlined. no valgrind error though. -#ifdef __clang__ - EIGEN_DONT_INLINE -#endif static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { dst.template topRows(src.nestedExpression().rows()) = src.nestedExpression(); @@ -383,10 +382,6 @@ template< typename DstXprType, typename ArgType, typename Scalar> struct Assignment, internal::assign_op, Dense2Dense, Scalar> { typedef Homogeneous SrcXprType; - // TODO clang generates garbage if this function is inlined. no valgrind error though. -#ifdef __clang__ - EIGEN_DONT_INLINE -#endif static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { dst.template leftCols(src.nestedExpression().cols()) = src.nestedExpression(); -- cgit v1.2.3 From 4dd55a2958318f295cfc050563dedfe5dca384f0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 1 Aug 2014 17:00:20 +0200 Subject: Optimize reduxions for Homogeneous --- Eigen/src/Core/Redux.h | 10 +++++----- Eigen/src/Geometry/Homogeneous.h | 7 +++++++ test/geo_homogeneous.cpp | 4 ++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 136cd165e..438ad018a 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -449,7 +449,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { - return this->redux(Eigen::internal::scalar_min_op()); + return derived().redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of \c *this. @@ -459,7 +459,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { - return this->redux(Eigen::internal::scalar_max_op()); + return derived().redux(Eigen::internal::scalar_max_op()); } /** \returns the sum of all coefficients of *this @@ -472,7 +472,7 @@ DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); - return this->redux(Eigen::internal::scalar_sum_op()); + return derived().redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this @@ -483,7 +483,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { - return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); + return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); } /** \returns the product of all coefficients of *this @@ -499,7 +499,7 @@ DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); - return this->redux(Eigen::internal::scalar_product_op()); + return derived().redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 8f3e5f419..96909bb7e 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -138,6 +138,13 @@ template class Homogeneous } #endif + template + EIGEN_STRONG_INLINE typename internal::result_of::type + redux(const Func& func) const + { + return func(m_matrix.redux(func), Scalar(1)); + } + protected: typename MatrixType::Nested m_matrix; }; diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp index 078894035..2f9d18c0f 100644 --- a/test/geo_homogeneous.cpp +++ b/test/geo_homogeneous.cpp @@ -38,6 +38,10 @@ template void homogeneous(void) hv0 << v0, 1; VERIFY_IS_APPROX(v0.homogeneous(), hv0); VERIFY_IS_APPROX(v0, hv0.hnormalized()); + + VERIFY_IS_APPROX(v0.homogeneous().sum(), hv0.sum()); + VERIFY_IS_APPROX(v0.homogeneous().minCoeff(), hv0.minCoeff()); + VERIFY_IS_APPROX(v0.homogeneous().maxCoeff(), hv0.maxCoeff()); hm0 << m0, ones.transpose(); VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0); -- cgit v1.2.3 From f29dbec321617d46287c4415889c4485ad70bea3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Aug 2014 15:12:03 +0200 Subject: undef Unsable macro --- Eigen/src/Core/ReturnByValue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index f15601d99..9d53fba27 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -81,6 +81,7 @@ template class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } +#undef Unusable #endif }; -- cgit v1.2.3 From c1d0f15bde4614c3efb84248e5d2ceb9cb995779 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 29 Aug 2014 15:31:32 +0200 Subject: Enable evaluators by default --- Eigen/Core | 11 +++++++---- test/CMakeLists.txt | 8 ++++---- test/evaluators.cpp | 4 ++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 239bc6990..47c4f6299 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -12,10 +12,13 @@ #define EIGEN_CORE_H // EIGEN_TEST_EVALUATORS => EIGEN_ENABLE_EVALUATORS -#ifdef EIGEN_TEST_EVALUATORS -#ifndef EIGEN_ENABLE_EVALUATORS -#define EIGEN_ENABLE_EVALUATORS -#endif +#ifndef EIGEN_TEST_NO_EVALUATORS + #ifndef EIGEN_TEST_EVALUATORS + #define EIGEN_TEST_EVALUATORS + #endif + #ifndef EIGEN_ENABLE_EVALUATORS + #define EIGEN_ENABLE_EVALUATORS + #endif #endif // first thing Eigen does: stop the compiler from committing suicide diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6446b8bb0..075b8d3de 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -139,10 +139,10 @@ endif(TEST_LIB) set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official") add_custom_target(BuildOfficial) -option(EIGEN_TEST_EVALUATORS "Enable work in progress evaluators" OFF) -if(EIGEN_TEST_EVALUATORS) - add_definitions("-DEIGEN_TEST_EVALUATORS=1") -endif(EIGEN_TEST_EVALUATORS) +option(EIGEN_TEST_NO_EVALUATORS "Disable evaluators in unit tests" OFF) +if(EIGEN_TEST_NO_EVALUATORS) + add_definitions("-DEIGEN_TEST_NO_EVALUATORS=1") +endif(EIGEN_TEST_NO_EVALUATORS) ei_add_test(meta) ei_add_test(sizeof) diff --git a/test/evaluators.cpp b/test/evaluators.cpp index 305047a6a..2ca453b1c 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -7,6 +7,10 @@ #undef EIGEN_TEST_EVALUATORS #endif +#ifdef EIGEN_TEST_NO_EVALUATORS +#undef EIGEN_TEST_NO_EVALUATORS +#endif + #include "main.h" namespace Eigen { -- cgit v1.2.3 From 7ff266e3ce592ec1a6284cf16811965eec775f25 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Fri, 29 Aug 2014 20:03:49 +0000 Subject: Initial VSX commit --- CMakeLists.txt | 6 + Eigen/Core | 17 +- Eigen/src/Core/arch/AltiVec/Complex.h | 186 ++++++++++++++++++++++ Eigen/src/Core/arch/AltiVec/PacketMath.h | 66 +++++++- Eigen/src/Core/products/GeneralBlockPanelKernel.h | 4 +- Eigen/src/Core/util/Constants.h | 6 + bench/btl/libs/eigen2/eigen2_interface.hh | 2 +- cmake/EigenTesting.cmake | 6 + test/main.h | 2 +- test/packetmath.cpp | 2 +- 10 files changed, 285 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96d6c8701..ea42cc8db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,12 @@ if(NOT MSVC) message(STATUS "Enabling AltiVec in tests/examples") endif() + option(EIGEN_TEST_VSX "Enable/Disable VSX in tests/examples" OFF) + if(EIGEN_TEST_VSX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mvsx") + message(STATUS "Enabling VSX in tests/examples") + endif() + option(EIGEN_TEST_NEON "Enable/Disable Neon in tests/examples" OFF) if(EIGEN_TEST_NEON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -mcpu=cortex-a8") diff --git a/Eigen/Core b/Eigen/Core index 776b7faf3..8ea165d5b 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -171,6 +171,15 @@ #undef bool #undef vector #undef pixel + #elif defined __VSX__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_VSX + #include + // We need to #undef all these ugly tokens defined in + // => use __vector instead of vector + #undef bool + #undef vector + #undef pixel #elif defined __ARM_NEON__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON @@ -235,6 +244,8 @@ inline static const char *SimdInstructionSetsInUse(void) { return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; +#elif defined(EIGEN_VECTORIZE_VSX) + return "VSX"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; #else @@ -286,8 +297,12 @@ using std::ptrdiff_t; #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" -#elif defined EIGEN_VECTORIZE_ALTIVEC +#elif defined(EIGEN_VECTORIZE_ALTIVEC) + #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/Complex.h" +#elif defined(EIGEN_VECTORIZE_ALTIVEC) #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/VSX.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 13b874d0c..064341a3b 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -14,7 +14,13 @@ namespace Eigen { namespace internal { +#ifdef _BIG_ENDIAN static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; +#else +static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4f_ZERO_, (Packet4ui)p4i_ZERO);//{ 0x80000000, 0x00000000, 0x80000000, 0x00000000 }; +static Packet2ul p2ul_CONJ_XOR = (Packet2ul) vec_sld((Packet4ui)p2d_ZERO_, (Packet4ui)p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +#endif + static Packet16uc p16uc_COMPLEX_RE = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; static Packet16uc p16uc_COMPLEX_IM = vec_sld(p16uc_DUPLICATE, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; static Packet16uc p16uc_COMPLEX_REV = vec_sld(p16uc_REVERSE, p16uc_REVERSE, 8);//{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; @@ -237,6 +243,186 @@ EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) kernel.packet[0].v = tmp; } +//---------- double ---------- +struct Packet1cd +{ + EIGEN_STRONG_INLINE Packet1cd() {} + EIGEN_STRONG_INLINE explicit Packet1cd(const Packet2d& a) : v(a) {} + Packet2d v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet1cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 0, + size = 1, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=1}; typedef Packet1cd half; }; + +template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_add(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_sub(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2ul)a.v, p2ul_CONJ_XOR)); } + +template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) +{ + Packet2d v1, v2; + + // Permute and multiply the real parts of a and b + v1 = vec_perm(a.v, a.v, p16uc_COMPLEX_RE); + // Get the imaginary parts of a + v2 = vec_perm(a.v, a.v, p16uc_COMPLEX_IM); + // multiply a_re * b + v1 = vec_madd(v1, b.v, p4f_ZERO); + // multiply a_im * b and get the conjugate result + v2 = vec_madd(v2, b.v, p4f_ZERO); + v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); + // permute back to a proper order + v2 = vec_perm(v2, v2, p16uc_COMPLEX_REV); + + return Packet2cf(vec_add(v1, v2)); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_or(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_xor(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v, vec_nor(b.v,b.v))); } + +template<> EIGEN_STRONG_INLINE Packet1cd pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } + +template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) +{ + return pset1(*from); +} + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { vec_dstt((double *)addr, DST_CTRL(2,2,32), DST_CHAN); } + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) +{ + std::complex EIGEN_ALIGN16 res[2]; + pstore((float *)&res, a.v); + + return res[0]; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) +{ + Packet2d rev_a; + rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX_REV2); + return Packet1cd(rev_a); +} + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) +{ + Packet2d b; + b = (Packet2d) vec_sld(a.v, a.v, 8); + b = padd(a.v, b); + return pfirst(Packet1cd(b)); +} + +template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) +{ + Packet2d b1, b2; + + b1 = (Packet2d) vec_sld(vecs[0].v, vecs[1].v, 8); + b2 = (Packet2d) vec_sld(vecs[1].v, vecs[0].v, 8); + b2 = (Packet2d) vec_sld(b2, b2, 8); + b2 = padd(b1, b2); + + return Packet1cd(b2); +} + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) +{ + Packet2d b; + Packet1cd prod; + b = (Packet2d) vec_sld(a.v, a.v, 8); + prod = pmul(a, Packet1cd(b)); + + return pfirst(prod); +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet1cd& first, const Packet1cd& second) + { } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) +{ + // TODO optimize it for AltiVec + Packet1cd res = conj_helper().pmul(a,b); + Packet2d s = vec_madd(b.v, b.v, p4f_ZERO); + return Packet1cd(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pcplxflip(const Packet1cd& x) +{ + return Packet1cd(vec_perm(x.v, x.v, p16uc_COMPLEX_REV)); +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet2d tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_0); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_1); + kernel.packet[0].v = tmp; +} + } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index b43e8ace3..e70039ae2 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -31,6 +31,12 @@ namespace internal { #define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 #endif +#ifdef __VSX__ +typedef __vector double Packet2d; +typedef __vector unsigned long Packet2ul; +typedef __vector long Packet2l; +#endif // __VSX__ + typedef __vector float Packet4f; typedef __vector int Packet4i; typedef __vector unsigned int Packet4ui; @@ -50,22 +56,37 @@ typedef __vector unsigned char Packet16uc; #define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ Packet4f p4f_##NAME = pset1(X) -#define _EIGEN_DECLARE_CONST_Packet4f_FROM_INT(NAME,X) \ - Packet4f p4f_##NAME = vreinterpretq_f32_u32(pset1(X)) - #define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \ Packet4i p4i_##NAME = pset1(X) +#define _EIGEN_DECLARE_CONST_Packet2d(NAME,X) \ + Packet2d p2d_##NAME = pset1(X) + +#define _EIGEN_DECLARE_CONST_Packet2l(NAME,X) \ + Packet2l p2l_##NAME = pset1(X) + #define DST_CHAN 1 #define DST_CTRL(size, count, stride) (((size) << 24) | ((count) << 16) | (stride)) +// Handle endianness properly while loading constants // Define global static constants: +#ifdef _BIG_ENDIAN static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; static Packet16uc p16uc_REVERSE = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); //{ 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15} static Packet16uc p16uc_DUPLICATE = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7}; - +#else +static Packet4f p4f_COUNTDOWN = { 3.0, 2.0, 1.0, 0.0 }; +static Packet4i p4i_COUNTDOWN = { 3, 2, 1, 0 }; +static Packet16uc p16uc_REVERSE = { 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15 }; +static Packet16uc p16uc_FORWARD = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; +static Packet16uc p16uc_DUPLICATE = { 4,5,6,7, 4,5,6,7, 0,1,2,3, 0,1,2,3 }; +static Packet2d p2d_ZERO_ = (Packet2d) { 0x8000000000000000, 0x8000000000000000 }; +static Packet2l p2l_ZERO = (Packet2l) { 0x0, 0x0 }; +#endif // _BIG_ENDIAN + +// These constants are endian-agnostic static _EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); //{ 0.0, 0.0, 0.0, 0.0} static _EIGEN_DECLARE_CONST_FAST_Packet4i(ZERO, 0); //{ 0, 0, 0, 0,} static _EIGEN_DECLARE_CONST_FAST_Packet4i(ONE,1); //{ 1, 1, 1, 1} @@ -93,6 +114,24 @@ template<> struct packet_traits : default_packet_traits HasSqrt = 0 }; }; +#ifdef __VSX__ +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 0, + + HasDiv = 1, + HasExp = 0, + HasSqrt = 0 + }; +}; +#endif // __VSX__ + template<> struct packet_traits : default_packet_traits { typedef Packet4i type; @@ -105,6 +144,10 @@ template<> struct packet_traits : default_packet_traits }; }; +#ifdef __VSX__ +template<> struct unpacket_traits { typedef double type; enum {size=2}; typedef Packet2d half; }; +#endif // __VSX__ + template<> struct unpacket_traits { typedef float type; enum {size=4}; typedef Packet4f half; }; template<> struct unpacket_traits { typedef int type; enum {size=4}; typedef Packet4i half; }; /* @@ -311,7 +354,6 @@ template<> EIGEN_STRONG_INLINE Packet4i pmin(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pmax(const Packet4f& a, const Packet4f& b) { return vec_max(a, b); } template<> EIGEN_STRONG_INLINE Packet4i pmax(const Packet4i& a, const Packet4i& b) { return vec_max(a, b); } -// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics template<> EIGEN_STRONG_INLINE Packet4f pand(const Packet4f& a, const Packet4f& b) { return vec_and(a, b); } template<> EIGEN_STRONG_INLINE Packet4i pand(const Packet4i& a, const Packet4i& b) { return vec_and(a, b); } @@ -327,10 +369,10 @@ template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, con template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } +#ifndef __VSX__ template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html Packet16uc MSQ, LSQ; Packet16uc mask; MSQ = vec_ld(0, (unsigned char *)from); // most significant quadword @@ -350,6 +392,18 @@ template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) mask = vec_lvsl(0, from); // create the permute mask return (Packet4i) vec_perm(MSQ, LSQ, mask); // align the data } +#else +template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD + return (Packet4i) vec_vsx_ld((long)from & 15, from); // align the data +} +template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD + return (Packet4f) vec_vsx_ld((long)from & 15, from); // align the data +} +#endif template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) { diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index 7da52c2e8..7b2ed6728 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -182,7 +182,7 @@ public: nr = 4, // register block size along the M direction (currently, this one cannot be modified) -#if defined(EIGEN_HAS_FUSED_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) +#if defined(EIGEN_HAS_FUSED_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX) // we assume 16 registers mr = 3*LhsPacketSize, #else @@ -290,7 +290,7 @@ public: NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS, nr = 4, -#if defined(EIGEN_HAS_FUSED_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) +#if defined(EIGEN_HAS_FUSED_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX) // we assume 16 registers mr = 3*LhsPacketSize, #else diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 05107fdfe..31073b990 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -413,10 +413,16 @@ namespace Architecture Generic = 0x0, SSE = 0x1, AltiVec = 0x2, + VSX = 0x3, + NEON = 0x4, #if defined EIGEN_VECTORIZE_SSE Target = SSE #elif defined EIGEN_VECTORIZE_ALTIVEC Target = AltiVec +#elif defined EIGEN_VECTORIZE_VSX + Target = VSX +#elif defined EIGEN_VECTORIZE_NEON + Target = NEON #else Target = Generic #endif diff --git a/bench/btl/libs/eigen2/eigen2_interface.hh b/bench/btl/libs/eigen2/eigen2_interface.hh index 47fe58135..1deabdae2 100644 --- a/bench/btl/libs/eigen2/eigen2_interface.hh +++ b/bench/btl/libs/eigen2/eigen2_interface.hh @@ -47,7 +47,7 @@ public : { #if defined(EIGEN_VECTORIZE_SSE) if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2"; - #elif defined(EIGEN_VECTORIZE_ALTIVEC) + #elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2"; #else if (SIZE==Dynamic) return "eigen2_novec"; else return "tiny_eigen2_novec"; diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 9b9776894..6383c6eac 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -282,6 +282,12 @@ macro(ei_testing_print_summary) message(STATUS "Altivec: Using architecture defaults") endif() + if(EIGEN_TEST_VSX) + message(STATUS "VSX: ON") + else() + message(STATUS "VSX: Using architecture defaults") + endif() + if(EIGEN_TEST_NEON) message(STATUS "ARM NEON: ON") else() diff --git a/test/main.h b/test/main.h index 773873a0d..7667eaa18 100644 --- a/test/main.h +++ b/test/main.h @@ -76,7 +76,7 @@ #endif // bounds integer values for AltiVec -#ifdef __ALTIVEC__ +#if defined(__ALTIVEC__) || defined(__VSX__) #define EIGEN_MAKING_DOCS #endif diff --git a/test/packetmath.cpp b/test/packetmath.cpp index e5dc473c2..e716d6d9a 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -156,7 +156,7 @@ template void packetmath() CHECK_CWISE2(REF_ADD, internal::padd); CHECK_CWISE2(REF_SUB, internal::psub); CHECK_CWISE2(REF_MUL, internal::pmul); - #ifndef EIGEN_VECTORIZE_ALTIVEC + #if !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX) if (!internal::is_same::value) CHECK_CWISE2(REF_DIV, internal::pdiv); #endif -- cgit v1.2.3 From e6cc24cbd60113c704d8f88293d4efdd1eef1b98 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 14:20:11 +0200 Subject: Fix compilation in legacy mode --- Eigen/src/SparseCore/SparseDenseProduct.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index a715b8bde..c8a515e8c 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -362,14 +362,6 @@ class DenseTimeSparseProduct DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); }; -// sparse * dense -template -template -inline const typename SparseDenseProductReturnType::Type -SparseMatrixBase::operator*(const MatrixBase &other) const -{ - return typename SparseDenseProductReturnType::Type(derived(), other.derived()); -} #endif // EIGEN_TEST_EVALUATORS #ifdef EIGEN_TEST_EVALUATORS -- cgit v1.2.3 From bc065c75d2a8df928cb368d0352b8fcb25791fa8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 14:50:59 +0200 Subject: Implement the missing bits to make Solve compatible with sparse rhs --- Eigen/src/Core/Solve.h | 9 +++++++++ Eigen/src/SparseCore/SparseAssign.h | 12 ++++++++++++ Eigen/src/SparseCore/SparseUtil.h | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index c28789968..a1501c259 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -99,6 +99,15 @@ private: Scalar coeff(Index i) const; }; +#ifdef EIGEN_TEST_EVALUATORS +// Generic API dispatcher +template +class SolveImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; +#endif namespace internal { diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 0a29cb32f..36c9fe845 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -284,6 +284,18 @@ struct Assignment +struct Assignment, internal::assign_op, Sparse2Sparse, Scalar> +{ + typedef Solve SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + src.dec()._solve_impl(src.rhs(), dst); + } +}; + } // end namespace internal #endif // EIGEN_TEST_EVALUATORS diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 0183907a1..28bf89bca 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -156,6 +156,14 @@ template struct plain_matrix_type typedef SparseMatrix<_Scalar, _Options, _Index> type; }; +#ifdef EIGEN_TEST_EVALUATORS +template +struct solve_traits +{ + typedef typename sparse_eval::type PlainObject; +}; +#endif + template struct generic_xpr_base { -- cgit v1.2.3 From 85c765957418cd2fd24b46ca3a14e6fcbad43f05 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 15:00:19 +0200 Subject: Refactoring of sparse solvers through a SparseSolverBase class and usage of the Solve<> expression. Introduce a SolveWithGuess expression on top of Solve. --- Eigen/IterativeLinearSolvers | 4 + Eigen/SparseCholesky | 3 + Eigen/SparseCore | 1 + Eigen/src/CholmodSupport/CholmodSupport.h | 30 +++--- .../IterativeLinearSolvers/BasicPreconditioners.h | 20 +++- Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 41 ++++++-- .../src/IterativeLinearSolvers/ConjugateGradient.h | 31 ++++-- Eigen/src/IterativeLinearSolvers/IncompleteLUT.h | 20 +++- .../IterativeLinearSolvers/IterativeSolverBase.h | 39 ++++++- Eigen/src/IterativeLinearSolvers/SolveWithGuess.h | 114 +++++++++++++++++++++ Eigen/src/PaStiXSupport/PaStiXSupport.h | 32 +++--- Eigen/src/PardisoSupport/PardisoSupport.h | 44 ++++---- Eigen/src/QR/HouseholderQR.h | 4 +- Eigen/src/SPQRSupport/SuiteSparseQRSupport.h | 33 +++--- Eigen/src/SparseCholesky/SimplicialCholesky.h | 41 +++++++- Eigen/src/SparseCore/SparseSolverBase.h | 113 ++++++++++++++++++++ Eigen/src/SparseLU/SparseLU.h | 35 +++++-- Eigen/src/SparseQR/SparseQR.h | 39 +++++-- Eigen/src/SuperLUSupport/SuperLUSupport.h | 31 +++--- Eigen/src/UmfPackSupport/UmfPackSupport.h | 21 ++-- 20 files changed, 565 insertions(+), 131 deletions(-) create mode 100644 Eigen/src/IterativeLinearSolvers/SolveWithGuess.h create mode 100644 Eigen/src/SparseCore/SparseSolverBase.h diff --git a/Eigen/IterativeLinearSolvers b/Eigen/IterativeLinearSolvers index 0f4159dc1..4df2c5a14 100644 --- a/Eigen/IterativeLinearSolvers +++ b/Eigen/IterativeLinearSolvers @@ -26,8 +26,12 @@ * \endcode */ +#ifndef EIGEN_TEST_EVALUATORS #include "src/misc/Solve.h" #include "src/misc/SparseSolve.h" +#else +#include "src/IterativeLinearSolvers/SolveWithGuess.h" +#endif #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" diff --git a/Eigen/SparseCholesky b/Eigen/SparseCholesky index 9f5056aa1..2c4f66105 100644 --- a/Eigen/SparseCholesky +++ b/Eigen/SparseCholesky @@ -34,8 +34,11 @@ #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif +#ifndef EIGEN_TEST_EVALUATORS #include "src/misc/Solve.h" #include "src/misc/SparseSolve.h" +#endif + #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY diff --git a/Eigen/SparseCore b/Eigen/SparseCore index 41cae58b0..b68c8fa8a 100644 --- a/Eigen/SparseCore +++ b/Eigen/SparseCore @@ -58,6 +58,7 @@ struct Sparse {}; #include "src/SparseCore/TriangularSolver.h" #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseSolverBase.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index c449960de..4416c5308 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -157,8 +157,12 @@ enum CholmodMode { * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT */ template -class CholmodBase : internal::noncopyable +class CholmodBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; public: typedef _MatrixType MatrixType; enum { UpLo = _UpLo }; @@ -170,14 +174,14 @@ class CholmodBase : internal::noncopyable public: CholmodBase() - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + : m_cholmodFactor(0), m_info(Success) { m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); cholmod_start(&m_cholmod); } CholmodBase(const MatrixType& matrix) - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + : m_cholmodFactor(0), m_info(Success) { m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); cholmod_start(&m_cholmod); @@ -194,9 +198,6 @@ class CholmodBase : internal::noncopyable inline Index cols() const { return m_cholmodFactor->n; } inline Index rows() const { return m_cholmodFactor->n; } - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } - /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, @@ -216,6 +217,7 @@ class CholmodBase : internal::noncopyable return derived(); } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -235,14 +237,15 @@ class CholmodBase : internal::noncopyable * \sa compute() */ template - inline const internal::sparse_solve_retval + inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(rows()==b.rows() && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); + return internal::sparse_solve_retval(derived(), b.derived()); } +#endif // EIGEN_TEST_EVALUATORS /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. * @@ -290,7 +293,7 @@ class CholmodBase : internal::noncopyable #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; @@ -312,7 +315,7 @@ class CholmodBase : internal::noncopyable /** \internal */ template - void _solve(const SparseMatrix &b, SparseMatrix &dest) const + void _solve_impl(const SparseMatrix &b, SparseMatrix &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; @@ -357,7 +360,6 @@ class CholmodBase : internal::noncopyable cholmod_factor* m_cholmodFactor; RealScalar m_shiftOffset[2]; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; }; @@ -572,6 +574,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom } }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -583,7 +586,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; @@ -596,11 +599,12 @@ struct sparse_solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif } // end namespace Eigen diff --git a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h index 1f3c060d0..92af28cc8 100644 --- a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +++ b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -80,12 +80,14 @@ class DiagonalPreconditioner return factorize(mat); } + /** \internal */ template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, Dest& x) const { x = m_invdiag.array() * b.array() ; } +#ifndef EIGEN_TEST_EVALUATORS template inline const internal::solve_retval solve(const MatrixBase& b) const { @@ -94,12 +96,23 @@ class DiagonalPreconditioner && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#else + template inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "DiagonalPreconditioner is not initialized."); + eigen_assert(m_invdiag.size()==b.rows() + && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); + return Solve(*this, b.derived()); + } +#endif protected: Vector m_invdiag; bool m_isInitialized; }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -111,11 +124,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } +#endif // EIGEN_TEST_EVALUATORS /** \ingroup IterativeLinearSolvers_Module * \brief A naive preconditioner which approximates any matrix as the identity matrix diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index 27824b9d5..2cad946d3 100644 --- a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2012 Désiré Nuentsa-Wakam // // This Source Code Form is subject to the terms of the Mozilla @@ -181,7 +181,8 @@ public: BiCGSTAB(const MatrixType& A) : Base(A) {} ~BiCGSTAB() {} - + +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * \a x0 as an initial solution. * @@ -197,10 +198,26 @@ public: return internal::solve_retval_with_guess (*this, b.derived(), x0); } - +#else + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A + * \a x0 as an initial solution. + * + * \sa compute() + */ + template + inline const SolveWithGuess + solveWithGuess(const MatrixBase& b, const Guess& x0) const + { + eigen_assert(m_isInitialized && "BiCGSTAB is not initialized."); + eigen_assert(Base::rows()==b.rows() + && "BiCGSTAB::solve(): invalid number of rows of the right hand side matrix b"); + return SolveWithGuess(*this, b.derived(), x0); + } +#endif + /** \internal */ template - void _solveWithGuess(const Rhs& b, Dest& x) const + void _solve_with_guess_impl(const Rhs& b, Dest& x) const { bool failed = false; for(int j=0; j - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const MatrixBase& b, Dest& x) const { -// x.setZero(); - x = b; - _solveWithGuess(b,x); + // x.setZero(); + x = b; + _solve_with_guess_impl(b,x); } protected: }; - +#ifndef EIGEN_TEST_EVALUATORS namespace internal { - template +template struct solve_retval, Rhs> : solve_retval_base, Rhs> { @@ -243,11 +261,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif } // end namespace Eigen diff --git a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index 3ce517940..000780eff 100644 --- a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -193,6 +193,7 @@ public: ~ConjugateGradient() {} +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * \a x0 as an initial solution. * @@ -208,10 +209,26 @@ public: return internal::solve_retval_with_guess (*this, b.derived(), x0); } +#else + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A + * \a x0 as an initial solution. + * + * \sa compute() + */ + template + inline const SolveWithGuess + solveWithGuess(const MatrixBase& b, const Guess& x0) const + { + eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); + eigen_assert(Base::rows()==b.rows() + && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b"); + return SolveWithGuess(*this, b.derived(), x0); + } +#endif /** \internal */ template - void _solveWithGuess(const Rhs& b, Dest& x) const + void _solve_with_guess_impl(const Rhs& b, Dest& x) const { m_iterations = Base::maxIterations(); m_error = Base::m_tolerance; @@ -231,18 +248,19 @@ public: } /** \internal */ + using Base::_solve_impl; template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const MatrixBase& b, Dest& x) const { x.setOnes(); - _solveWithGuess(b,x); + _solve_with_guess_impl(b.derived(),x); } protected: }; - +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -254,11 +272,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif } // end namespace Eigen diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index b55afc136..a39ed7748 100644 --- a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2012 Désiré Nuentsa-Wakam +// Copyright (C) 2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -158,7 +159,11 @@ class IncompleteLUT : internal::noncopyable void setFillfactor(int fillfactor); template +#ifndef EIGEN_TEST_EVALUATORS void _solve(const Rhs& b, Dest& x) const +#else + void _solve_impl(const Rhs& b, Dest& x) const +#endif { x = m_Pinv * b; x = m_lu.template triangularView().solve(x); @@ -166,14 +171,25 @@ class IncompleteLUT : internal::noncopyable x = m_P * x; } +#ifndef EIGEN_TEST_EVALUATORS template inline const internal::solve_retval - solve(const MatrixBase& b) const + solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); eigen_assert(cols()==b.rows() && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#else + template inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); + eigen_assert(cols()==b.rows() + && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); + return Solve(*this, b.derived()); + } +#endif protected: @@ -445,6 +461,7 @@ void IncompleteLUT::factorize(const _MatrixType& amat) m_info = Success; } +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -461,6 +478,7 @@ struct solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 2036922d6..2fc1a511b 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,8 +18,12 @@ namespace Eigen { * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ template< typename Derived> -class IterativeSolverBase : internal::noncopyable +class IterativeSolverBase : public SparseSolverBase { +protected: + typedef SparseSolverBase Base; + using Base::m_isInitialized; + public: typedef typename internal::traits::MatrixType MatrixType; typedef typename internal::traits::Preconditioner Preconditioner; @@ -29,8 +33,7 @@ public: public: - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } + using Base::derived; /** Default constructor. */ IterativeSolverBase() @@ -159,6 +162,7 @@ public: return m_error; } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -171,7 +175,9 @@ public: && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(derived(), b.derived()); } +#endif +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -185,6 +191,7 @@ public: && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } +#endif // EIGEN_TEST_EVALUATORS /** \returns Success if the iterations converged, and NoConvergence otherwise. */ ComputationInfo info() const @@ -193,6 +200,7 @@ public: return m_info; } +#ifndef EIGEN_TEST_EVALUATORS /** \internal */ template void _solve_sparse(const Rhs& b, SparseMatrix &dest) const @@ -210,6 +218,25 @@ public: dest.col(k) = tx.sparseView(0); } } +#else + /** \internal */ + template + void _solve_impl(const Rhs& b, SparseMatrix &dest) const + { + eigen_assert(rows()==b.rows()); + + int rhsCols = b.cols(); + int size = b.rows(); + Eigen::Matrix tb(size); + Eigen::Matrix tx(size); + for(int k=0; k @@ -248,6 +276,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h new file mode 100644 index 000000000..46dd5babe --- /dev/null +++ b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h @@ -0,0 +1,114 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SOLVEWITHGUESS_H +#define EIGEN_SOLVEWITHGUESS_H + +namespace Eigen { + +template class SolveWithGuess; + +/** \class SolveWithGuess + * \ingroup IterativeLinearSolvers_Module + * + * \brief Pseudo expression representing a solving operation + * + * \tparam Decomposition the type of the matrix or decomposion object + * \tparam Rhstype the type of the right-hand side + * + * This class represents an expression of A.solve(B) + * and most of the time this is the only way it is used. + * + */ +namespace internal { + + +template +struct traits > + : traits > +{}; + +} + + +template +class SolveWithGuess : public internal::generic_xpr_base, MatrixXpr, typename internal::traits::StorageKind>::type +{ +public: + typedef typename RhsType::Index Index; + typedef typename internal::traits::PlainObject PlainObject; + typedef typename internal::generic_xpr_base, MatrixXpr, typename internal::traits::StorageKind>::type Base; + + SolveWithGuess(const Decomposition &dec, const RhsType &rhs, const GuessType &guess) + : m_dec(dec), m_rhs(rhs), m_guess(guess) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_dec.cols(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const Decomposition& dec() const { return m_dec; } + EIGEN_DEVICE_FUNC const RhsType& rhs() const { return m_rhs; } + EIGEN_DEVICE_FUNC const GuessType& guess() const { return m_guess; } + +protected: + const Decomposition &m_dec; + const RhsType &m_rhs; + const GuessType &m_guess; + + typedef typename internal::traits::Scalar Scalar; + +private: + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +// Evaluator of SolveWithGuess -> eval into a temporary +template +struct evaluator > + : public evaluator::PlainObject>::type +{ + typedef SolveWithGuess SolveType; + typedef typename SolveType::PlainObject PlainObject; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const SolveType& solve) + : m_result(solve.rows(), solve.cols()) + { + ::new (static_cast(this)) Base(m_result); + solve.dec()._solve_with_guess_impl(solve.rhs(), m_result, solve().guess()); + } + +protected: + PlainObject m_result; +}; + +// Specialization for "dst = dec.solve(rhs)" +// NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere +template +struct Assignment, internal::assign_op, Dense2Dense, Scalar> +{ + typedef Solve SrcXprType; + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + // FIXME shall we resize dst here? + dst = src.guess(); + src.dec()._solve_with_guess_impl(src.rhs(), dst/*, src.guess()*/); + } +}; + +} // end namepsace internal + +} // end namespace Eigen + +#endif // EIGEN_SOLVEWITHGUESS_H diff --git a/Eigen/src/PaStiXSupport/PaStiXSupport.h b/Eigen/src/PaStiXSupport/PaStiXSupport.h index 8a546dc2f..0dc5c6a6f 100644 --- a/Eigen/src/PaStiXSupport/PaStiXSupport.h +++ b/Eigen/src/PaStiXSupport/PaStiXSupport.h @@ -125,9 +125,15 @@ namespace internal // This is the base class to interface with PaStiX functions. // Users should not used this class directly. template -class PastixBase : internal::noncopyable +class PastixBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; public: + using Base::_solve_impl; + typedef typename internal::pastix_traits::MatrixType _MatrixType; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; @@ -138,7 +144,7 @@ class PastixBase : internal::noncopyable public: - PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false), m_pastixdata(0), m_size(0) + PastixBase() : m_initisOk(false), m_analysisIsOk(false), m_factorizationIsOk(false), m_pastixdata(0), m_size(0) { init(); } @@ -148,6 +154,7 @@ class PastixBase : internal::noncopyable clean(); } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -161,19 +168,11 @@ class PastixBase : internal::noncopyable && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#endif template - bool _solve (const MatrixBase &b, MatrixBase &x) const; + bool _solve_impl(const MatrixBase &b, MatrixBase &x) const; - Derived& derived() - { - return *static_cast(this); - } - const Derived& derived() const - { - return *static_cast(this); - } - /** Returns a reference to the integer vector IPARM of PaStiX parameters * to modify the default parameters. * The statistics related to the different phases of factorization and solve are saved here as well @@ -228,6 +227,7 @@ class PastixBase : internal::noncopyable return m_info; } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -241,6 +241,7 @@ class PastixBase : internal::noncopyable && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } +#endif // EIGEN_TEST_EVALUATORS protected: @@ -268,7 +269,6 @@ class PastixBase : internal::noncopyable int m_initisOk; int m_analysisIsOk; int m_factorizationIsOk; - bool m_isInitialized; mutable ComputationInfo m_info; mutable pastix_data_t *m_pastixdata; // Data structure for pastix mutable int m_comm; // The MPI communicator identifier @@ -393,7 +393,7 @@ void PastixBase::factorize(ColSpMatrix& mat) /* Solve the system */ template template -bool PastixBase::_solve (const MatrixBase &b, MatrixBase &x) const +bool PastixBase::_solve_impl(const MatrixBase &b, MatrixBase &x) const { eigen_assert(m_isInitialized && "The matrix should be factorized first"); EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0, @@ -694,6 +694,7 @@ class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > } }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -705,7 +706,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; @@ -723,6 +724,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/PardisoSupport/PardisoSupport.h b/Eigen/src/PardisoSupport/PardisoSupport.h index b6571069e..e3b1c5bc0 100644 --- a/Eigen/src/PardisoSupport/PardisoSupport.h +++ b/Eigen/src/PardisoSupport/PardisoSupport.h @@ -96,10 +96,17 @@ namespace internal } template -class PardisoImpl : internal::noncopyable +class PardisoImpl : public SparseSolveBase { + protected: + typedef SparseSolveBase Base; + using Base::derived; + using Base::m_isInitialized; + typedef internal::pardiso_traits Traits; public: + using base::_solve_impl; + typedef typename Traits::MatrixType MatrixType; typedef typename Traits::Scalar Scalar; typedef typename Traits::RealScalar RealScalar; @@ -118,7 +125,7 @@ class PardisoImpl : internal::noncopyable eigen_assert((sizeof(Index) >= sizeof(_INTEGER_t) && sizeof(Index) <= 8) && "Non-supported index type"); m_iparm.setZero(); m_msglvl = 0; // No output - m_initialized = false; + m_isInitialized = false; } ~PardisoImpl() @@ -136,7 +143,7 @@ class PardisoImpl : internal::noncopyable */ ComputationInfo info() const { - eigen_assert(m_initialized && "Decomposition is not initialized."); + eigen_assert(m_isInitialized && "Decomposition is not initialized."); return m_info; } @@ -166,6 +173,7 @@ class PardisoImpl : internal::noncopyable Derived& compute(const MatrixType& matrix); +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -174,7 +182,7 @@ class PardisoImpl : internal::noncopyable inline const internal::solve_retval solve(const MatrixBase& b) const { - eigen_assert(m_initialized && "Pardiso solver is not initialized."); + eigen_assert(m_isInitialized && "Pardiso solver is not initialized."); eigen_assert(rows()==b.rows() && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); @@ -188,28 +196,20 @@ class PardisoImpl : internal::noncopyable inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const { - eigen_assert(m_initialized && "Pardiso solver is not initialized."); + eigen_assert(m_isInitialized && "Pardiso solver is not initialized."); eigen_assert(rows()==b.rows() && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } - - Derived& derived() - { - return *static_cast(this); - } - const Derived& derived() const - { - return *static_cast(this); - } +#endif template - bool _solve(const MatrixBase &b, MatrixBase& x) const; + bool _solve_impl(const MatrixBase &b, MatrixBase& x) const; protected: void pardisoRelease() { - if(m_initialized) // Factorization ran at least once + if(m_isInitialized) // Factorization ran at least once { internal::pardiso_run_selector::run(m_pt, 1, 1, m_type, -1, m_size, 0, 0, 0, m_perm.data(), 0, m_iparm.data(), m_msglvl, 0, 0); @@ -270,7 +270,7 @@ class PardisoImpl : internal::noncopyable mutable SparseMatrixType m_matrix; ComputationInfo m_info; - bool m_initialized, m_analysisIsOk, m_factorizationIsOk; + bool m_analysisIsOk, m_factorizationIsOk; Index m_type, m_msglvl; mutable void *m_pt[64]; mutable ParameterType m_iparm; @@ -298,7 +298,7 @@ Derived& PardisoImpl::compute(const MatrixType& a) manageErrorCode(error); m_analysisIsOk = true; m_factorizationIsOk = true; - m_initialized = true; + m_isInitialized = true; return derived(); } @@ -321,7 +321,7 @@ Derived& PardisoImpl::analyzePattern(const MatrixType& a) manageErrorCode(error); m_analysisIsOk = true; m_factorizationIsOk = false; - m_initialized = true; + m_isInitialized = true; return derived(); } @@ -345,7 +345,7 @@ Derived& PardisoImpl::factorize(const MatrixType& a) template template -bool PardisoImpl::_solve(const MatrixBase &b, MatrixBase& x) const +bool PardisoImpl::_solve_impl(const MatrixBase &b, MatrixBase& x) const { if(m_iparm[0] == 0) // Factorization was not computed return false; @@ -546,6 +546,7 @@ class PardisoLDLT : public PardisoImpl< PardisoLDLT > } }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -557,7 +558,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; @@ -575,6 +576,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 8808e6c0d..136e80ce9 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -350,7 +350,8 @@ void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) c dst.bottomRows(cols()-rank).setZero(); } #endif - + +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -366,6 +367,7 @@ struct solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS /** Performs the QR factorization of the given matrix \a matrix. The result of * the factorization is stored into \c *this, and a reference to \c *this diff --git a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h index a2cc2a9e2..483aaef07 100644 --- a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +++ b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2012 Desire Nuentsa +// Copyright (C) 2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -54,8 +55,11 @@ namespace Eigen { * */ template -class SPQR +class SPQR : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; public: typedef typename _MatrixType::Scalar Scalar; typedef typename _MatrixType::RealScalar RealScalar; @@ -64,19 +68,13 @@ class SPQR typedef PermutationMatrix PermutationType; public: SPQR() - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits::epsilon()) + : m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()) { cholmod_l_start(&m_cc); } SPQR(const _MatrixType& matrix) - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits::epsilon()) + : m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()) { cholmod_l_start(&m_cc); compute(matrix); @@ -127,10 +125,11 @@ class SPQR */ inline Index cols() const { return m_cR->ncol; } - /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. - * - * \sa compute() - */ +#ifndef EIGEN_TEST_EVALUATORS + /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. + * + * \sa compute() + */ template inline const internal::solve_retval solve(const MatrixBase& B) const { @@ -139,9 +138,10 @@ class SPQR && "SPQR::solve(): invalid number of rows of the right hand side matrix B"); return internal::solve_retval(*this, B.derived()); } +#endif // EIGEN_TEST_EVALUATORS template - void _solve(const MatrixBase &b, MatrixBase &dest) const + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const { eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()"); eigen_assert(b.cols()==1 && "This method is for vectors only"); @@ -214,7 +214,6 @@ class SPQR return m_info; } protected: - bool m_isInitialized; bool m_analysisIsOk; bool m_factorizationIsOk; mutable bool m_isRUpToDate; @@ -293,6 +292,7 @@ struct SPQRMatrixQTransposeReturnType{ const SPQRType& m_spqr; }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -304,11 +304,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif }// End namespace Eigen #endif diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index 1abd31304..ac8cd29b0 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -33,8 +33,11 @@ enum SimplicialCholeskyMode { * */ template -class SimplicialCholeskyBase : internal::noncopyable +class SimplicialCholeskyBase : public SparseSolverBase { + typedef SparseSolverBase Base; + using Base::m_isInitialized; + public: typedef typename internal::traits::MatrixType MatrixType; typedef typename internal::traits::OrderingType OrderingType; @@ -46,14 +49,16 @@ class SimplicialCholeskyBase : internal::noncopyable typedef Matrix VectorType; public: + + using Base::derived; /** Default constructor */ SimplicialCholeskyBase() - : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) + : m_info(Success), m_shiftOffset(0), m_shiftScale(1) {} SimplicialCholeskyBase(const MatrixType& matrix) - : m_info(Success), m_isInitialized(false), m_shiftOffset(0), m_shiftScale(1) + : m_info(Success), m_shiftOffset(0), m_shiftScale(1) { derived().compute(matrix); } @@ -79,6 +84,7 @@ class SimplicialCholeskyBase : internal::noncopyable return m_info; } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -106,6 +112,7 @@ class SimplicialCholeskyBase : internal::noncopyable && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } +#endif // EIGEN_TEST_EVALUATORS /** \returns the permutation P * \sa permutationPinv() */ @@ -150,7 +157,11 @@ class SimplicialCholeskyBase : internal::noncopyable /** \internal */ template +#ifndef EIGEN_TEST_EVALUATORS void _solve(const MatrixBase &b, MatrixBase &dest) const +#else + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const +#endif { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); eigen_assert(m_matrix.rows()==b.rows()); @@ -176,6 +187,14 @@ class SimplicialCholeskyBase : internal::noncopyable dest = m_Pinv * dest; } +#ifdef EIGEN_TEST_EVALUATORS + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const + { + internal::solve_sparse_through_dense_panels(derived(), b, dest); + } +#endif + #endif // EIGEN_PARSED_BY_DOXYGEN protected: @@ -226,7 +245,6 @@ class SimplicialCholeskyBase : internal::noncopyable }; mutable ComputationInfo m_info; - bool m_isInitialized; bool m_factorizationIsOk; bool m_analysisIsOk; @@ -560,7 +578,11 @@ public: /** \internal */ template +#ifndef EIGEN_TEST_EVALUATORS void _solve(const MatrixBase &b, MatrixBase &dest) const +#else + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const +#endif { eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); eigen_assert(Base::m_matrix.rows()==b.rows()); @@ -596,6 +618,15 @@ public: dest = Base::m_Pinv * dest; } +#ifdef EIGEN_TEST_EVALUATORS + /** \internal */ + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const + { + internal::solve_sparse_through_dense_panels(*this, b, dest); + } +#endif + Scalar determinant() const { if(m_LDLT) @@ -636,6 +667,7 @@ void SimplicialCholeskyBase::ordering(const MatrixType& a, CholMatrixTy ap.template selfadjointView() = a.template selfadjointView().twistedBy(m_P); } +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -665,6 +697,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseSolverBase.h b/Eigen/src/SparseCore/SparseSolverBase.h new file mode 100644 index 000000000..9a6ed1292 --- /dev/null +++ b/Eigen/src/SparseCore/SparseSolverBase.h @@ -0,0 +1,113 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSESOLVERBASE_H +#define EIGEN_SPARSESOLVERBASE_H + +namespace Eigen { + +namespace internal { + + /** \internal + * Helper functions to solve with a sparse right-hand-side and result. + * The rhs is decomposed into small vertical panels which are solved through dense temporaries. + */ +template +void solve_sparse_through_dense_panels(const Decomposition &dec, const Rhs& rhs, Dest &dest) +{ + EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + typedef typename Dest::Scalar DestScalar; + // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. + static const int NbColsAtOnce = 4; + int rhsCols = rhs.cols(); + int size = rhs.rows(); + // the temporary matrices do not need more columns than NbColsAtOnce: + int tmpCols = (std::min)(rhsCols, NbColsAtOnce); + Eigen::Matrix tmp(size,tmpCols); + Eigen::Matrix tmpX(size,tmpCols); + for(int k=0; k(rhsCols-k, NbColsAtOnce); + tmp.leftCols(actualCols) = rhs.middleCols(k,actualCols); + tmpX.leftCols(actualCols) = dec.solve(tmp.leftCols(actualCols)); + dest.middleCols(k,actualCols) = tmpX.leftCols(actualCols).sparseView(); + } +} + +} // end namespace internal + +/** \class SparseSolverBase + * \ingroup SparseCore_Module + * \brief A base class for sparse solvers + * + * \tparam Derived the actual type of the solver. + * + */ +template +class SparseSolverBase : internal::noncopyable +{ + public: + + /** Default constructor */ + SparseSolverBase() + : m_isInitialized(false) + {} + + ~SparseSolverBase() + {} + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + +#ifdef EIGEN_TEST_EVALUATORS + /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "Solver is not initialized."); + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return Solve(derived(), b.derived()); + } + + /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const Solve + solve(const SparseMatrixBase& b) const + { + eigen_assert(m_isInitialized && "Solver is not initialized."); + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return Solve(derived(), b.derived()); + } +#endif + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal default implementation of solving with a sparse rhs */ + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const + { + internal::solve_sparse_through_dense_panels(derived(), b.derived(), dest.derived()); + } +#endif // EIGEN_PARSED_BY_DOXYGEN + + protected: + + mutable bool m_isInitialized; +}; + +} // end namespace Eigen + +#endif // EIGEN_SPARSESOLVERBASE_H diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index 7a9aeec2d..eb61fe3d9 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2012 Désiré Nuentsa-Wakam -// Copyright (C) 2012 Gael Guennebaud +// Copyright (C) 2012-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -70,9 +70,14 @@ template struct SparseLUMatrixURetu * \sa \ref OrderingMethods_Module */ template -class SparseLU : public internal::SparseLUImpl +class SparseLU : public SparseSolverBase >, public internal::SparseLUImpl { + protected: + typedef SparseSolverBase > APIBase; + using APIBase::m_isInitialized; public: + using APIBase::_solve_impl; + typedef _MatrixType MatrixType; typedef _OrderingType OrderingType; typedef typename MatrixType::Scalar Scalar; @@ -86,11 +91,11 @@ class SparseLU : public internal::SparseLUImpl Base; public: - SparseLU():m_isInitialized(true),m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) + SparseLU():m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) { initperfvalues(); } - SparseLU(const MatrixType& matrix):m_isInitialized(true),m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) + SparseLU(const MatrixType& matrix):m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) { initperfvalues(); compute(matrix); @@ -168,6 +173,7 @@ class SparseLU : public internal::SparseLUImplsolve(B) must be colmun-major. @@ -195,6 +201,20 @@ class SparseLU : public internal::SparseLUImpl(*this, B.derived()); } +#else + +#ifdef EIGEN_PARSED_BY_DOXYGEN + /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. + * + * \warning the destination matrix X in X = this->solve(B) must be colmun-major. + * + * \sa compute() + */ + template + inline const Solve solve(const MatrixBase& B) const; +#endif // EIGEN_PARSED_BY_DOXYGEN + +#endif // EIGEN_TEST_EVALUATORS /** \brief Reports whether previous computation was successful. * @@ -219,7 +239,7 @@ class SparseLU : public internal::SparseLUImpl - bool _solve(const MatrixBase &B, MatrixBase &X_base) const + bool _solve_impl(const MatrixBase &B, MatrixBase &X_base) const { Dest& X(X_base.derived()); eigen_assert(m_factorizationIsOk && "The matrix should be factorized first"); @@ -332,7 +352,6 @@ class SparseLU : public internal::SparseLUImpl @@ -739,7 +759,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; @@ -756,6 +776,7 @@ struct sparse_solve_retval, Rhs> } }; } // end namespace internal +#endif } // End namespace Eigen diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 6be569533..8e946b045 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -62,9 +62,13 @@ namespace internal { * */ template -class SparseQR +class SparseQR : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; public: + using Base::_solve_impl; typedef _MatrixType MatrixType; typedef _OrderingType OrderingType; typedef typename MatrixType::Scalar Scalar; @@ -75,7 +79,7 @@ class SparseQR typedef Matrix ScalarVector; typedef PermutationMatrix PermutationType; public: - SparseQR () : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) + SparseQR () : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) { } /** Construct a QR factorization of the matrix \a mat. @@ -84,7 +88,7 @@ class SparseQR * * \sa compute() */ - SparseQR(const MatrixType& mat) : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) + SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) { compute(mat); } @@ -162,7 +166,7 @@ class SparseQR /** \internal */ template - bool _solve(const MatrixBase &B, MatrixBase &dest) const + bool _solve_impl(const MatrixBase &B, MatrixBase &dest) const { eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); @@ -186,7 +190,6 @@ class SparseQR m_info = Success; return true; } - /** Sets the threshold that is used to determine linearly dependent columns during the factorization. * @@ -199,6 +202,7 @@ class SparseQR m_threshold = threshold; } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. * * \sa compute() @@ -217,6 +221,26 @@ class SparseQR eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); return internal::sparse_solve_retval(*this, B.derived()); } +#else + /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. + * + * \sa compute() + */ + template + inline const Solve solve(const MatrixBase& B) const + { + eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); + eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); + return Solve(*this, B.derived()); + } + template + inline const Solve solve(const SparseMatrixBase& B) const + { + eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); + eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); + return Solve(*this, B.derived()); + } +#endif // EIGEN_TEST_EVALUATORS /** \brief Reports whether previous computation was successful. * @@ -244,7 +268,6 @@ class SparseQR protected: - bool m_isInitialized; bool m_analysisIsok; bool m_factorizationIsok; mutable ComputationInfo m_info; @@ -554,6 +577,7 @@ void SparseQR::factorize(const MatrixType& mat) m_info = Success; } +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -565,7 +589,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; template @@ -581,6 +605,7 @@ struct sparse_solve_retval, Rhs> } }; } // end namespace internal +#endif // EIGEN_TEST_EVALUATORS template struct SparseQR_QProduct : ReturnByValue > diff --git a/Eigen/src/SuperLUSupport/SuperLUSupport.h b/Eigen/src/SuperLUSupport/SuperLUSupport.h index bcb355760..fcecd4fcf 100644 --- a/Eigen/src/SuperLUSupport/SuperLUSupport.h +++ b/Eigen/src/SuperLUSupport/SuperLUSupport.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -288,8 +288,12 @@ MappedSparseMatrix map_superlu(SluMatrix& sluMat) * \brief The base class for the direct and incomplete LU factorization of SuperLU */ template -class SuperLUBase : internal::noncopyable +class SuperLUBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; public: typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; @@ -309,9 +313,6 @@ class SuperLUBase : internal::noncopyable clearFactors(); } - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } - inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } @@ -336,6 +337,7 @@ class SuperLUBase : internal::noncopyable derived().factorize(matrix); } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -361,7 +363,8 @@ class SuperLUBase : internal::noncopyable && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } - +#endif // EIGEN_TEST_EVALUATORS + /** Performs a symbolic decomposition on the sparcity of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. @@ -453,7 +456,6 @@ class SuperLUBase : internal::noncopyable mutable char m_sluEqued; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; mutable bool m_extractedDataAreDirty; @@ -491,6 +493,7 @@ class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> > typedef TriangularView UMatrixType; public: + using Base::_solve_impl; SuperLU() : Base() { init(); } @@ -528,7 +531,7 @@ class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> > #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const; + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const; #endif // EIGEN_PARSED_BY_DOXYGEN inline const LMatrixType& matrixL() const @@ -637,7 +640,7 @@ void SuperLU::factorize(const MatrixType& a) template template -void SuperLU::_solve(const MatrixBase &b, MatrixBase& x) const +void SuperLU::_solve_impl(const MatrixBase &b, MatrixBase& x) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); @@ -828,6 +831,7 @@ class SuperILU : public SuperLUBase<_MatrixType,SuperILU<_MatrixType> > typedef typename Base::Index Index; public: + using Base::_solve_impl; SuperILU() : Base() { init(); } @@ -863,7 +867,7 @@ class SuperILU : public SuperLUBase<_MatrixType,SuperILU<_MatrixType> > #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const; + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const; #endif // EIGEN_PARSED_BY_DOXYGEN protected: @@ -948,7 +952,7 @@ void SuperILU::factorize(const MatrixType& a) template template -void SuperILU::_solve(const MatrixBase &b, MatrixBase& x) const +void SuperILU::_solve_impl(const MatrixBase &b, MatrixBase& x) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or analyzePattern()/factorize()"); @@ -991,6 +995,7 @@ void SuperILU::_solve(const MatrixBase &b, MatrixBase& x) } #endif +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -1002,7 +1007,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec().derived()._solve(rhs(),dst); + dec().derived()._solve_impl(rhs(),dst); } }; @@ -1020,7 +1025,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal - +#endif } // end namespace Eigen #endif // EIGEN_SUPERLUSUPPORT_H diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index 3a48cecf7..845c8076a 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -121,9 +121,13 @@ inline int umfpack_get_determinant(std::complex *Mx, double *Ex, void *N * \sa \ref TutorialSparseDirectSolvers */ template -class UmfPackLU : internal::noncopyable +class UmfPackLU : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; public: + using Base::_solve_impl; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; @@ -197,7 +201,8 @@ class UmfPackLU : internal::noncopyable analyzePattern(matrix); factorize(matrix); } - + +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -223,6 +228,7 @@ class UmfPackLU : internal::noncopyable && "UmfPackLU::solve(): invalid number of rows of the right hand side matrix b"); return internal::sparse_solve_retval(*this, b.derived()); } +#endif /** Performs a symbolic decomposition on the sparcity of \a matrix. * @@ -274,7 +280,7 @@ class UmfPackLU : internal::noncopyable #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - bool _solve(const MatrixBase &b, MatrixBase &x) const; + bool _solve_impl(const MatrixBase &b, MatrixBase &x) const; #endif Scalar determinant() const; @@ -328,7 +334,6 @@ class UmfPackLU : internal::noncopyable void* m_symbolic; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; mutable bool m_extractedDataAreDirty; @@ -376,7 +381,7 @@ typename UmfPackLU::Scalar UmfPackLU::determinant() cons template template -bool UmfPackLU::_solve(const MatrixBase &b, MatrixBase &x) const +bool UmfPackLU::_solve_impl(const MatrixBase &b, MatrixBase &x) const { const int rhsCols = b.cols(); eigen_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major rhs yet"); @@ -396,7 +401,7 @@ bool UmfPackLU::_solve(const MatrixBase &b, MatrixBase @@ -408,7 +413,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; @@ -426,7 +431,7 @@ struct sparse_solve_retval, Rhs> }; } // end namespace internal - +#endif } // end namespace Eigen #endif // EIGEN_UMFPACKSUPPORT_H -- cgit v1.2.3 From fbb53b6cbb7f1a7cce2166c9df981b76fdd37f87 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 16:53:52 +0200 Subject: Fix sparse matrix times sparse vector. --- Eigen/src/SparseCore/ConservativeSparseSparseProduct.h | 6 ++++-- test/sparse_vector.cpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 815fdb6d8..535713ec5 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -28,6 +28,8 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r ei_declare_aligned_stack_constructed_variable(bool, mask, rows, 0); ei_declare_aligned_stack_constructed_variable(Scalar, values, rows, 0); ei_declare_aligned_stack_constructed_variable(Index, indices, rows, 0); + + std::memset(mask,0,sizeof(bool)*rows); // estimate the number of non zero entries // given a rhs column containing Y non zeros, we assume that the respective Y columns @@ -155,14 +157,14 @@ struct conservative_sparse_sparse_product_selector(lhs, rhs, resCol, true); - res.swap(resCol); + res = resCol.markAsRValue(); } else { // ressort to transpose to sort the entries internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, false); RowMajorMatrix resRow(resCol); - res = resRow; + res = resRow.markAsRValue(); } } }; diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 0c9476803..5eea9edfd 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -71,6 +71,7 @@ template void sparse_vector(int rows, int cols) VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2)); VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2)); + VERIFY_IS_APPROX(m1*v2, refM1*refV2); VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2)); int i = internal::random(0,rows-1); VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i))); -- cgit v1.2.3 From f9580a3473b20b97cf3e939154f85004e232d96e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:14:30 +0200 Subject: Fix Cholmod support without evaluators --- Eigen/src/CholmodSupport/CholmodSupport.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index 4416c5308..d3db51d0b 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -237,13 +237,13 @@ class CholmodBase : public SparseSolverBase * \sa compute() */ template - inline const internal::sparse_solve_retval + inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(rows()==b.rows() && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(derived(), b.derived()); + return internal::sparse_solve_retval(*this, b.derived()); } #endif // EIGEN_TEST_EVALUATORS -- cgit v1.2.3 From 1bf3b3484975ead812c4615f0d54f25d859320c3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:15:08 +0200 Subject: Fix regression in sparse-sparse product --- Eigen/src/SparseCore/ConservativeSparseSparseProduct.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 535713ec5..ae8fc75e5 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -151,18 +151,19 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrixAux; typedef typename sparse_eval::type ColMajorMatrix; - ColMajorMatrix resCol(lhs.rows(),rhs.cols()); // FIXME, the following heuristic is probably not very good. if(lhs.rows()>=rhs.cols()) { + ColMajorMatrix resCol(lhs.rows(),rhs.cols()); // perform sorted insertion internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, true); res = resCol.markAsRValue(); } else { + ColMajorMatrixAux resCol(lhs.rows(),rhs.cols()); // ressort to transpose to sort the entries - internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, false); + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, false); RowMajorMatrix resRow(resCol); res = resRow.markAsRValue(); } -- cgit v1.2.3 From 863b7362bc6cbd6f5c3ba96b4d6935557f9d9486 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:16:32 +0200 Subject: Fix usage of m_isInitialized in SparseLU and Pastix support. --- Eigen/src/PaStiXSupport/PaStiXSupport.h | 1 - Eigen/src/SparseLU/SparseLU.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/PaStiXSupport/PaStiXSupport.h b/Eigen/src/PaStiXSupport/PaStiXSupport.h index 0dc5c6a6f..95d53c850 100644 --- a/Eigen/src/PaStiXSupport/PaStiXSupport.h +++ b/Eigen/src/PaStiXSupport/PaStiXSupport.h @@ -328,7 +328,6 @@ void PastixBase::compute(ColSpMatrix& mat) factorize(mat); m_iparm(IPARM_MATRIX_VERIFICATION) = API_NO; - m_isInitialized = m_factorizationIsOk; } diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index eb61fe3d9..fb01f99cd 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -482,6 +482,8 @@ void SparseLU::factorize(const MatrixType& matrix) typedef typename IndexVector::Scalar Index; + m_isInitialized = true; + // Apply the column permutation computed in analyzepattern() // m_mat = matrix * m_perm_c.inverse(); -- cgit v1.2.3 From 8a74ce922cbee1c416675e57e48393dd6b399e4e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:19:16 +0200 Subject: Make IncompleteLUT use SparseSolverBase. --- Eigen/src/IterativeLinearSolvers/IncompleteLUT.h | 26 ++++++++---------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index a39ed7748..f337c5fb0 100644 --- a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -94,8 +94,12 @@ Index QuickSplit(VectorV &row, VectorI &ind, Index ncut) * http://comments.gmane.org/gmane.comp.lib.eigen/3302 */ template -class IncompleteLUT : internal::noncopyable +class IncompleteLUT : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; + public: typedef _Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix Vector; @@ -108,13 +112,13 @@ class IncompleteLUT : internal::noncopyable IncompleteLUT() : m_droptol(NumTraits::dummy_precision()), m_fillfactor(10), - m_analysisIsOk(false), m_factorizationIsOk(false), m_isInitialized(false) + m_analysisIsOk(false), m_factorizationIsOk(false) {} template IncompleteLUT(const MatrixType& mat, const RealScalar& droptol=NumTraits::dummy_precision(), int fillfactor = 10) : m_droptol(droptol),m_fillfactor(fillfactor), - m_analysisIsOk(false),m_factorizationIsOk(false),m_isInitialized(false) + m_analysisIsOk(false),m_factorizationIsOk(false) { eigen_assert(fillfactor != 0); compute(mat); @@ -159,11 +163,7 @@ class IncompleteLUT : internal::noncopyable void setFillfactor(int fillfactor); template -#ifndef EIGEN_TEST_EVALUATORS - void _solve(const Rhs& b, Dest& x) const -#else void _solve_impl(const Rhs& b, Dest& x) const -#endif { x = m_Pinv * b; x = m_lu.template triangularView().solve(x); @@ -180,15 +180,6 @@ class IncompleteLUT : internal::noncopyable && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } -#else - template inline const Solve - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); - eigen_assert(cols()==b.rows() - && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); - return Solve(*this, b.derived()); - } #endif protected: @@ -208,7 +199,6 @@ protected: int m_fillfactor; bool m_analysisIsOk; bool m_factorizationIsOk; - bool m_isInitialized; ComputationInfo m_info; PermutationMatrix m_P; // Fill-reducing permutation PermutationMatrix m_Pinv; // Inverse permutation @@ -473,7 +463,7 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; -- cgit v1.2.3 From 1c4b69c5fb4ec6a8b71a64f39ea82dacf50a8bfd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:19:51 +0200 Subject: Factorize solveWithGuess in IterativeSolverBase --- Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 15 --------------- Eigen/src/IterativeLinearSolvers/ConjugateGradient.h | 15 --------------- Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index 2cad946d3..b4d1d2a79 100644 --- a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -198,21 +198,6 @@ public: return internal::solve_retval_with_guess (*this, b.derived(), x0); } -#else - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const SolveWithGuess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "BiCGSTAB is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "BiCGSTAB::solve(): invalid number of rows of the right hand side matrix b"); - return SolveWithGuess(*this, b.derived(), x0); - } #endif /** \internal */ diff --git a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index 000780eff..b0273aaaf 100644 --- a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -209,21 +209,6 @@ public: return internal::solve_retval_with_guess (*this, b.derived(), x0); } -#else - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const SolveWithGuess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b"); - return SolveWithGuess(*this, b.derived(), x0); - } #endif /** \internal */ diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 2fc1a511b..26487dbb2 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -193,6 +193,22 @@ public: } #endif // EIGEN_TEST_EVALUATORS +#ifdef EIGEN_TEST_EVALUATORS + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A + * and \a x0 as an initial solution. + * + * \sa solve(), compute() + */ + template + inline const SolveWithGuess + solveWithGuess(const MatrixBase& b, const Guess& x0) const + { + eigen_assert(m_isInitialized && "Solver is not initialized."); + eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + return SolveWithGuess(derived(), b.derived(), x0); + } +#endif // EIGEN_TEST_EVALUATORS + /** \returns Success if the iterations converged, and NoConvergence otherwise. */ ComputationInfo info() const { -- cgit v1.2.3 From b3d63b4db21e746ef3ef260caa28773c8d3ae77b Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:21:05 +0200 Subject: Add evaluator for DynamicSparseMatrix --- .../Eigen/src/SparseExtra/DynamicSparseMatrix.h | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h index dec16df28..4210df68a 100644 --- a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h +++ b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h @@ -352,6 +352,38 @@ class DynamicSparseMatrix::ReverseInnerIterator : public const Index m_outer; }; +#ifdef EIGEN_ENABLE_EVALUATORS +namespace internal { + +template +struct evaluator > + : evaluator_base > +{ + typedef _Scalar Scalar; + typedef _Index Index; + typedef DynamicSparseMatrix<_Scalar,_Options,_Index> SparseMatrixType; + typedef typename SparseMatrixType::InnerIterator InnerIterator; + typedef typename SparseMatrixType::ReverseInnerIterator ReverseInnerIterator; + + enum { + CoeffReadCost = NumTraits<_Scalar>::ReadCost, + Flags = SparseMatrixType::Flags + }; + + evaluator() : m_matrix(0) {} + evaluator(const SparseMatrixType &mat) : m_matrix(&mat) {} + + operator SparseMatrixType&() { return m_matrix->const_cast_derived(); } + operator const SparseMatrixType&() const { return *m_matrix; } + + Scalar coeff(Index row, Index col) const { return m_matrix->coeff(row,col); } + + const SparseMatrixType *m_matrix; +}; + +} +#endif + } // end namespace Eigen #endif // EIGEN_DYNAMIC_SPARSEMATRIX_H -- cgit v1.2.3 From b051bbd64fcde21a352ff35d23adcd00afaf845d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:21:47 +0200 Subject: Make unsupport sparse solvers use SparseSolverBase --- unsupported/Eigen/src/IterativeSolvers/DGMRES.h | 13 +++++++++---- unsupported/Eigen/src/IterativeSolvers/GMRES.h | 15 +++++++++------ .../Eigen/src/IterativeSolvers/IncompleteCholesky.h | 15 ++++++++++++--- unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h | 19 +++++++++++++------ unsupported/Eigen/src/IterativeSolvers/MINRES.h | 19 ++++++++++++------- 5 files changed, 55 insertions(+), 26 deletions(-) diff --git a/unsupported/Eigen/src/IterativeSolvers/DGMRES.h b/unsupported/Eigen/src/IterativeSolvers/DGMRES.h index 9fcc8a8d9..fe0bfd948 100644 --- a/unsupported/Eigen/src/IterativeSolvers/DGMRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/DGMRES.h @@ -108,6 +108,7 @@ class DGMRES : public IterativeSolverBase > using Base::m_isInitialized; using Base::m_tolerance; public: + using Base::_solve_impl; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -138,6 +139,7 @@ class DGMRES : public IterativeSolverBase > ~DGMRES() {} +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * \a x0 as an initial solution. * @@ -153,10 +155,11 @@ class DGMRES : public IterativeSolverBase > return internal::solve_retval_with_guess (*this, b.derived(), x0); } +#endif /** \internal */ template - void _solveWithGuess(const Rhs& b, Dest& x) const + void _solve_with_guess_impl(const Rhs& b, Dest& x) const { bool failed = false; for(int j=0; j > /** \internal */ template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, MatrixBase& x) const { x = b; - _solveWithGuess(b,x); + _solve_with_guess_impl(b,x.derived()); } /** * Get the restart value @@ -522,6 +525,7 @@ int DGMRES<_MatrixType, _Preconditioner>::dgmresApplyDeflation(const RhsType &x, return 0; } +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -533,10 +537,11 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif } // end namespace Eigen #endif diff --git a/unsupported/Eigen/src/IterativeSolvers/GMRES.h b/unsupported/Eigen/src/IterativeSolvers/GMRES.h index 67498705b..fd76a9d2c 100644 --- a/unsupported/Eigen/src/IterativeSolvers/GMRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/GMRES.h @@ -281,6 +281,7 @@ private: int m_restart; public: + using Base::_solve_impl; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -315,6 +316,7 @@ public: */ void set_restart(const int restart) { m_restart=restart; } +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * \a x0 as an initial solution. * @@ -330,10 +332,11 @@ public: return internal::solve_retval_with_guess (*this, b.derived(), x0); } +#endif /** \internal */ template - void _solveWithGuess(const Rhs& b, Dest& x) const + void _solve_with_guess_impl(const Rhs& b, Dest& x) const { bool failed = false; for(int j=0; j - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, MatrixBase &x) const { x = b; if(x.squaredNorm() == 0) return; // Check Zero right hand side - _solveWithGuess(b,x); + _solve_with_guess_impl(b,x.derived()); } protected: }; - +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -376,12 +379,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal - +#endif } // end namespace Eigen #endif // EIGEN_GMRES_H diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h index 661c1f2e0..1ee1c89b2 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h @@ -27,8 +27,11 @@ namespace Eigen { */ template > -class IncompleteCholesky : internal::noncopyable +class IncompleteCholesky : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; public: typedef SparseMatrix MatrixType; typedef _OrderingType OrderingType; @@ -89,7 +92,7 @@ class IncompleteCholesky : internal::noncopyable } template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, Dest& x) const { eigen_assert(m_factorizationIsOk && "factorize() should be called first"); if (m_perm.rows() == b.rows()) @@ -103,6 +106,8 @@ class IncompleteCholesky : internal::noncopyable x = m_perm * x; x = m_scal.asDiagonal() * x; } + +#ifndef EIGEN_TEST_EVALUATORS template inline const internal::solve_retval solve(const MatrixBase& b) const { @@ -112,13 +117,14 @@ class IncompleteCholesky : internal::noncopyable && "IncompleteLLT::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#endif + protected: SparseMatrix m_L; // The lower part stored in CSC ScalarType m_scal; // The vector for scaling the matrix Scalar m_shift; //The initial shift parameter bool m_analysisIsOk; bool m_factorizationIsOk; - bool m_isInitialized; ComputationInfo m_info; PermutationType m_perm; @@ -256,6 +262,8 @@ inline void IncompleteCholesky::updateList(const Idx listCol[rowIdx(jk)].push_back(col); } } + +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -272,6 +280,7 @@ struct solve_retval, Rhs> }; } // end namespace internal +#endif } // end namespace Eigen diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h index 67e780181..e86f65644 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h @@ -13,8 +13,12 @@ namespace Eigen { template -class IncompleteLU +class IncompleteLU : public SparseSolverBase > { + protected: + typedef SparseSolverBase > Base; + using Base::m_isInitialized; + typedef _Scalar Scalar; typedef Matrix Vector; typedef typename Vector::Index Index; @@ -23,10 +27,10 @@ class IncompleteLU public: typedef Matrix MatrixType; - IncompleteLU() : m_isInitialized(false) {} + IncompleteLU() {} template - IncompleteLU(const MatrixType& mat) : m_isInitialized(false) + IncompleteLU(const MatrixType& mat) { compute(mat); } @@ -71,12 +75,13 @@ class IncompleteLU } template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, Dest& x) const { x = m_lu.template triangularView().solve(b); x = m_lu.template triangularView().solve(x); } +#ifndef EIGEN_TEST_EVALUATORS template inline const internal::solve_retval solve(const MatrixBase& b) const { @@ -85,12 +90,13 @@ class IncompleteLU && "IncompleteLU::solve(): invalid number of rows of the right hand side matrix b"); return internal::solve_retval(*this, b.derived()); } +#endif protected: FactorType m_lu; - bool m_isInitialized; }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -102,11 +108,12 @@ struct solve_retval, Rhs> template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal +#endif } // end namespace Eigen diff --git a/unsupported/Eigen/src/IterativeSolvers/MINRES.h b/unsupported/Eigen/src/IterativeSolvers/MINRES.h index 98f9ecc17..28d5c692d 100644 --- a/unsupported/Eigen/src/IterativeSolvers/MINRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/MINRES.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2012 Giacomo Po -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -217,6 +217,7 @@ namespace Eigen { using Base::m_info; using Base::m_isInitialized; public: + using Base::_solve_impl; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -244,7 +245,8 @@ namespace Eigen { /** Destructor. */ ~MINRES(){} - + +#ifndef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * \a x0 as an initial solution. * @@ -260,10 +262,11 @@ namespace Eigen { return internal::solve_retval_with_guess (*this, b.derived(), x0); } +#endif /** \internal */ template - void _solveWithGuess(const Rhs& b, Dest& x) const + void _solve_with_guess_impl(const Rhs& b, Dest& x) const { m_iterations = Base::maxIterations(); m_error = Base::m_tolerance; @@ -284,16 +287,17 @@ namespace Eigen { /** \internal */ template - void _solve(const Rhs& b, Dest& x) const + void _solve_impl(const Rhs& b, MatrixBase &x) const { x.setZero(); - _solveWithGuess(b,x); + _solve_with_guess_impl(b,x.derived()); } protected: }; +#ifndef EIGEN_TEST_EVALUATORS namespace internal { template @@ -305,12 +309,13 @@ namespace Eigen { template void evalTo(Dest& dst) const { - dec()._solve(rhs(),dst); + dec()._solve_impl(rhs(),dst); } }; } // end namespace internal - +#endif + } // end namespace Eigen #endif // EIGEN_MINRES_H -- cgit v1.2.3 From daad9585a3635223b273cb45ba2a965d91060ff8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:24:07 +0200 Subject: Fix Kronecker product in legacy mode. --- unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h index b8f2cba17..ca66d4d89 100644 --- a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h @@ -215,7 +215,7 @@ struct traits > typedef typename remove_all<_Lhs>::type Lhs; typedef typename remove_all<_Rhs>::type Rhs; typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, typename traits::StorageKind>::ret StorageKind; + typedef typename cwise_promote_storage_type::StorageKind, typename traits::StorageKind, scalar_product_op >::ret StorageKind; typedef typename promote_index_type::type Index; enum { -- cgit v1.2.3 From 8754341848b125b1f720b9b210875aa1543666d8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:25:13 +0200 Subject: Fix remaining garbage during a merge. --- unsupported/Eigen/MPRealSupport | 4 ---- 1 file changed, 4 deletions(-) diff --git a/unsupported/Eigen/MPRealSupport b/unsupported/Eigen/MPRealSupport index 630e0aa77..8e42965a3 100644 --- a/unsupported/Eigen/MPRealSupport +++ b/unsupported/Eigen/MPRealSupport @@ -159,11 +159,7 @@ int main() { if(rows==0 || cols==0 || depth==0) return; -<<<<<<< local -======= - ->>>>>>> other mpreal acc1(0,mpfr_get_prec(blockA[0].mpfr_srcptr())), tmp (0,mpfr_get_prec(blockA[0].mpfr_srcptr())); -- cgit v1.2.3 From 72c4f8ca8fc64a812801295babfb6d56ca96f427 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:35:58 +0200 Subject: Disable a few unit tests in unsupported --- unsupported/test/CMakeLists.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 0a6c56c19..5e9e74050 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -5,6 +5,11 @@ add_custom_target(BuildUnsupported) include_directories(../../test ../../unsupported ../../Eigen ${CMAKE_CURRENT_BINARY_DIR}/../../test) + +if(EIGEN_TEST_NO_EVALUATORS) + add_definitions("-DEIGEN_TEST_NO_EVALUATORS=1") +endif(EIGEN_TEST_NO_EVALUATORS) + find_package(GoogleHash) if(GOOGLEHASH_FOUND) add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT") @@ -28,18 +33,23 @@ endif(ADOLC_FOUND) ei_add_test(NonLinearOptimization) ei_add_test(NumericalDiff) +if(EIGEN_TEST_NO_EVALUATORS) ei_add_test(autodiff_scalar) ei_add_test(autodiff) +endif() if (NOT CMAKE_CXX_COMPILER MATCHES "clang\\+\\+$") ei_add_test(BVH) endif() +if(EIGEN_TEST_NO_EVALUATORS) ei_add_test(matrix_exponential) ei_add_test(matrix_function) ei_add_test(matrix_power) ei_add_test(matrix_square_root) ei_add_test(alignedvector3) +endif() + ei_add_test(FFT) find_package(MPFR 2.3.0) @@ -86,12 +96,14 @@ endif() ei_add_test(polynomialsolver) ei_add_test(polynomialutils) -ei_add_test(kronecker_product) ei_add_test(splines) ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) +if(EIGEN_TEST_NO_EVALUATORS) ei_add_test(bdcsvd) +ei_add_test(kronecker_product) +endif() option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF) if(EIGEN_TEST_CXX11) -- cgit v1.2.3 From 1f398dfc826c2427375e6aa6a15bfe23383d76f7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 18:31:54 +0200 Subject: Factorize *SVD::solve to SVDBase --- Eigen/src/SVD/JacobiSVD.h | 71 ----------------------------------------- Eigen/src/SVD/SVDBase.h | 70 ++++++++++++++++++++++++++++++++++++++++ unsupported/test/CMakeLists.txt | 2 +- 3 files changed, 71 insertions(+), 72 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 3d778516a..2b9d03c2b 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -592,47 +592,12 @@ template class JacobiSVD return compute(matrix, m_computationOptions); } - /** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A. - * - * \param b the right-hand-side of the equation to solve. - * - * \note Solving requires both U and V to be computed. Thin U and V are enough, there is no need for full U or V. - * - * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. - * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. - */ -#ifdef EIGEN_TEST_EVALUATORS - template - inline const Solve - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return Solve(*this, b.derived()); - } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return internal::solve_retval(*this, b.derived()); - } -#endif - using Base::computeU; using Base::computeV; using Base::rows; using Base::cols; using Base::rank; - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_DEVICE_FUNC - void _solve_impl(const RhsType &rhs, DstType &dst) const; - #endif - private: void allocate(Index rows, Index cols, unsigned int computationOptions); @@ -817,42 +782,6 @@ JacobiSVD::compute(const MatrixType& matrix, unsig return *this; } -#ifndef EIGEN_PARSED_BY_DOXYGEN -template -template -void JacobiSVD<_MatrixType,QRPreconditioner>::_solve_impl(const RhsType &rhs, DstType &dst) const -{ - eigen_assert(rhs.rows() == rows()); - - // A = U S V^* - // So A^{-1} = V S^{-1} U^* - - Matrix tmp; - Index l_rank = rank(); - - tmp.noalias() = m_matrixU.leftCols(l_rank).adjoint() * rhs; - tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp; - dst = m_matrixV.leftCols(l_rank) * tmp; -} -#endif - -namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef JacobiSVD<_MatrixType, QRPreconditioner> JacobiSVDType; - EIGEN_MAKE_SOLVE_HELPERS(JacobiSVDType,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; -#endif -} // end namespace internal - #ifndef __CUDACC__ /** \svd_module * diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h index 61b01fb8a..a4bb97f4b 100644 --- a/Eigen/src/SVD/SVDBase.h +++ b/Eigen/src/SVD/SVDBase.h @@ -190,6 +190,41 @@ public: inline Index rows() const { return m_rows; } inline Index cols() const { return m_cols; } + + /** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A. + * + * \param b the right-hand-side of the equation to solve. + * + * \note Solving requires both U and V to be computed. Thin U and V are enough, there is no need for full U or V. + * + * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. + * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. + */ +#ifdef EIGEN_TEST_EVALUATORS + template + inline const Solve + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + eigen_assert(computeU() && computeV() && "SVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); + return Solve(derived(), b.derived()); + } +#else + template + inline const internal::solve_retval + solve(const MatrixBase& b) const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + eigen_assert(computeU() && computeV() && "SVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); + return internal::solve_retval(*this, b.derived()); + } +#endif + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif protected: // return true if already allocated @@ -220,6 +255,41 @@ protected: }; +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void SVDBase::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + eigen_assert(rhs.rows() == rows()); + + // A = U S V^* + // So A^{-1} = V S^{-1} U^* + + Matrix tmp; + Index l_rank = rank(); + + tmp.noalias() = m_matrixU.leftCols(l_rank).adjoint() * rhs; + tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp; + dst = m_matrixV.leftCols(l_rank) * tmp; +} +#endif + +namespace internal { +#ifndef EIGEN_TEST_EVALUATORS +template +struct solve_retval, Rhs> + : solve_retval_base, Rhs> +{ + typedef SVDBase SVDType; + EIGEN_MAKE_SOLVE_HELPERS(SVDType,Rhs) + + template void evalTo(Dest& dst) const + { + dec().derived()._solve_impl(rhs(), dst); + } +}; +#endif +} // end namespace internal template bool SVDBase::allocate(Index rows, Index cols, unsigned int computationOptions) diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 5e9e74050..970a05bbd 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -100,8 +100,8 @@ ei_add_test(splines) ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) -if(EIGEN_TEST_NO_EVALUATORS) ei_add_test(bdcsvd) +if(EIGEN_TEST_NO_EVALUATORS) ei_add_test(kronecker_product) endif() -- cgit v1.2.3 From 47829e2d16c2bc4fba6aef8fd1b7712a9db839eb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 18:32:59 +0200 Subject: Disable solve_ret_val like mechanism with evaluator enabled --- Eigen/src/misc/Solve.h | 4 +++- Eigen/src/misc/SparseSolve.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Eigen/src/misc/Solve.h b/Eigen/src/misc/Solve.h index 7f70d60af..ebdd981d0 100644 --- a/Eigen/src/misc/Solve.h +++ b/Eigen/src/misc/Solve.h @@ -10,6 +10,8 @@ #ifndef EIGEN_MISC_SOLVE_H #define EIGEN_MISC_SOLVE_H +#ifndef EIGEN_TEST_EVALUATORS + namespace Eigen { namespace internal { @@ -72,5 +74,5 @@ template struct solve_retval_base : Base(dec, rhs) {} } // end namespace Eigen - +#endif // EIGEN_TEST_EVALUATORS #endif // EIGEN_MISC_SOLVE_H diff --git a/Eigen/src/misc/SparseSolve.h b/Eigen/src/misc/SparseSolve.h index 05caa9266..2396dc8e8 100644 --- a/Eigen/src/misc/SparseSolve.h +++ b/Eigen/src/misc/SparseSolve.h @@ -10,6 +10,8 @@ #ifndef EIGEN_SPARSE_SOLVE_H #define EIGEN_SPARSE_SOLVE_H +#ifndef EIGEN_TEST_EVALUATORS + namespace Eigen { namespace internal { @@ -127,4 +129,6 @@ template struct solve_ } // end namespace Eigen +#endif // EIGEN_TEST_EVALUATORS + #endif // EIGEN_SPARSE_SOLVE_H -- cgit v1.2.3 From a96f3d629cfd5e562430f49c9c4d632c365e8020 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 22:30:23 +0200 Subject: Clean bdcsvd --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 73 ++++------------------------------- 1 file changed, 7 insertions(+), 66 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index a7c369633..829446911 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -57,6 +57,8 @@ class BDCSVD : public SVDBase > public: using Base::rows; using Base::cols; + using Base::computeU; + using Base::computeV; typedef _MatrixType MatrixType; typedef typename MatrixType::Scalar Scalar; @@ -72,15 +74,10 @@ public: MatrixOptions = MatrixType::Options }; - typedef Matrix - MatrixUType; - typedef Matrix - MatrixVType; - typedef typename internal::plain_diag_type::type SingularValuesType; - typedef typename internal::plain_row_type::type RowType; - typedef typename internal::plain_col_type::type ColType; + typedef typename Base::MatrixUType MatrixUType; + typedef typename Base::MatrixVType MatrixVType; + typedef typename Base::SingularValuesType SingularValuesType; + typedef Matrix MatrixX; typedef Matrix MatrixXr; typedef Matrix VectorType; @@ -155,27 +152,6 @@ public: eigen_assert(s>3 && "BDCSVD the size of the algo switch has to be greater than 3"); algoswap = s; } - - - /** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A. - * - * \param b the right - hand - side of the equation to solve. - * - * \note Solving requires both U and V to be computed. Thin U and V are enough, there is no need for full U or V. - * - * \note SVD solving is implicitly least - squares. Thus, this method serves both purposes of exact solving and least - squares solving. - * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(this->m_isInitialized && "BDCSVD is not initialized."); - eigen_assert(computeU() && computeV() && - "BDCSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return internal::solve_retval(*this, b.derived()); - } - const MatrixUType& matrixU() const { @@ -188,11 +164,9 @@ public: { eigen_assert(this->computeU() && "This SVD decomposition didn't compute U. Did you ask for it?"); return this->m_matrixU; - } - + } } - const MatrixVType& matrixV() const { eigen_assert(this->m_isInitialized && "SVD is not initialized."); @@ -206,9 +180,6 @@ public: return this->m_matrixV; } } - - using Base::computeU; - using Base::computeV; private: void allocate(Index rows, Index cols, unsigned int computationOptions); @@ -898,36 +869,6 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index }//end deflation -namespace internal{ - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef BDCSVD<_MatrixType> BDCSVDType; - EIGEN_MAKE_SOLVE_HELPERS(BDCSVDType, Rhs) - - template void evalTo(Dest& dst) const - { - eigen_assert(rhs().rows() == dec().rows()); - // A = U S V^* - // So A^{ - 1} = V S^{ - 1} U^* - Index diagSize = (std::min)(dec().rows(), dec().cols()); - typename BDCSVDType::SingularValuesType invertedSingVals(diagSize); - Index nonzeroSingVals = dec().nonzeroSingularValues(); - invertedSingVals.head(nonzeroSingVals) = dec().singularValues().head(nonzeroSingVals).array().inverse(); - invertedSingVals.tail(diagSize - nonzeroSingVals).setZero(); - - dst = dec().matrixV().leftCols(diagSize) - * invertedSingVals.asDiagonal() - * dec().matrixU().leftCols(diagSize).adjoint() - * rhs(); - return; - } -}; - -} //end namespace internal - /** \svd_module * * \return the singular value decomposition of \c *this computed by -- cgit v1.2.3 From c82dc227f19e75571ff4d8c47dfbd66765c8dbc5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 3 Sep 2014 10:15:24 +0200 Subject: Cleaning in BDCSVD (formating, handling of transpose case, remove some for loops) --- Eigen/src/SVD/SVDBase.h | 1 - unsupported/Eigen/src/BDCSVD/BDCSVD.h | 441 ++++++++++++++++------------------ 2 files changed, 202 insertions(+), 240 deletions(-) diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h index a4bb97f4b..60a5aabb6 100644 --- a/Eigen/src/SVD/SVDBase.h +++ b/Eigen/src/SVD/SVDBase.h @@ -267,7 +267,6 @@ void SVDBase::_solve_impl(const RhsType &rhs, DstType &dst) const Matrix tmp; Index l_rank = rank(); - tmp.noalias() = m_matrixU.leftCols(l_rank).adjoint() * rhs; tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp; dst = m_matrixV.leftCols(l_rank) * tmp; diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index 829446911..64cee029b 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -19,10 +19,6 @@ #ifndef EIGEN_BDCSVD_H #define EIGEN_BDCSVD_H -#define EPSILON 0.0000000000000001 - -#define ALGOSWAP 16 - namespace Eigen { template class BDCSVD; @@ -88,7 +84,7 @@ public: * The default constructor is useful in cases in which the user intends to * perform decompositions via BDCSVD::compute(const MatrixType&). */ - BDCSVD() : algoswap(ALGOSWAP), m_numIters(0) + BDCSVD() : m_algoswap(16), m_numIters(0) {} @@ -99,7 +95,7 @@ public: * \sa BDCSVD() */ BDCSVD(Index rows, Index cols, unsigned int computationOptions = 0) - : algoswap(ALGOSWAP), m_numIters(0) + : m_algoswap(16), m_numIters(0) { allocate(rows, cols, computationOptions); } @@ -115,7 +111,7 @@ public: * available with the (non - default) FullPivHouseholderQR preconditioner. */ BDCSVD(const MatrixType& matrix, unsigned int computationOptions = 0) - : algoswap(ALGOSWAP), m_numIters(0) + : m_algoswap(16), m_numIters(0) { compute(matrix, computationOptions); } @@ -150,35 +146,7 @@ public: void setSwitchSize(int s) { eigen_assert(s>3 && "BDCSVD the size of the algo switch has to be greater than 3"); - algoswap = s; - } - - const MatrixUType& matrixU() const - { - eigen_assert(this->m_isInitialized && "SVD is not initialized."); - if (isTranspose){ - eigen_assert(this->computeV() && "This SVD decomposition didn't compute U. Did you ask for it?"); - return this->m_matrixV; - } - else - { - eigen_assert(this->computeU() && "This SVD decomposition didn't compute U. Did you ask for it?"); - return this->m_matrixU; - } - } - - const MatrixVType& matrixV() const - { - eigen_assert(this->m_isInitialized && "SVD is not initialized."); - if (isTranspose){ - eigen_assert(this->computeU() && "This SVD decomposition didn't compute V. Did you ask for it?"); - return this->m_matrixU; - } - else - { - eigen_assert(this->computeV() && "This SVD decomposition didn't compute V. Did you ask for it?"); - return this->m_matrixV; - } + m_algoswap = s; } private: @@ -194,15 +162,26 @@ private: void deflation43(Index firstCol, Index shift, Index i, Index size); void deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size); void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift); - void copyUV(const typename internal::UpperBidiagonalization::HouseholderUSequenceType& householderU, - const typename internal::UpperBidiagonalization::HouseholderVSequenceType& householderV); + template + void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); protected: MatrixXr m_naiveU, m_naiveV; MatrixXr m_computed; - Index nRec; - int algoswap; - bool isTranspose, compU, compV; + Index m_nRec; + int m_algoswap; + bool m_isTranspose, m_compU, m_compV; + + using Base::m_singularValues; + using Base::m_diagSize; + using Base::m_computeFullU; + using Base::m_computeFullV; + using Base::m_computeThinU; + using Base::m_computeThinV; + using Base::m_matrixU; + using Base::m_matrixV; + using Base::m_isInitialized; + using Base::m_nonzeroSingularValues; public: int m_numIters; @@ -213,50 +192,35 @@ public: template void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) { - isTranspose = (cols > rows); - if (Base::allocate(rows, cols, computationOptions)) return; - m_computed = MatrixXr::Zero(this->m_diagSize + 1, this->m_diagSize ); - if (isTranspose){ - compU = this->computeU(); - compV = this->computeV(); - } - else - { - compV = this->computeU(); - compU = this->computeV(); - } - if (compU) m_naiveU = MatrixXr::Zero(this->m_diagSize + 1, this->m_diagSize + 1 ); - else m_naiveU = MatrixXr::Zero(2, this->m_diagSize + 1 ); + m_isTranspose = (cols > rows); + if (Base::allocate(rows, cols, computationOptions)) + return; - if (compV) m_naiveV = MatrixXr::Zero(this->m_diagSize, this->m_diagSize); + m_computed = MatrixXr::Zero(m_diagSize + 1, m_diagSize ); + m_compU = computeV(); + m_compV = computeU(); + if (m_isTranspose) + std::swap(m_compU, m_compV); - - //should be changed for a cleaner implementation - if (isTranspose){ - bool aux; - if (this->computeU()||this->computeV()){ - aux = this->m_computeFullU; - this->m_computeFullU = this->m_computeFullV; - this->m_computeFullV = aux; - aux = this->m_computeThinU; - this->m_computeThinU = this->m_computeThinV; - this->m_computeThinV = aux; - } - } + if (m_compU) m_naiveU = MatrixXr::Zero(m_diagSize + 1, m_diagSize + 1 ); + else m_naiveU = MatrixXr::Zero(2, m_diagSize + 1 ); + + if (m_compV) m_naiveV = MatrixXr::Zero(m_diagSize, m_diagSize); }// end allocate // Methode which compute the BDCSVD for the int template<> -BDCSVD >& BDCSVD >::compute(const MatrixType& matrix, unsigned int computationOptions) { +BDCSVD >& BDCSVD >::compute(const MatrixType& matrix, unsigned int computationOptions) +{ allocate(matrix.rows(), matrix.cols(), computationOptions); - this->m_nonzeroSingularValues = 0; + m_nonzeroSingularValues = 0; m_computed = Matrix::Zero(rows(), cols()); - for (int i=0; im_diagSize; i++) { - this->m_singularValues.coeffRef(i) = 0; - } - if (this->m_computeFullU) this->m_matrixU = Matrix::Zero(rows(), rows()); - if (this->m_computeFullV) this->m_matrixV = Matrix::Zero(cols(), cols()); - this->m_isInitialized = true; + + m_singularValues.head(m_diagSize).setZero(); + + if (m_computeFullU) m_matrixU.setZero(rows(), rows()); + if (m_computeFullV) m_matrixV.setZero(cols(), cols()); + m_isInitialized = true; return *this; } @@ -268,59 +232,62 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign allocate(matrix.rows(), matrix.cols(), computationOptions); using std::abs; - //**** step 1 Bidiagonalization isTranspose = (matrix.cols()>matrix.rows()) ; + //**** step 1 Bidiagonalization m_isTranspose = (matrix.cols()>matrix.rows()) ; MatrixType copy; - if (isTranspose) copy = matrix.adjoint(); - else copy = matrix; + if (m_isTranspose) copy = matrix.adjoint(); + else copy = matrix; internal::UpperBidiagonalization bid(copy); //**** step 2 Divide - m_computed.topRows(this->m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); + m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); m_computed.template bottomRows<1>().setZero(); - divide(0, this->m_diagSize - 1, 0, 0, 0); + divide(0, m_diagSize - 1, 0, 0, 0); //**** step 3 copy - for (int i=0; im_diagSize; i++) { + for (int i=0; im_singularValues.coeffRef(i) = a; - if (a == 0){ - this->m_nonzeroSingularValues = i; - this->m_singularValues.tail(this->m_diagSize - i - 1).setZero(); + m_singularValues.coeffRef(i) = a; + if (a == 0) + { + m_nonzeroSingularValues = i; + m_singularValues.tail(m_diagSize - i - 1).setZero(); break; } - else if (i == this->m_diagSize - 1) + else if (i == m_diagSize - 1) { - this->m_nonzeroSingularValues = i + 1; + m_nonzeroSingularValues = i + 1; break; } } - copyUV(bid.householderU(), bid.householderV()); - this->m_isInitialized = true; + if(m_isTranspose) copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU); + else copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV); + m_isInitialized = true; return *this; }// end compute template -void BDCSVD::copyUV(const typename internal::UpperBidiagonalization::HouseholderUSequenceType& householderU, - const typename internal::UpperBidiagonalization::HouseholderVSequenceType& householderV) +template +void BDCSVD::copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naiveV) { // Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa - if (this->computeU()){ - Index Ucols = this->m_computeThinU ? this->m_nonzeroSingularValues : householderU.cols(); - this->m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); - Index blockCols = this->m_computeThinU ? this->m_nonzeroSingularValues : this->m_diagSize; - this->m_matrixU.block(0, 0, this->m_diagSize, blockCols) = - m_naiveV.template cast().block(0, 0, this->m_diagSize, blockCols); - this->m_matrixU = householderU * this->m_matrixU; + if (computeU()) + { + Index Ucols = m_computeThinU ? m_nonzeroSingularValues : householderU.cols(); + m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); + Index blockCols = m_computeThinU ? m_nonzeroSingularValues : m_diagSize; + m_matrixU.topLeftCorner(m_diagSize, blockCols) = naiveV.template cast().topLeftCorner(m_diagSize, blockCols); + m_matrixU = householderU * m_matrixU; } - if (this->computeV()){ - Index Vcols = this->m_computeThinV ? this->m_nonzeroSingularValues : householderV.cols(); - this->m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); - Index blockCols = this->m_computeThinV ? this->m_nonzeroSingularValues : this->m_diagSize; - this->m_matrixV.block(0, 0, this->m_diagSize, blockCols) = - m_naiveU.template cast().block(0, 0, this->m_diagSize, blockCols); - this->m_matrixV = householderV * this->m_matrixV; + if (computeV()) + { + Index Vcols = m_computeThinV ? m_nonzeroSingularValues : householderV.cols(); + m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); + Index blockCols = m_computeThinV ? m_nonzeroSingularValues : m_diagSize; + m_matrixV.topLeftCorner(m_diagSize, blockCols) = naiveU.template cast().topLeftCorner(m_diagSize, blockCols); + m_matrixV = householderV * m_matrixV; } } @@ -335,8 +302,7 @@ void BDCSVD::copyUV(const typename internal::UpperBidiagonalization< //@param shift : Each time one takes the left submatrix, one must add 1 to the shift. Why? Because! We actually want the last column of the U submatrix // to become the first column (*coeff) and to shift all the other columns to the right. There are more details on the reference paper. template -void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, - Index firstColW, Index shift) +void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift) { // requires nbRows = nbCols + 1; using std::pow; @@ -351,21 +317,19 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, MatrixXr l, f; // We use the other algorithm which is more efficient for small // matrices. - if (n < algoswap){ - JacobiSVD b(m_computed.block(firstCol, firstCol, n + 1, n), - ComputeFullU | (ComputeFullV * compV)) ; - if (compU) m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() << b.matrixU(); + if (n < m_algoswap) + { + JacobiSVD b(m_computed.block(firstCol, firstCol, n + 1, n), ComputeFullU | (m_compV ? ComputeFullV : 0)) ; + if (m_compU) + m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = b.matrixU(); else { - m_naiveU.row(0).segment(firstCol, n + 1).real() << b.matrixU().row(0); - m_naiveU.row(1).segment(firstCol, n + 1).real() << b.matrixU().row(n); + m_naiveU.row(0).segment(firstCol, n + 1).real() = b.matrixU().row(0); + m_naiveU.row(1).segment(firstCol, n + 1).real() = b.matrixU().row(n); } - if (compV) m_naiveV.block(firstRowW, firstColW, n, n).real() << b.matrixV(); + if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = b.matrixV(); m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero(); - for (int i=0; i::divide (Index firstCol, Index lastCol, Index firstRowW, // right submatrix before the left one. divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift); divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1); - if (compU) + if (m_compU) { lambda = m_naiveU(firstCol + k, firstCol + k); phi = m_naiveU(firstCol + k + 1, lastCol + 1); @@ -386,9 +350,8 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, lambda = m_naiveU(1, firstCol + k); phi = m_naiveU(0, lastCol + 1); } - r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) - + abs(betaK * phi) * abs(betaK * phi)); - if (compU) + r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) + abs(betaK * phi) * abs(betaK * phi)); + if (m_compU) { l = m_naiveU.row(firstCol + k).segment(firstCol, k); f = m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1); @@ -398,7 +361,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, l = m_naiveU.row(1).segment(firstCol, k); f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1); } - if (compV) m_naiveV(firstRowW+k, firstColW) = 1; + if (m_compV) m_naiveV(firstRowW+k, firstColW) = 1; if (r0 == 0) { c0 = 1; @@ -409,21 +372,18 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, c0 = alphaK * lambda / r0; s0 = betaK * phi / r0; } - if (compU) + if (m_compU) { MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1)); // we shiftW Q1 to the right for (Index i = firstCol + k - 1; i >= firstCol; i--) - { - m_naiveU.col(i + 1).segment(firstCol, k + 1) << m_naiveU.col(i).segment(firstCol, k + 1); - } + m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1); // we shift q1 at the left with a factor c0 - m_naiveU.col(firstCol).segment( firstCol, k + 1) << (q1 * c0); + m_naiveU.col(firstCol).segment( firstCol, k + 1) = (q1 * c0); // last column = q1 * - s0 - m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) << (q1 * ( - s0)); + m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * ( - s0)); // first column = q2 * s0 - m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) << - m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *s0; + m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) = m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0; // q2 *= c0 m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0; } @@ -432,9 +392,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, RealScalar q1 = (m_naiveU(0, firstCol + k)); // we shift Q1 to the right for (Index i = firstCol + k - 1; i >= firstCol; i--) - { m_naiveU(0, i + 1) = m_naiveU(0, i); - } // we shift q1 at the left with a factor c0 m_naiveU(0, firstCol) = (q1 * c0); // last column = q1 * - s0 @@ -447,8 +405,8 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero(); } m_computed(firstCol + shift, firstCol + shift) = r0; - m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) << alphaK * l.transpose().real(); - m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) << betaK * f.transpose().real(); + m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); + m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); // Second part: try to deflate singular values in combined matrix @@ -458,9 +416,9 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, MatrixXr UofSVD, VofSVD; VectorType singVals; computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); - if (compU) m_naiveU.block(firstCol, firstCol, n + 1, n + 1) *= UofSVD; - else m_naiveU.block(0, firstCol, 2, n + 1) *= UofSVD; - if (compV) m_naiveV.block(firstRowW, firstColW, n, n) *= VofSVD; + if (m_compU) m_naiveU.block(firstCol, firstCol, n + 1, n + 1) *= UofSVD; // FIXME this requires a temporary + else m_naiveU.block(0, firstCol, 2, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time + if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n) *= VofSVD; // FIXME this requires a temporary m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; }// end divide @@ -468,7 +426,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, // Compute SVD of m_computed.block(firstCol, firstCol, n + 1, n); this block only has non-zeros in // the first column and on the diagonal and has undergone deflation, so diagonal is in increasing // order except for possibly the (0,0) entry. The computed SVD is stored U, singVals and V, except -// that if compV is false, then V is not computed. Singular values are sorted in decreasing order. +// that if m_compV is false, then V is not computed. Singular values are sorted in decreasing order. // // TODO Opportunities for optimization: better root finding algo, better stopping criterion, better // handling of round-off errors, be consistent in ordering @@ -483,7 +441,7 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec // compute singular values and vectors (in decreasing order) singVals.resize(n); U.resize(n+1, n+1); - if (compV) V.resize(n, n); + if (m_compV) V.resize(n, n); if (col0.hasNaN() || diag.hasNaN()) return; @@ -495,7 +453,7 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec // Reverse order so that singular values in increased order singVals.reverseInPlace(); U.leftCols(n) = U.leftCols(n).rowwise().reverse().eval(); - if (compV) V = V.rowwise().reverse().eval(); + if (m_compV) V = V.rowwise().reverse().eval(); } template @@ -504,10 +462,13 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia { using std::abs; using std::swap; + using std::max; Index n = col0.size(); - for (Index k = 0; k < n; ++k) { - if (col0(k) == 0) { + for (Index k = 0; k < n; ++k) + { + if (col0(k) == 0) + { // entry is deflated, so singular value is on diagonal singVals(k) = diag(k); mus(k) = 0; @@ -523,27 +484,29 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia RealScalar mid = left + (right-left) / 2; RealScalar fMid = 1 + (col0.square() / ((diag + mid) * (diag - mid))).sum(); - RealScalar shift; - if (k == n-1 || fMid > 0) shift = left; - else shift = right; + RealScalar shift = (k == n-1 || fMid > 0) ? left : right; // measure everything relative to shift ArrayXr diagShifted = diag - shift; // initial guess RealScalar muPrev, muCur; - if (shift == left) { + if (shift == left) + { muPrev = (right - left) * 0.1; if (k == n-1) muCur = right - left; - else muCur = (right - left) * 0.5; - } else { + else muCur = (right - left) * 0.5; + } + else + { muPrev = -(right - left) * 0.1; muCur = -(right - left) * 0.5; } RealScalar fPrev = 1 + (col0.square() / ((diagShifted - muPrev) * (diag + shift + muPrev))).sum(); RealScalar fCur = 1 + (col0.square() / ((diagShifted - muCur) * (diag + shift + muCur))).sum(); - if (abs(fPrev) < abs(fCur)) { + if (abs(fPrev) < abs(fCur)) + { swap(fPrev, fCur); swap(muPrev, muCur); } @@ -551,7 +514,8 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // rational interpolation: fit a function of the form a / mu + b through the two previous // iterates and use its zero to compute the next iterate bool useBisection = false; - while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (std::max)(abs(muCur), abs(muPrev)) && fCur != fPrev && !useBisection) { + while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && fCur != fPrev && !useBisection) + { ++m_numIters; RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); @@ -567,13 +531,17 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia } // fall back on bisection method if rational interpolation did not work - if (useBisection) { + if (useBisection) + { RealScalar leftShifted, rightShifted; - if (shift == left) { + if (shift == left) + { leftShifted = 1e-30; if (k == 0) rightShifted = right - left; - else rightShifted = (right - left) * 0.6; // theoretically we can take 0.5, but let's be safe - } else { + else rightShifted = (right - left) * 0.6; // theoretically we can take 0.5, but let's be safe + } + else + { leftShifted = -(right - left) * 0.6; rightShifted = -1e-30; } @@ -582,13 +550,17 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia RealScalar fRight = 1 + (col0.square() / ((diagShifted - rightShifted) * (diag + shift + rightShifted))).sum(); assert(fLeft * fRight < 0); - while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (std::max)(abs(leftShifted), abs(rightShifted))) { + while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (max)(abs(leftShifted), abs(rightShifted))) + { RealScalar midShifted = (leftShifted + rightShifted) / 2; RealScalar fMid = 1 + (col0.square() / ((diagShifted - midShifted) * (diag + shift + midShifted))).sum(); - if (fLeft * fMid < 0) { + if (fLeft * fMid < 0) + { rightShifted = midShifted; fRight = fMid; - } else { + } + else + { leftShifted = midShifted; fLeft = fMid; } @@ -615,13 +587,15 @@ void BDCSVD::perturbCol0 (const ArrayXr& col0, const ArrayXr& diag, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) { + using std::sqrt; Index n = col0.size(); - for (Index k = 0; k < n; ++k) { + for (Index k = 0; k < n; ++k) + { if (col0(k) == 0) zhat(k) = 0; - else { + else + { // see equation (3.6) - using std::sqrt; RealScalar tmp = sqrt( (singVals(n-1) + diag(k)) * (mus(n-1) + (shifts(n-1) - diag(k))) @@ -647,16 +621,21 @@ void BDCSVD::computeSingVecs const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V) { Index n = zhat.size(); - for (Index k = 0; k < n; ++k) { - if (zhat(k) == 0) { + for (Index k = 0; k < n; ++k) + { + if (zhat(k) == 0) + { U.col(k) = VectorType::Unit(n+1, k); - if (compV) V.col(k) = VectorType::Unit(n, k); - } else { + if (m_compV) V.col(k) = VectorType::Unit(n, k); + } + else + { U.col(k).head(n) = zhat / (((diag - shifts(k)) - mus(k)) * (diag + singVals[k])); U(n,k) = 0; U.col(k).normalize(); - if (compV) { + if (m_compV) + { V.col(k).tail(n-1) = (diag * zhat / (((diag - shifts(k)) - mus(k)) * (diag + singVals[k]))).tail(n-1); V(0,k) = -1; V.col(k).normalize(); @@ -671,15 +650,17 @@ void BDCSVD::computeSingVecs // i >= 1, di almost null and zi non null. // We use a rotation to zero out zi applied to the left of M template -void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index size){ +void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index size) +{ using std::abs; using std::sqrt; using std::pow; RealScalar c = m_computed(firstCol + shift, firstCol + shift); RealScalar s = m_computed(i, firstCol + shift); RealScalar r = sqrt(pow(abs(c), 2) + pow(abs(s), 2)); - if (r == 0){ - m_computed(i, i)=0; + if (r == 0) + { + m_computed(i, i) = 0; return; } c/=r; @@ -687,7 +668,8 @@ void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index m_computed(firstCol + shift, firstCol + shift) = r; m_computed(i, firstCol + shift) = 0; m_computed(i, i) = 0; - if (compU){ + if (m_compU) + { m_naiveU.col(firstCol).segment(firstCol,size) = c * m_naiveU.col(firstCol).segment(firstCol, size) - s * m_naiveU.col(i).segment(firstCol, size) ; @@ -703,7 +685,8 @@ void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index // i,j >= 1, i != j and |di - dj| < epsilon * norm2(M) // We apply two rotations to have zj = 0; template -void BDCSVD::deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size){ +void BDCSVD::deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size) +{ using std::abs; using std::sqrt; using std::conj; @@ -711,7 +694,8 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi RealScalar c = m_computed(firstColm, firstColm + j - 1); RealScalar s = m_computed(firstColm, firstColm + i - 1); RealScalar r = sqrt(pow(abs(c), 2) + pow(abs(s), 2)); - if (r==0){ + if (r==0) + { m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); return; } @@ -720,7 +704,8 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi m_computed(firstColm + i, firstColm) = r; m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); m_computed(firstColm + j, firstColm) = 0; - if (compU){ + if (m_compU) + { m_naiveU.col(firstColu + i).segment(firstColu, size) = c * m_naiveU.col(firstColu + i).segment(firstColu, size) - s * m_naiveU.col(firstColu + j).segment(firstColu, size) ; @@ -729,7 +714,8 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi (c + s*s/c) * m_naiveU.col(firstColu + j).segment(firstColu, size) + (s/c) * m_naiveU.col(firstColu + i).segment(firstColu, size); } - if (compV){ + if (m_compV) + { m_naiveV.col(firstColW + i).segment(firstRowW, size - 1) = c * m_naiveV.col(firstColW + i).segment(firstRowW, size - 1) + s * m_naiveV.col(firstColW + j).segment(firstRowW, size - 1) ; @@ -743,72 +729,56 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi // acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive] template -void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift){ +void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift) +{ //condition 4.1 using std::sqrt; + using std::abs; const Index length = lastCol + 1 - firstCol; RealScalar norm1 = m_computed.block(firstCol+shift, firstCol+shift, length, 1).squaredNorm(); RealScalar norm2 = m_computed.block(firstCol+shift, firstCol+shift, length, length).diagonal().squaredNorm(); - RealScalar EPS = 10 * NumTraits::epsilon() * sqrt(norm1 + norm2); - if (m_computed(firstCol + shift, firstCol + shift) < EPS){ - m_computed(firstCol + shift, firstCol + shift) = EPS; - } + RealScalar epsilon = 10 * NumTraits::epsilon() * sqrt(norm1 + norm2); + if (m_computed(firstCol + shift, firstCol + shift) < epsilon) + m_computed(firstCol + shift, firstCol + shift) = epsilon; //condition 4.2 - for (Index i=firstCol + shift + 1;i<=lastCol + shift;i++){ - if (std::abs(m_computed(i, firstCol + shift)) < EPS){ + for (Index i=firstCol + shift + 1;i<=lastCol + shift;i++) + if (abs(m_computed(i, firstCol + shift)) < epsilon) m_computed(i, firstCol + shift) = 0; - } - } //condition 4.3 - for (Index i=firstCol + shift + 1;i<=lastCol + shift; i++){ - if (m_computed(i, i) < EPS){ + for (Index i=firstCol + shift + 1;i<=lastCol + shift; i++) + if (m_computed(i, i) < epsilon) deflation43(firstCol, shift, i, length); - } - } //condition 4.4 Index i=firstCol + shift + 1, j=firstCol + shift + k + 1; //we stock the final place of each line - Index *permutation = new Index[length]; + Index *permutation = new Index[length]; // FIXME avoid repeated dynamic memory allocation - for (Index p =1; p < length; p++) { - if (i> firstCol + shift + k){ - permutation[p] = j; - j++; - } else if (j> lastCol + shift) - { - permutation[p] = i; - i++; - } - else - { - if (m_computed(i, i) < m_computed(j, j)){ - permutation[p] = j; - j++; - } - else - { - permutation[p] = i; - i++; - } - } + for (Index p =1; p < length; p++) + { + if (i> firstCol + shift + k) permutation[p] = j++; + else if (j> lastCol + shift) permutation[p] = i++; + else if (m_computed(i, i) < m_computed(j, j)) permutation[p] = j++; + else permutation[p] = i++; } //we do the permutation RealScalar aux; //we stock the current index of each col //and the column of each index - Index *realInd = new Index[length]; - Index *realCol = new Index[length]; - for (int pos = 0; pos< length; pos++){ + Index *realInd = new Index[length]; // FIXME avoid repeated dynamic memory allocation + Index *realCol = new Index[length]; // FIXME avoid repeated dynamic memory allocation + for (int pos = 0; pos< length; pos++) + { realCol[pos] = pos + firstCol + shift; realInd[pos] = pos; } const Index Zero = firstCol + shift; VectorType temp; - for (int i = 1; i < length - 1; i++){ + for (int i = 1; i < length - 1; i++) + { const Index I = i + Zero; const Index realI = realInd[i]; const Index j = permutation[length - i] - Zero; @@ -825,25 +795,25 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index m_computed(J, Zero) = aux; // change columns - if (compU) { + if (m_compU) + { temp = m_naiveU.col(I - shift).segment(firstCol, length + 1); - m_naiveU.col(I - shift).segment(firstCol, length + 1) << - m_naiveU.col(J - shift).segment(firstCol, length + 1); - m_naiveU.col(J - shift).segment(firstCol, length + 1) << temp; + m_naiveU.col(I - shift).segment(firstCol, length + 1) = m_naiveU.col(J - shift).segment(firstCol, length + 1); + m_naiveU.col(J - shift).segment(firstCol, length + 1) = temp; } else { temp = m_naiveU.col(I - shift).segment(0, 2); - m_naiveU.col(I - shift).segment(0, 2) << - m_naiveU.col(J - shift).segment(0, 2); - m_naiveU.col(J - shift).segment(0, 2) << temp; + m_naiveU.col(I - shift).template head<2>() = m_naiveU.col(J - shift).segment(0, 2); + m_naiveU.col(J - shift).template head<2>() = temp; } - if (compV) { + if (m_compV) + { const Index CWI = I + firstColW - Zero; const Index CWJ = J + firstColW - Zero; temp = m_naiveV.col(CWI).segment(firstRowW, length); - m_naiveV.col(CWI).segment(firstRowW, length) << m_naiveV.col(CWJ).segment(firstRowW, length); - m_naiveV.col(CWJ).segment(firstRowW, length) << temp; + m_naiveV.col(CWI).segment(firstRowW, length) = m_naiveV.col(CWJ).segment(firstRowW, length); + m_naiveV.col(CWJ).segment(firstRowW, length) = temp; } //update real pos @@ -852,20 +822,13 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index realInd[J - Zero] = realI; realInd[I - Zero] = j; } - for (Index i = firstCol + shift + 1; i Date: Wed, 3 Sep 2014 22:56:39 +0200 Subject: Disable a test which had never worked without evalautors --- test/sparse_vector.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 5eea9edfd..6cd5a9a8c 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -71,7 +71,10 @@ template void sparse_vector(int rows, int cols) VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2)); VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2)); +#ifdef EIGEN_TEST_EVALUATORS + // the following did not compiled without evaluators VERIFY_IS_APPROX(m1*v2, refM1*refV2); +#endif VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2)); int i = internal::random(0,rows-1); VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i))); -- cgit v1.2.3 From 8846aa6d1b68fb0951c70bc339af93b418117ae2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 4 Sep 2014 09:15:59 +0200 Subject: Optimization: enable cache-efficient application of HouseholderSequence. --- Eigen/src/Householder/BlockHouseholder.h | 73 ++++++++++++++++++++++------- Eigen/src/Householder/HouseholderSequence.h | 34 ++++++++++++-- Eigen/src/QR/HouseholderQR.h | 6 +-- Eigen/src/SVD/UpperBidiagonalization.h | 4 +- 4 files changed, 89 insertions(+), 28 deletions(-) diff --git a/Eigen/src/Householder/BlockHouseholder.h b/Eigen/src/Householder/BlockHouseholder.h index 60dbea5f5..35dbf80a1 100644 --- a/Eigen/src/Householder/BlockHouseholder.h +++ b/Eigen/src/Householder/BlockHouseholder.h @@ -16,48 +16,85 @@ namespace Eigen { namespace internal { + +/** \internal */ +// template +// void make_block_householder_triangular_factor(TriangularFactorType& triFactor, const VectorsType& vectors, const CoeffsType& hCoeffs) +// { +// typedef typename TriangularFactorType::Index Index; +// typedef typename VectorsType::Scalar Scalar; +// const Index nbVecs = vectors.cols(); +// eigen_assert(triFactor.rows() == nbVecs && triFactor.cols() == nbVecs && vectors.rows()>=nbVecs); +// +// for(Index i = 0; i < nbVecs; i++) +// { +// Index rs = vectors.rows() - i; +// // Warning, note that hCoeffs may alias with vectors. +// // It is then necessary to copy it before modifying vectors(i,i). +// typename CoeffsType::Scalar h = hCoeffs(i); +// // This hack permits to pass trough nested Block<> and Transpose<> expressions. +// Scalar *Vii_ptr = const_cast(vectors.data() + vectors.outerStride()*i + vectors.innerStride()*i); +// Scalar Vii = *Vii_ptr; +// *Vii_ptr = Scalar(1); +// triFactor.col(i).head(i).noalias() = -h * vectors.block(i, 0, rs, i).adjoint() +// * vectors.col(i).tail(rs); +// *Vii_ptr = Vii; +// // FIXME add .noalias() once the triangular product can work inplace +// triFactor.col(i).head(i) = triFactor.block(0,0,i,i).template triangularView() +// * triFactor.col(i).head(i); +// triFactor(i,i) = hCoeffs(i); +// } +// } /** \internal */ +// This variant avoid modifications in vectors template void make_block_householder_triangular_factor(TriangularFactorType& triFactor, const VectorsType& vectors, const CoeffsType& hCoeffs) { typedef typename TriangularFactorType::Index Index; - typedef typename VectorsType::Scalar Scalar; const Index nbVecs = vectors.cols(); eigen_assert(triFactor.rows() == nbVecs && triFactor.cols() == nbVecs && vectors.rows()>=nbVecs); - for(Index i = 0; i < nbVecs; i++) + for(Index i = nbVecs-1; i >=0 ; --i) { - Index rs = vectors.rows() - i; - Scalar Vii = vectors(i,i); - vectors.const_cast_derived().coeffRef(i,i) = Scalar(1); - triFactor.col(i).head(i).noalias() = -hCoeffs(i) * vectors.block(i, 0, rs, i).adjoint() - * vectors.col(i).tail(rs); - vectors.const_cast_derived().coeffRef(i, i) = Vii; - // FIXME add .noalias() once the triangular product can work inplace - triFactor.col(i).head(i) = triFactor.block(0,0,i,i).template triangularView() - * triFactor.col(i).head(i); + Index rs = vectors.rows() - i - 1; + Index rt = nbVecs-i-1; + + if(rt>0) + { + triFactor.row(i).tail(rt).noalias() = -hCoeffs(i) * vectors.col(i).tail(rs).adjoint() + * vectors.bottomRightCorner(rs, rt).template triangularView(); + + // FIXME add .noalias() once the triangular product can work inplace + triFactor.row(i).tail(rt) = triFactor.row(i).tail(rt) * triFactor.bottomRightCorner(rt,rt).template triangularView(); + + } triFactor(i,i) = hCoeffs(i); } } -/** \internal */ +/** \internal + * if forward then perform mat = H0 * H1 * H2 * mat + * otherwise perform mat = H2 * H1 * H0 * mat + */ template -void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vectors, const CoeffsType& hCoeffs) +void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vectors, const CoeffsType& hCoeffs, bool forward) { typedef typename MatrixType::Index Index; enum { TFactorSize = MatrixType::ColsAtCompileTime }; Index nbVecs = vectors.cols(); - Matrix T(nbVecs,nbVecs); - make_block_householder_triangular_factor(T, vectors, hCoeffs); - - const TriangularView& V(vectors); + Matrix T(nbVecs,nbVecs); + + if(forward) make_block_householder_triangular_factor(T, vectors, hCoeffs); + else make_block_householder_triangular_factor(T, vectors, hCoeffs.conjugate()); + const TriangularView V(vectors); // A -= V T V^* A Matrix tmp = V.adjoint() * mat; // FIXME add .noalias() once the triangular product can work inplace - tmp = T.template triangularView().adjoint() * tmp; + if(forward) tmp = T.template triangularView() * tmp; + else tmp = T.template triangularView().adjoint() * tmp; mat.noalias() -= V * tmp; } diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 99d3eb21f..111936f0e 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -319,12 +319,36 @@ template class HouseholderS template inline void applyThisOnTheLeft(Dest& dst, Workspace& workspace) const { - workspace.resize(dst.cols()); - for(Index k = 0; k < m_length; ++k) + const Index BlockSize = 1; + // if the entries are large enough, then apply the reflectors by block + if(m_length>BlockSize && dst.cols()>1) + { + for(Index i = 0; i < m_length; i+=BlockSize) + { + Index end = m_trans ? (std::min)(m_length,i+BlockSize) : m_length-i; + Index k = m_trans ? i : (std::max)(Index(0),end-BlockSize); + Index bs = end-k; + Index start = k + m_shift; + + typedef Block::type,Dynamic,Dynamic> SubVectorsType; + SubVectorsType sub_vecs1(m_vectors.const_cast_derived(), Side==OnTheRight ? k : start, + Side==OnTheRight ? start : k, + Side==OnTheRight ? bs : m_vectors.rows()-start, + Side==OnTheRight ? m_vectors.cols()-start : bs); + typename internal::conditional, SubVectorsType&>::type sub_vecs(sub_vecs1); + Block sub_dst(dst,dst.rows()-rows()+m_shift+k,0, rows()-m_shift-k,dst.cols()); + apply_block_householder_on_the_left(sub_dst, sub_vecs, m_coeffs.segment(k, bs), !m_trans); + } + } + else { - Index actual_k = m_trans ? k : m_length-k-1; - dst.bottomRows(rows()-m_shift-actual_k) - .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data()); + workspace.resize(dst.cols()); + for(Index k = 0; k < m_length; ++k) + { + Index actual_k = m_trans ? k : m_length-k-1; + dst.bottomRows(rows()-m_shift-actual_k) + .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), workspace.data()); + } } } diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 136e80ce9..8604fff6f 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -299,8 +299,8 @@ struct householder_qr_inplace_blocked for (k = 0; k < size; k += blockSize) { Index bs = (std::min)(size-k,blockSize); // actual size of the block - Index tcols = cols - k - bs; // trailing columns - Index brows = rows-k; // rows of the block + Index tcols = cols - k - bs; // trailing columns + Index brows = rows-k; // rows of the block // partition the matrix: // A00 | A01 | A02 @@ -318,7 +318,7 @@ struct householder_qr_inplace_blocked if(tcols) { BlockType A21_22 = mat.block(k,k+bs,brows,tcols); - apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint()); + apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment, false); // false == backward } } } diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h index 225b19e3c..0e081254d 100644 --- a/Eigen/src/SVD/UpperBidiagonalization.h +++ b/Eigen/src/SVD/UpperBidiagonalization.h @@ -215,10 +215,10 @@ void upperbidiagonalization_blocked_helper(MatrixType& A, if(k) u_k -= U_k1.adjoint() * X.row(k).head(k).adjoint(); } - // 5 - construct right Householder transform in-placecols + // 5 - construct right Householder transform in-place u_k.makeHouseholderInPlace(tau_u, upper_diagonal[k]); - // this eases the application of Householder transforAions + // this eases the application of Householder transformations // A(k,k+1) will store tau_u later A(k,k+1) = Scalar(1); -- cgit v1.2.3 From 15bad3670b7e9261764fb65037c148ab87ad9d07 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 4 Sep 2014 09:17:01 +0200 Subject: Apply Householder U and V in-place. --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index 64cee029b..fcad104c0 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -279,7 +279,7 @@ void BDCSVD::copyUV(const HouseholderU &householderU, const Househol m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); Index blockCols = m_computeThinU ? m_nonzeroSingularValues : m_diagSize; m_matrixU.topLeftCorner(m_diagSize, blockCols) = naiveV.template cast().topLeftCorner(m_diagSize, blockCols); - m_matrixU = householderU * m_matrixU; + householderU.applyThisOnTheLeft(m_matrixU); } if (computeV()) { @@ -287,7 +287,7 @@ void BDCSVD::copyUV(const HouseholderU &householderU, const Househol m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); Index blockCols = m_computeThinV ? m_nonzeroSingularValues : m_diagSize; m_matrixV.topLeftCorner(m_diagSize, blockCols) = naiveU.template cast().topLeftCorner(m_diagSize, blockCols); - m_matrixV = householderV * m_matrixV; + householderV.applyThisOnTheLeft(m_matrixV); } } @@ -314,7 +314,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, RealScalar betaK; RealScalar r0; RealScalar lambda, phi, c0, s0; - MatrixXr l, f; + VectorType l, f; // We use the other algorithm which is more efficient for small // matrices. if (n < m_algoswap) @@ -385,7 +385,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, // first column = q2 * s0 m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) = m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0; // q2 *= c0 - m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0; + m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0; } else { @@ -408,7 +408,6 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); - // Second part: try to deflate singular values in combined matrix deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); @@ -417,7 +416,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, VectorType singVals; computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); if (m_compU) m_naiveU.block(firstCol, firstCol, n + 1, n + 1) *= UofSVD; // FIXME this requires a temporary - else m_naiveU.block(0, firstCol, 2, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time + else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n) *= VofSVD; // FIXME this requires a temporary m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; @@ -434,7 +433,8 @@ template void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V) { // TODO Get rid of these copies (?) - ArrayXr col0 = m_computed.block(firstCol, firstCol, n, 1); + // FIXME at least preallocate them + ArrayXr col0 = m_computed.col(firstCol).segment(firstCol, n); ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); diag(0) = 0; @@ -446,14 +446,15 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec if (col0.hasNaN() || diag.hasNaN()) return; ArrayXr shifts(n), mus(n), zhat(n); + computeSingVals(col0, diag, singVals, shifts, mus); perturbCol0(col0, diag, singVals, shifts, mus, zhat); computeSingVecs(zhat, diag, singVals, shifts, mus, U, V); // Reverse order so that singular values in increased order singVals.reverseInPlace(); - U.leftCols(n) = U.leftCols(n).rowwise().reverse().eval(); - if (m_compV) V = V.rowwise().reverse().eval(); + U.leftCols(n) = U.leftCols(n).rowwise().reverse().eval(); // FIXME this requires a temporary + if (m_compV) V = V.rowwise().reverse().eval(); // FIXME this requires a temporary } template -- cgit v1.2.3 From b23556bbbd796c078e4310c806feceacc8e8c3e8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 5 Sep 2014 08:50:50 +0200 Subject: Oops, a block size of 1 is not very useful, set it to 48 as in HouseholderQR --- Eigen/src/Householder/HouseholderSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 111936f0e..ab32f7d3f 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -319,7 +319,7 @@ template class HouseholderS template inline void applyThisOnTheLeft(Dest& dst, Workspace& workspace) const { - const Index BlockSize = 1; + const Index BlockSize = 48; // if the entries are large enough, then apply the reflectors by block if(m_length>BlockSize && dst.cols()>1) { -- cgit v1.2.3 From dacd39ea76d488133392b3abecf1c5061ba568d7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 5 Sep 2014 17:51:46 +0200 Subject: Exploit sparse structure in naiveU and naiveV when updating them. --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 54 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index fcad104c0..0167872af 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -164,6 +164,7 @@ private: void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift); template void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); + static void structured_update(Block A, const MatrixXr &B, Index n1); protected: MatrixXr m_naiveU, m_naiveV; @@ -240,6 +241,8 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign internal::UpperBidiagonalization bid(copy); //**** step 2 Divide + m_naiveU.setZero(); + m_naiveV.setZero(); m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); m_computed.template bottomRows<1>().setZero(); divide(0, m_diagSize - 1, 0, 0, 0); @@ -291,6 +294,48 @@ void BDCSVD::copyUV(const HouseholderU &householderU, const Househol } } +/** \internal + * Performs A = A * B exploiting the special structure of the matrix A. Splitting A as: + * A = [A1] + * [A2] + * such that A1.rows()==n1, then we assume that at least half of the columns of A1 and A2 are zeros. + * We can thus pack them prior to the the matrix product. However, this is only worth the effort if the matrix is large + * enough. + */ +template +void BDCSVD::structured_update(Block A, const MatrixXr &B, Index n1) +{ + Index n = A.rows(); + if(n>100) + { + // If the matrices are large enough, let's exploit the sparse strucure of A by + // splitting it in half (wrt n1), and packing the non-zero columns. + DenseIndex n2 = n - n1; + MatrixXr A1(n1,n), A2(n2,n), B1(n,n), B2(n,n); + Index k1=0, k2=0; + for(Index j=0; j::divide (Index firstCol, Index lastCol, Index firstRowW, MatrixXr UofSVD, VofSVD; VectorType singVals; computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); - if (m_compU) m_naiveU.block(firstCol, firstCol, n + 1, n + 1) *= UofSVD; // FIXME this requires a temporary - else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time - if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n) *= VofSVD; // FIXME this requires a temporary + + if (m_compU) structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2); + else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time + + if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n+1)/2); + m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; }// end divide -- cgit v1.2.3 From 188a13f9fe235e1579a1e2da048b3595d60e37e8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 8 Sep 2014 09:50:03 +0200 Subject: Fix compilation of coeff(Index) on sub-inner-panels --- Eigen/src/Core/Block.h | 3 ++- Eigen/src/Core/CoreEvaluators.h | 2 +- Eigen/src/Core/MapBase.h | 6 ++++++ test/block.cpp | 8 ++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 0f3ab304a..2d62f7a46 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -101,7 +101,8 @@ struct traits > : traits::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags = (traits::Flags & DirectAccessBit) | FlagsLvalueBit | FlagsRowMajorBit // FIXME DirectAccessBit should not be handled by expressions + Flags = (traits::Flags & DirectAccessBit) | FlagsLvalueBit | FlagsRowMajorBit + // FIXME DirectAccessBit should not be handled by expressions #endif }; }; diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 8c9190a0e..b8dc05d98 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -722,7 +722,7 @@ struct evaluator > ? PacketAccessBit : 0, MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, FlagsRowMajorBit = XprType::Flags&RowMajorBit, Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | DirectAccessBit | diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 927a59c50..591ea26fb 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -11,9 +11,15 @@ #ifndef EIGEN_MAPBASE_H #define EIGEN_MAPBASE_H +#ifndef EIGEN_TEST_EVALUATORS #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) +#else +#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ + EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) +#endif namespace Eigen { diff --git a/test/block.cpp b/test/block.cpp index 269acd28e..3b77b704a 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -130,6 +130,14 @@ template void block(const MatrixType& m) VERIFY(numext::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows)); VERIFY(numext::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols)); + + // chekc that linear acccessors works on blocks + m1 = m1_copy; + if((MatrixType::Flags&RowMajorBit)==0) + VERIFY_IS_EQUAL(m1.leftCols(c1).coeff(r1+c1*rows), m1(r1,c1)); + else + VERIFY_IS_EQUAL(m1.topRows(r1).coeff(c1+r1*cols), m1(r1,c1)); + // now test some block-inside-of-block. -- cgit v1.2.3 From 470aa15c35539a7b79dd053c74578ac9e769f6e5 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Tue, 9 Sep 2014 16:58:48 +0000 Subject: First time it compiles, but fails to pass the tests. --- Eigen/Core | 6 +- Eigen/src/Core/arch/AltiVec/Complex.h | 74 +++++--- Eigen/src/Core/arch/AltiVec/PacketMath.h | 309 ++++++++++++++++++++++++++----- 3 files changed, 313 insertions(+), 76 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index 8ea165d5b..ac3cbd0c7 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -297,13 +297,9 @@ using std::ptrdiff_t; #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" -#elif defined(EIGEN_VECTORIZE_ALTIVEC) +#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) #include "src/Core/arch/AltiVec/PacketMath.h" #include "src/Core/arch/AltiVec/Complex.h" -#elif defined(EIGEN_VECTORIZE_ALTIVEC) - #include "src/Core/arch/AltiVec/PacketMath.h" - #include "src/Core/arch/AltiVec/VSX.h" - #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" #include "src/Core/arch/NEON/Complex.h" diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 064341a3b..d90cfe0de 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -18,7 +18,7 @@ namespace internal { static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; #else static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4f_ZERO_, (Packet4ui)p4i_ZERO);//{ 0x80000000, 0x00000000, 0x80000000, 0x00000000 }; -static Packet2ul p2ul_CONJ_XOR = (Packet2ul) vec_sld((Packet4ui)p2d_ZERO_, (Packet4ui)p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui)p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; #endif static Packet16uc p16uc_COMPLEX_RE = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; @@ -276,28 +276,58 @@ template<> struct packet_traits > : default_packet_traits template<> struct unpacket_traits { typedef std::complex type; enum {size=1}; typedef Packet1cd half; }; +template<> EIGEN_STRONG_INLINE Packet1cd pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) +{ + Packet1cd res; + /* On AltiVec we cannot load 64-bit registers, so wa have to take care of alignment */ + if((ptrdiff_t(&from) % 16) == 0) + res.v = pload((const double *)&from); + else + res.v = ploadu((const double *)&from); + res.v = vec_perm(res.v, res.v, p16uc_PSET_HI); + return res; +} +template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, DenseIndex stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1cd>(std::complex* to, const Packet1cd& from, DenseIndex stride) +{ + std::complex EIGEN_ALIGN16 af[2]; + pstore >(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} + template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_add(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_sub(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } -template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2ul)a.v, p2ul_CONJ_XOR)); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2d)a.v, (Packet2d)p2ul_CONJ_XOR)); } template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) { - Packet2d v1, v2; + Packet2d a_re, a_im, v1, v2; // Permute and multiply the real parts of a and b - v1 = vec_perm(a.v, a.v, p16uc_COMPLEX_RE); + a_re = vec_perm(a.v, a.v, p16uc_PSET_HI); // Get the imaginary parts of a - v2 = vec_perm(a.v, a.v, p16uc_COMPLEX_IM); + a_im = vec_perm(a.v, a.v, p16uc_PSET_HI); // multiply a_re * b - v1 = vec_madd(v1, b.v, p4f_ZERO); + v1 = vec_madd(a_re, b.v, p2d_ZERO_); // multiply a_im * b and get the conjugate result - v2 = vec_madd(v2, b.v, p4f_ZERO); - v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); - // permute back to a proper order - v2 = vec_perm(v2, v2, p16uc_COMPLEX_REV); + v2 = vec_madd(a_im, b.v, p2d_ZERO_); + v2 = (Packet2d) vec_sld((Packet4ui)v2, (Packet4ui)v2, 8); + v2 = (Packet2d) vec_xor((Packet2d)v2, (Packet2d) p2ul_CONJ_XOR); - return Packet2cf(vec_add(v1, v2)); + return Packet1cd(vec_add(v1, v2)); } template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v,b.v)); } @@ -305,23 +335,17 @@ template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_xor(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_and(a.v, vec_nor(b.v,b.v))); } -template<> EIGEN_STRONG_INLINE Packet1cd pload (const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } -template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } - template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } -template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } -template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } - -template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { vec_dstt((double *)addr, DST_CTRL(2,2,32), DST_CHAN); } +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { vec_dstt((long *)addr, DST_CTRL(2,2,32), DST_CHAN); } template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) { std::complex EIGEN_ALIGN16 res[2]; - pstore((float *)&res, a.v); + pstore >(res, a); return res[0]; } @@ -336,7 +360,7 @@ template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) { Packet2d b; - b = (Packet2d) vec_sld(a.v, a.v, 8); + b = (Packet2d) vec_sld((Packet4ui) a.v, (Packet4ui) a.v, 8); b = padd(a.v, b); return pfirst(Packet1cd(b)); } @@ -345,9 +369,9 @@ template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vec { Packet2d b1, b2; - b1 = (Packet2d) vec_sld(vecs[0].v, vecs[1].v, 8); - b2 = (Packet2d) vec_sld(vecs[1].v, vecs[0].v, 8); - b2 = (Packet2d) vec_sld(b2, b2, 8); + b1 = (Packet2d) vec_sld((Packet4ui) vecs[0].v, (Packet4ui) vecs[1].v, 8); + b2 = (Packet2d) vec_sld((Packet4ui) vecs[1].v, (Packet4ui) vecs[0].v, 8); + b2 = (Packet2d) vec_sld((Packet4ui) b2, (Packet4ui) b2, 8); b2 = padd(b1, b2); return Packet1cd(b2); @@ -357,7 +381,7 @@ template<> EIGEN_STRONG_INLINE std::complex predux_mul(const { Packet2d b; Packet1cd prod; - b = (Packet2d) vec_sld(a.v, a.v, 8); + b = (Packet2d) vec_sld((Packet4ui) a.v, (Packet4ui) a.v, 8); prod = pmul(a, Packet1cd(b)); return pfirst(prod); @@ -407,7 +431,7 @@ template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, con { // TODO optimize it for AltiVec Packet1cd res = conj_helper().pmul(a,b); - Packet2d s = vec_madd(b.v, b.v, p4f_ZERO); + Packet2d s = vec_madd(b.v, b.v, p2d_ZERO_); return Packet1cd(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); } diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index e70039ae2..0489ad886 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -31,12 +31,6 @@ namespace internal { #define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 #endif -#ifdef __VSX__ -typedef __vector double Packet2d; -typedef __vector unsigned long Packet2ul; -typedef __vector long Packet2l; -#endif // __VSX__ - typedef __vector float Packet4f; typedef __vector int Packet4i; typedef __vector unsigned int Packet4ui; @@ -82,8 +76,6 @@ static Packet4i p4i_COUNTDOWN = { 3, 2, 1, 0 }; static Packet16uc p16uc_REVERSE = { 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15 }; static Packet16uc p16uc_FORWARD = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; static Packet16uc p16uc_DUPLICATE = { 4,5,6,7, 4,5,6,7, 0,1,2,3, 0,1,2,3 }; -static Packet2d p2d_ZERO_ = (Packet2d) { 0x8000000000000000, 0x8000000000000000 }; -static Packet2l p2l_ZERO = (Packet2l) { 0x0, 0x0 }; #endif // _BIG_ENDIAN // These constants are endian-agnostic @@ -114,24 +106,6 @@ template<> struct packet_traits : default_packet_traits HasSqrt = 0 }; }; -#ifdef __VSX__ -template<> struct packet_traits : default_packet_traits -{ - typedef Packet2d type; - typedef Packet2d half; - enum { - Vectorizable = 1, - AlignedOnScalar = 1, - size=2, - HasHalfPacket = 0, - - HasDiv = 1, - HasExp = 0, - HasSqrt = 0 - }; -}; -#endif // __VSX__ - template<> struct packet_traits : default_packet_traits { typedef Packet4i type; @@ -144,9 +118,6 @@ template<> struct packet_traits : default_packet_traits }; }; -#ifdef __VSX__ -template<> struct unpacket_traits { typedef double type; enum {size=2}; typedef Packet2d half; }; -#endif // __VSX__ template<> struct unpacket_traits { typedef float type; enum {size=4}; typedef Packet4f half; }; template<> struct unpacket_traits { typedef int type; enum {size=4}; typedef Packet4i half; }; @@ -196,11 +167,18 @@ inline std::ostream & operator <<(std::ostream & s, const Packetbi & v) } */ +// Need to define them first or we get specialization after instantiation errors +template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } +template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } + +template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } +template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } + template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html float EIGEN_ALIGN16 af[4]; af[0] = from; - Packet4f vc = vec_ld(0, af); + Packet4f vc = pload(af); vc = vec_splat(vc, 0); return vc; } @@ -208,17 +186,15 @@ template<> EIGEN_STRONG_INLINE Packet4f pset1(const float& from) { template<> EIGEN_STRONG_INLINE Packet4i pset1(const int& from) { int EIGEN_ALIGN16 ai[4]; ai[0] = from; - Packet4i vc = vec_ld(0, ai); + Packet4i vc = pload(ai); vc = vec_splat(vc, 0); return vc; } - - template<> EIGEN_STRONG_INLINE void pbroadcast4(const float *a, Packet4f& a0, Packet4f& a1, Packet4f& a2, Packet4f& a3) { - a3 = vec_ld(0,a); + a3 = pload(a); a0 = vec_splat(a3, 0); a1 = vec_splat(a3, 1); a2 = vec_splat(a3, 2); @@ -228,7 +204,7 @@ template<> EIGEN_STRONG_INLINE void pbroadcast4(const int *a, Packet4i& a0, Packet4i& a1, Packet4i& a2, Packet4i& a3) { - a3 = vec_ld(0,a); + a3 = pload(a); a0 = vec_splat(a3, 0); a1 = vec_splat(a3, 1); a2 = vec_splat(a3, 2); @@ -242,7 +218,7 @@ template<> EIGEN_DEVICE_FUNC inline Packet4f pgather(const floa af[1] = from[1*stride]; af[2] = from[2*stride]; af[3] = from[3*stride]; - return vec_ld(0, af); + return pload(af); } template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int* from, DenseIndex stride) { @@ -251,12 +227,12 @@ template<> EIGEN_DEVICE_FUNC inline Packet4i pgather(const int* f ai[1] = from[1*stride]; ai[2] = from[2*stride]; ai[3] = from[3*stride]; - return vec_ld(0, ai); + return pload(ai); } template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, const Packet4f& from, DenseIndex stride) { float EIGEN_ALIGN16 af[4]; - vec_st(from, 0, af); + pstore(af, from); to[0*stride] = af[0]; to[1*stride] = af[1]; to[2*stride] = af[2]; @@ -265,7 +241,7 @@ template<> EIGEN_DEVICE_FUNC inline void pscatter(float* to, co template<> EIGEN_DEVICE_FUNC inline void pscatter(int* to, const Packet4i& from, DenseIndex stride) { int EIGEN_ALIGN16 ai[4]; - vec_st(from, 0, ai); + pstore((int *)ai, from); to[0*stride] = ai[0]; to[1*stride] = ai[1]; to[2*stride] = ai[2]; @@ -366,10 +342,7 @@ template<> EIGEN_STRONG_INLINE Packet4i pxor(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pandnot(const Packet4f& a, const Packet4f& b) { return vec_and(a, vec_nor(b, b)); } template<> EIGEN_STRONG_INLINE Packet4i pandnot(const Packet4i& a, const Packet4i& b) { return vec_and(a, vec_nor(b, b)); } -template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } -template<> EIGEN_STRONG_INLINE Packet4i pload(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } - -#ifndef __VSX__ +#ifdef _BIG_ENDIAN template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD @@ -393,6 +366,7 @@ template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) return (Packet4i) vec_perm(MSQ, LSQ, mask); // align the data } #else +// We also need ot redefine little endian loading of Packet4i/Packet4f using VSX template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD @@ -420,9 +394,6 @@ template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) return vec_perm(p, p, p16uc_DUPLICATE); } -template<> EIGEN_STRONG_INLINE void pstore(float* to, const Packet4f& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } -template<> EIGEN_STRONG_INLINE void pstore(int* to, const Packet4i& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st(from, 0, to); } - template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE @@ -642,6 +613,252 @@ ptranspose(PacketBlock& kernel) { kernel.packet[3] = vec_mergel(t1, t3); } + +//---------- double ---------- +#ifdef __VSX__ +typedef __vector double Packet2d; +typedef __vector unsigned long long Packet2ul; +typedef __vector long long Packet2l; + +static Packet2l p2l_ZERO = { 0x0, 0x0 }; +static Packet2d p2l_ONE = { 1, 1 }; +static Packet2d p2d_ONE = { 1.0, 1.0 }; +static Packet2d p2d_ZERO = { 0.0, 0.0 }; +static Packet2d p2d_ZERO_ = { (double) 0x8000000000000000, (double) 0x8000000000000000 }; +static Packet2d p2d_COUNTDOWN = { 1.0, 0.0 }; + +#ifdef _BIG_ENDIAN +static Packet16uc p16uc_SPLATQ1 = { 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_SPLATQ2 = { 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; +#else +static Packet16uc p16uc_SPLATQ1 = { 4,5,6,7, 0,1,2,3, 4,5,6,7, 0,1,3,4 }; +static Packet16uc p16uc_SPLATQ2 = { 12,13,14,15, 8,9,10,11, 12,13,14,15, 8,9,10,11 }; +#endif + + +static EIGEN_STRONG_INLINE Packet2d vec_splat_dbl(Packet2d& a, int index) +{ + switch (index) { + case 0: + return (Packet2d) vec_perm(a, a, p16uc_SPLATQ1); + case 1: + return (Packet2d) vec_perm(a, a, p16uc_SPLATQ2); + } + return a; +} + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size=2, + HasHalfPacket = 0, + + HasDiv = 1, + HasExp = 0, + HasSqrt = 0 + }; +}; + +template<> struct unpacket_traits { typedef double type; enum {size=2}; typedef Packet2d half; }; + +/* +inline std::ostream & operator <<(std::ostream & s, const Packet2d & v) +{ + union { + Packetdf v; + double n[2]; + } vt; + vt.v = v; + s << vt.n[0] << ", " << vt.n[1]; + return s; +}*/ + +// Need to define them first or we get specialization after instantiation errors +template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return (Packet2d) vec_ld(0, (const float *) from); } //FIXME + +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) { EIGEN_DEBUG_ALIGNED_STORE vec_st((Packet4f)from, 0, (float *)to); } + +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { + double EIGEN_ALIGN16 af[2]; + af[0] = from; + Packet2d vc = pload(af); + vc = vec_splat_dbl(vc, 0); + return vc; +} +template<> EIGEN_STRONG_INLINE void +pbroadcast4(const double *a, + Packet2d& a0, Packet2d& a1, Packet2d& a2, Packet2d& a3) +{ + a1 = pload(a); + a0 = vec_splat_dbl(a1, 0); + a1 = vec_splat_dbl(a1, 1); + a3 = pload(a+2); + a2 = vec_splat_dbl(a3, 0); + a3 = vec_splat_dbl(a1, 1); +} +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, DenseIndex stride) +{ + double EIGEN_ALIGN16 af[2]; + af[0] = from[0*stride]; + af[1] = from[1*stride]; + return pload(af); +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, DenseIndex stride) +{ + double EIGEN_ALIGN16 af[2]; + pstore(af, from); + to[0*stride] = af[0]; + to[1*stride] = af[1]; +} +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) { return vec_add(pset1(a), p2d_COUNTDOWN); } + +template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return vec_add(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d psub(const Packet2d& a, const Packet2d& b) { return vec_sub(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return psub(p2d_ZERO, a); } + +template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return vec_madd(a,b,p2d_ZERO); } +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) +{ + Packet2d t, y_0, y_1, res; + + // Altivec does not offer a divide instruction, we have to do a reciprocal approximation + y_0 = vec_re(b); + + // Do one Newton-Raphson iteration to get the needed accuracy + t = vec_nmsub(y_0, b, p2d_ONE); + y_1 = vec_madd(y_0, t, y_0); + + res = vec_madd(a, y_1, p2d_ZERO); + return res; +} + +// for some weird raisons, it has to be overloaded for packet of integers +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vec_madd(a, b, c); } + +template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return vec_min(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return vec_max(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) { return vec_and(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d por(const Packet2d& a, const Packet2d& b) { return vec_or(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const Packet2d& b) { return vec_xor(a, b); } + +template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) { return vec_and(a, vec_nor(b, b)); } + + +template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) +{ + EIGEN_DEBUG_ALIGNED_LOAD + return (Packet2d) vec_vsx_ld((int)((size_t)(from) & 15), (const float *)from); // align the data +} +template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) +{ + Packet2d p; + if((ptrdiff_t(from) % 16) == 0) p = pload(from); + else p = ploadu(from); + return vec_perm(p, p, p16uc_DUPLICATE); +} + +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) +{ + EIGEN_DEBUG_UNALIGNED_STORE + // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html + // Warning: not thread safe! + Packet16uc MSQ, LSQ, edges; + Packet16uc edgeAlign, align; + + MSQ = vec_ld(0, (unsigned char *)to); // most significant quadword + LSQ = vec_ld(15, (unsigned char *)to); // least significant quadword + edgeAlign = vec_lvsl(0, to); // permute map to extract edges + edges=vec_perm(LSQ,MSQ,edgeAlign); // extract the edges + align = vec_lvsr( 0, to ); // permute map to misalign data + MSQ = vec_perm(edges,(Packet16uc)from,align); // misalign the data (MSQ) + LSQ = vec_perm((Packet16uc)from,edges,align); // misalign the data (LSQ) + vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first + vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part +} +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { vec_dstt((const float *) addr, DST_CTRL(2,2,32), DST_CHAN); } + +template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { double EIGEN_ALIGN16 x[2]; pstore(x, a); return x[0]; } + +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { return (Packet2d)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } + +template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vec_abs(a); } + +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) +{ + Packet2d b, sum; + b = (Packet2d) vec_sld((Packet4ui) a, (Packet4ui)a, 8); + sum = vec_add(a, b); + return pfirst(sum); +} + +template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) +{ + Packet2d v[2], sum; + + v[0] = (Packet2d) vec_sld((Packet4ui) vecs[0], (Packet4ui) vecs[1], 8); + v[1] = (Packet2d) vec_sld((Packet4ui) vecs[1], (Packet4ui) vecs[0], 8); + sum = vec_add(v[0], v[1]); + + return sum; +} +// Other reduction functions: +// mul +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) +{ + Packet2d prod; + prod = pmul(a, (Packet2d)vec_sld((Packet4ui) a, (Packet4ui)a, 8)); + return pfirst(pmul(prod, (Packet2d)vec_sld((Packet4ui) prod, (Packet4ui) prod, 4))); +} + +// min +template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) +{ + Packet2d b, res; + b = vec_min(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8)); + res = vec_min(b, (Packet2d) vec_sld((Packet4ui) b, (Packet4ui) b, 4)); + return pfirst(res); +} + +// max +template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) +{ + Packet2d res; + res = vec_max(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8)); + return pfirst(res); +} + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) + { + if (Offset!=0) + first = (Packet2d) vec_sld((Packet4ui) first, (Packet4ui) second, Offset*8); + } +}; + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + Packet2d t0, t1; + t0 = (Packet2d) vec_sld((Packet4ui) kernel.packet[0], (Packet4ui) kernel.packet[1], 8); + t1 = (Packet2d) vec_sld((Packet4ui) kernel.packet[1], (Packet4ui) kernel.packet[0], 8); + kernel.packet[0] = t0; + kernel.packet[1] = t1; +} + +#endif // __VSX__ } // end namespace internal } // end namespace Eigen -- cgit v1.2.3 From af9c9f7706bb7701a7224827e981ecc2f3bd9ac7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 17:33:39 +0200 Subject: Fix comparison to block size --- Eigen/src/Householder/HouseholderSequence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index ab32f7d3f..0c6a09861 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -321,7 +321,7 @@ template class HouseholderS { const Index BlockSize = 48; // if the entries are large enough, then apply the reflectors by block - if(m_length>BlockSize && dst.cols()>1) + if(m_length>=BlockSize && dst.cols()>1) { for(Index i = 0; i < m_length; i+=BlockSize) { -- cgit v1.2.3 From dfc54e1bbf99a069146025677b70e38755383df9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 18:27:48 +0200 Subject: Fix /= when using evaluator as in changeset 2d90484450f3934db3f5db39ef37967fb9444263 --- Eigen/src/Core/SelfCwiseBinaryOp.h | 12 +----------- test/linearstructure.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 87fcde323..bec6f4968 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -212,17 +212,7 @@ template inline Derived& DenseBase::operator/=(const Scalar& other) { typedef typename Derived::PlainObject PlainObject; - - typedef typename internal::conditional::IsInteger, - internal::div_assign_op, - internal::mul_assign_op >::type AssignOp; - - Scalar actual_other; - if(NumTraits::IsInteger) actual_other = other; - else actual_other = Scalar(1)/other; - - internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),actual_other), AssignOp()); - + internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::div_assign_op()); return derived(); } #else diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp index b627915ce..87dfa1b6b 100644 --- a/test/linearstructure.cpp +++ b/test/linearstructure.cpp @@ -9,7 +9,6 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. static bool g_called; - #define EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN { g_called = true; } #include "main.h" @@ -107,4 +106,19 @@ void test_linearstructure() CALL_SUBTEST_10( real_complex() ); CALL_SUBTEST_10( real_complex(10,10) ); } + +#ifdef EIGEN_TEST_PART_4 + { + // make sure that /=scalar and /scalar do not overflow + // rational: 1.0/4.94e-320 overflow, but m/4.94e-320 should not + Matrix4d m2, m3; + m3 = m2 = Matrix4d::Random()*1e-20; + m2 = m2 / 4.9e-320; + VERIFY_IS_APPROX(m2.cwiseQuotient(m2), Matrix4d::Ones()); + m3 /= 4.9e-320; + VERIFY_IS_APPROX(m3.cwiseQuotient(m3), Matrix4d::Ones()); + + + } +#endif } -- cgit v1.2.3 From fda680f9cf8e81f62ae815b700698958b7b0f027 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 18:31:29 +0200 Subject: Adapt changeset 51b3f558bb76c11149fc64971db786798f1b692c to evaluators: (Fix bug #822: outer products needed linear access, and add respective unit tests) --- Eigen/src/Core/ProductEvaluators.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 8a63384a7..f880e7696 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -215,7 +215,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(Dst& dst, const Lhs &lhs, cons // FIXME we should probably build an evaluator for dst and rhs const Index cols = dst.cols(); for (Index j=0; j -- cgit v1.2.3 From 26db954776c0e8f0230ca1542ad303e23ede4db1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 19:06:08 +0200 Subject: Re-enable aliasing checks when using evaluators --- Eigen/src/Core/Assign.h | 7 ++++--- Eigen/src/Core/AssignEvaluator.h | 7 +++++++ Eigen/src/Core/DenseBase.h | 2 ++ Eigen/src/Core/Transpose.h | 10 +++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 071cfbf7e..5395e5436 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -521,12 +521,13 @@ EIGEN_STRONG_INLINE Derived& DenseBase eigen_assert(rows() == other.rows() && cols() == other.cols()); internal::assign_impl::Traversal) : int(InvalidTraversal)>::run(derived(),other.derived()); - -#endif // EIGEN_TEST_EVALUATORS - + #ifndef EIGEN_NO_DEBUG checkTransposeAliasing(other.derived()); #endif + +#endif // EIGEN_TEST_EVALUATORS + return derived(); } diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 1727a6a4a..521b8a93a 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -763,6 +763,9 @@ void call_assignment_no_alias(Dst& dst, const Src& src) call_assignment_no_alias(dst, src, internal::assign_op()); } +// forxard declaration +template void check_for_aliasing(const Dst &dst, const Src &src); + // Generic Dense to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment @@ -771,6 +774,10 @@ struct Assignment { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); +#ifndef EIGEN_NO_DEBUG + internal::check_for_aliasing(dst, src); +#endif + call_dense_assignment_loop(dst, src, func); } }; diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 14643b5a8..f35c2edc4 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -314,11 +314,13 @@ template class DenseBase EIGEN_DEVICE_FUNC void transposeInPlace(); #ifndef EIGEN_NO_DEBUG +#ifndef EIGEN_TEST_EVALUATORS protected: template void checkTransposeAliasing(const OtherDerived& other) const; public: #endif +#endif EIGEN_DEVICE_FUNC static const ConstantReturnType diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index f5148221d..b22b50a8f 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -437,15 +437,23 @@ struct checkTransposeAliasing_impl } }; +template +void check_for_aliasing(const Dst &dst, const Src &src) +{ + internal::checkTransposeAliasing_impl::run(dst, src); +} + } // end namespace internal +#ifndef EIGEN_TEST_EVALUATORS template template void DenseBase::checkTransposeAliasing(const OtherDerived& other) const { internal::checkTransposeAliasing_impl::run(derived(), other); } -#endif +#endif // EIGEN_TEST_EVALUATORS +#endif // EIGEN_NO_DEBUG } // end namespace Eigen -- cgit v1.2.3 From c83e01f2d6113fb2f7dcc591b3364eb87b7a74aa Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 19:38:49 +0200 Subject: Favor column major storage for inner products --- Eigen/src/Core/AssignEvaluator.h | 4 ++-- Eigen/src/Core/Product.h | 2 +- test/vectorization_logic.cpp | 16 +++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 521b8a93a..4e35e432e 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -55,8 +55,8 @@ private: }; enum { - DstIsRowMajor = DstEvaluator::Flags&RowMajorBit, - SrcIsRowMajor = SrcEvaluator::Flags&RowMajorBit, + DstIsRowMajor = DstFlags&RowMajorBit, + SrcIsRowMajor = SrcFlags&RowMajorBit, StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), MightVectorize = StorageOrdersAgree && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 0cf20f2e2..6825873d5 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -85,7 +85,7 @@ struct traits > #endif // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. - Flags = ( MaxRowsAtCompileTime==1 + Flags = ( (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) || ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit : (MaxColsAtCompileTime==1 ? 0 : NoPreferredStorageOrderBit) diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp index 42015e21b..303eb6cf0 100644 --- a/test/vectorization_logic.cpp +++ b/test/vectorization_logic.cpp @@ -30,13 +30,15 @@ std::string demangle_unrolling(int t) std::string demangle_flags(int f) { std::string res; - if(f&RowMajorBit) res += " | RowMajor"; - if(f&PacketAccessBit) res += " | Packet"; - if(f&LinearAccessBit) res += " | Linear"; - if(f&LvalueBit) res += " | Lvalue"; - if(f&DirectAccessBit) res += " | Direct"; - if(f&AlignedBit) res += " | Aligned"; - if(f&NestByRefBit) res += " | NestByRef"; + if(f&RowMajorBit) res += " | RowMajor"; + if(f&PacketAccessBit) res += " | Packet"; + if(f&LinearAccessBit) res += " | Linear"; + if(f&LvalueBit) res += " | Lvalue"; + if(f&DirectAccessBit) res += " | Direct"; + if(f&AlignedBit) res += " | Aligned"; + if(f&NestByRefBit) res += " | NestByRef"; + if(f&NoPreferredStorageOrderBit) res += " | NoPreferredStorageOrderBit"; + return res; } -- cgit v1.2.3 From 0403d49006818079c79c038a6b55c48bc3839c22 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 14 Sep 2014 20:12:07 +0200 Subject: Fix inverse unit test making sure we try to invert an invertible matrix --- test/inverse.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/inverse.cpp b/test/inverse.cpp index 1195bcc76..1e7b20958 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -73,6 +73,7 @@ template void inverse(const MatrixType& m) { Matrix m3; m3.setRandom(); + m3.topLeftCorner(rows,rows) = m1; m2 = m3.template topLeftCorner().inverse(); VERIFY_IS_APPROX( (m3.template topLeftCorner()), m2.inverse() ); } -- cgit v1.2.3 From 8514179aa31a6a42523c66f66a94723ed758cd5f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Sep 2014 13:53:52 +0200 Subject: Fix traits::IsAligned when using evaluators --- Eigen/src/Geometry/Quaternion.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 11e5398d4..850940302 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -217,7 +217,11 @@ struct traits > typedef _Scalar Scalar; typedef Matrix<_Scalar,4,1,_Options> Coefficients; enum{ +#ifndef EIGEN_TEST_EVALUATORS IsAligned = internal::traits::Flags & AlignedBit, +#else + IsAligned = (internal::traits::EvaluatorFlags & AlignedBit) != 0, +#endif Flags = IsAligned ? (AlignedBit | LvalueBit) : LvalueBit }; }; -- cgit v1.2.3 From 466d6d41c6dfda5a2814d0ee6d02439ccda4c8d0 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 15 Sep 2014 17:40:17 +0200 Subject: Avoid a potential risk of recursive definition using traits to get he scalar type --- Eigen/src/Core/CoreEvaluators.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index b8dc05d98..09a83a382 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -49,8 +49,8 @@ template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; template< typename T, typename LhsKind = typename evaluator_traits::Kind, typename RhsKind = typename evaluator_traits::Kind, - typename LhsScalar = typename T::Lhs::Scalar, - typename RhsScalar = typename T::Rhs::Scalar> struct binary_evaluator; + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct binary_evaluator; template< typename T, typename Kind = typename evaluator_traits::Kind, -- cgit v1.2.3 From 486ca277a002b888a13fe14b136ff54b3979d475 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 16 Sep 2014 10:29:29 -0700 Subject: Workaround MSVC ICE --- Eigen/src/Core/TriangularMatrix.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 0383ca9f5..cc585bc6c 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -277,7 +277,16 @@ template class TriangularView solve(const MatrixBase& other) const { return Solve(*this, other.derived()); } + // workaround MSVC ICE + #ifdef _MSC_VER + template + EIGEN_DEVICE_FUNC + inline const internal::triangular_solve_retval + solve(const MatrixBase& other) const + { return Base::template solve(other); } + #else using Base::solve; + #endif #endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC @@ -575,7 +584,7 @@ template class TriangularViewImpl<_Mat EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { if(!(internal::is_same::value && internal::extract_data(dst) == internal::extract_data(rhs))) dst = rhs; - this->template solveInPlace(dst); + this->solveInPlace(dst); } template -- cgit v1.2.3 From 0f0580b97c4209faeb01f415523fab5863e742b1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 17 Sep 2014 09:55:44 +0200 Subject: Remove not needed template keyword. --- Eigen/src/SparseCore/SparseTriangularView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 87f4ab18d..3df7a4cd4 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -50,7 +50,7 @@ protected: EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { if(!(internal::is_same::value && internal::extract_data(dst) == internal::extract_data(rhs))) dst = rhs; - this->template solveInPlace(dst); + this->solveInPlace(dst); } #endif // EIGEN_TEST_EVALUATORS -- cgit v1.2.3 From fc23e937076d01e565fac5b771f22099dee5ad6c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 17 Sep 2014 09:56:07 +0200 Subject: Add a portable log2 function for integers --- Eigen/src/Core/MathFunctions.h | 15 +++++++++++++++ Eigen/src/SparseCore/ConservativeSparseSparseProduct.h | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index e9fed2e52..8834f71fa 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -694,6 +694,21 @@ bool (isfinite)(const std::complex& x) return isfinite(real(x)) && isfinite(imag(x)); } +// Log base 2 for 32 bits positive integers. +// Conveniently returns 0 for x==0. +int log2(int x) +{ + eigen_assert(x>=0); + unsigned int v(x); + static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return table[(v * 0x07C4ACDDU) >> 27]; +} + } // end namespace numext namespace internal { diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index ae8fc75e5..398008597 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -101,7 +101,7 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r // otherwise => loop through the entire vector // In order to avoid to perform an expensive log2 when the // result is clearly very sparse we use a linear bound up to 200. - if((nnz<200 && nnz1) std::sort(indices,indices+nnz); for(Index k=0; k Date: Tue, 16 Sep 2014 16:05:06 -0700 Subject: avoid division by 0 --- test/stable_norm.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index f76919af4..6cd65c64a 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -130,7 +130,7 @@ template void stable_norm(const MatrixType& m) // NaN { v = vrand; - v(i,j) = RealScalar(0)/RealScalar(0); + v(i,j) = std::numeric_limits::quiet_NaN(); VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); @@ -141,7 +141,7 @@ template void stable_norm(const MatrixType& m) // +inf { v = vrand; - v(i,j) = RealScalar(1)/RealScalar(0); + v(i,j) = std::numeric_limits::infinity(); VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); @@ -152,7 +152,7 @@ template void stable_norm(const MatrixType& m) // -inf { v = vrand; - v(i,j) = RealScalar(-1)/RealScalar(0); + v(i,j) = -std::numeric_limits::infinity(); VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); @@ -165,8 +165,8 @@ template void stable_norm(const MatrixType& m) Index i2 = internal::random(0,rows-1); Index j2 = internal::random(0,cols-1); v = vrand; - v(i,j) = RealScalar(-1)/RealScalar(0); - v(i2,j2) = RealScalar(0)/RealScalar(0); + v(i,j) = -std::numeric_limits::infinity(); + v(i2,j2) = std::numeric_limits::quiet_NaN(); VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); -- cgit v1.2.3 From 125619146bc3db3074c8f7632869c7f85b857b8a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 16 Sep 2014 16:06:32 -0700 Subject: workaround weird MSVC compilation issue: a typdedef in a base class shadows a template parameter of a derived class --- Eigen/src/SparseCore/SparseDenseProduct.h | 37 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index c8a515e8c..803d98e2d 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -402,30 +402,30 @@ struct generic_product_impl } }; -template +template struct sparse_dense_outer_product_evaluator { protected: - typedef typename conditional::type Lhs1; - typedef typename conditional::type Rhs; - typedef Product ProdXprType; + typedef typename conditional::type Lhs1; + typedef typename conditional::type ActualRhs; + typedef Product ProdXprType; // if the actual left-hand side is a dense vector, // then build a sparse-view so that we can seamlessly iterator over it. typedef typename conditional::StorageKind,Sparse>::value, - Lhs1, SparseView >::type Lhs; + Lhs1, SparseView >::type ActualLhs; typedef typename conditional::StorageKind,Sparse>::value, Lhs1 const&, SparseView >::type LhsArg; - typedef typename evaluator::type LhsEval; - typedef typename evaluator::type RhsEval; - typedef typename evaluator::InnerIterator LhsIterator; + typedef typename evaluator::type LhsEval; + typedef typename evaluator::type RhsEval; + typedef typename evaluator::InnerIterator LhsIterator; typedef typename ProdXprType::Scalar Scalar; typedef typename ProdXprType::Index Index; public: enum { - Flags = Transpose ? RowMajorBit : 0, + Flags = NeedToTranspose ? RowMajorBit : 0, CoeffReadCost = Dynamic }; @@ -436,17 +436,16 @@ public: : LhsIterator(xprEval.m_lhsXprImpl, 0), m_outer(outer), m_empty(false), - m_factor(get(xprEval.m_rhsXprImpl, outer, typename internal::traits::StorageKind() )) + m_factor(get(xprEval.m_rhsXprImpl, outer, typename internal::traits::StorageKind() )) {} EIGEN_STRONG_INLINE Index outer() const { return m_outer; } - EIGEN_STRONG_INLINE Index row() const { return Transpose ? m_outer : LhsIterator::index(); } - EIGEN_STRONG_INLINE Index col() const { return Transpose ? LhsIterator::index() : m_outer; } + EIGEN_STRONG_INLINE Index row() const { return NeedToTranspose ? m_outer : LhsIterator::index(); } + EIGEN_STRONG_INLINE Index col() const { return NeedToTranspose ? LhsIterator::index() : m_outer; } EIGEN_STRONG_INLINE Scalar value() const { return LhsIterator::value() * m_factor; } EIGEN_STRONG_INLINE operator bool() const { return LhsIterator::operator bool() && (!m_empty); } - protected: Scalar get(const RhsEval &rhs, Index outer, Dense = Dense()) const { @@ -467,19 +466,19 @@ public: Scalar m_factor; }; - sparse_dense_outer_product_evaluator(const Lhs &lhs, const Rhs &rhs) - : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + sparse_dense_outer_product_evaluator(const ActualLhs &lhs, const ActualRhs &rhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) {} // transpose case - sparse_dense_outer_product_evaluator(const Rhs &rhs, const Lhs1 &lhs) - : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) + sparse_dense_outer_product_evaluator(const ActualRhs &rhs, const Lhs1 &lhs) + : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) {} protected: const LhsArg m_lhs; - typename evaluator::nestedType m_lhsXprImpl; - typename evaluator::nestedType m_rhsXprImpl; + typename evaluator::nestedType m_lhsXprImpl; + typename evaluator::nestedType m_rhsXprImpl; }; // sparse * dense outer product -- cgit v1.2.3 From c2f66c65aaef44c698ba141a08b5940baf4c56c8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 16 Sep 2014 16:23:45 -0700 Subject: workaround MSVC compilation issue (shadow issue) --- Eigen/src/Core/Inverse.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 1d167867f..84abd258e 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -101,11 +101,11 @@ namespace internal { * * \sa class Inverse */ -template -struct unary_evaluator > - : public evaluator::PlainObject>::type +template +struct unary_evaluator > + : public evaluator::PlainObject>::type { - typedef Inverse InverseType; + typedef Inverse InverseType; typedef typename InverseType::PlainObject PlainObject; typedef typename evaluator::type Base; -- cgit v1.2.3 From e44d78dab30809f359043b8d09787b7435526671 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 16 Sep 2014 17:10:25 -0700 Subject: workaround ambiguous call --- test/product_mmtr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/product_mmtr.cpp b/test/product_mmtr.cpp index 7d6746800..92e6b668f 100644 --- a/test/product_mmtr.cpp +++ b/test/product_mmtr.cpp @@ -13,7 +13,8 @@ ref2 = ref1 = DEST; \ DEST.template triangularView() OP; \ ref1 OP; \ - ref2.template triangularView() = ref1; \ + ref2.template triangularView() \ + = ref1.template triangularView(); \ VERIFY_IS_APPROX(DEST,ref2); \ } -- cgit v1.2.3 From 0bf589486132e011a40d0a657a719980562b026f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 16 Sep 2014 18:21:39 -0700 Subject: workaround one more shadowing issue with MSVC --- Eigen/src/Core/Transpose.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index b22b50a8f..dd6180a8f 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -29,9 +29,10 @@ namespace Eigen { namespace internal { template -struct traits > : traits +struct traits > { - typedef typename MatrixType::Scalar Scalar; + typedef typename traits::Scalar Scalar; + typedef typename traits::Index Index; typedef typename nested::type MatrixTypeNested; typedef typename remove_reference::type MatrixTypeNestedPlain; typedef typename traits::StorageKind StorageKind; -- cgit v1.2.3 From 8b3be4907da2cbf47ec15734b7f364e6e66bf4c3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 10:53:53 +0200 Subject: log2(int) must be inlined. --- Eigen/src/Core/MathFunctions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 8834f71fa..73859b0ee 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -696,7 +696,7 @@ bool (isfinite)(const std::complex& x) // Log base 2 for 32 bits positive integers. // Conveniently returns 0 for x==0. -int log2(int x) +inline int log2(int x) { eigen_assert(x>=0); unsigned int v(x); -- cgit v1.2.3 From 0ca43f7e9a654e32da0066163a8656415961e266 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 15:15:27 +0200 Subject: Remove deprecated code not used by evaluators --- Eigen/Cholesky | 1 - Eigen/CholmodSupport | 4 - Eigen/Core | 25 +- Eigen/IterativeLinearSolvers | 6 - Eigen/LU | 1 - Eigen/PaStiXSupport | 4 - Eigen/QR | 1 - Eigen/SPQRSupport | 2 - Eigen/SVD | 1 - Eigen/SparseCholesky | 5 - Eigen/SparseLU | 3 - Eigen/SparseQR | 3 - Eigen/SuperLUSupport | 4 - Eigen/UmfPackSupport | 3 - Eigen/src/Cholesky/LDLT.h | 29 - Eigen/src/Cholesky/LLT.h | 30 -- Eigen/src/CholmodSupport/CholmodSupport.h | 62 --- Eigen/src/Core/ArrayBase.h | 65 --- Eigen/src/Core/Assign.h | 587 --------------------- Eigen/src/Core/AssignEvaluator.h | 6 - Eigen/src/Core/BandMatrix.h | 4 - Eigen/src/Core/Block.h | 15 - Eigen/src/Core/BooleanRedux.h | 51 -- Eigen/src/Core/CwiseBinaryOp.h | 72 --- Eigen/src/Core/CwiseNullaryOp.h | 9 - Eigen/src/Core/CwiseUnaryOp.h | 47 -- Eigen/src/Core/CwiseUnaryView.h | 31 -- Eigen/src/Core/DenseBase.h | 56 -- Eigen/src/Core/DenseCoeffsBase.h | 164 ------ Eigen/src/Core/Diagonal.h | 6 - Eigen/src/Core/DiagonalMatrix.h | 42 -- Eigen/src/Core/DiagonalProduct.h | 117 ---- Eigen/src/Core/Dot.h | 11 - Eigen/src/Core/EigenBase.h | 12 - Eigen/src/Core/Fuzzy.h | 5 - Eigen/src/Core/GeneralProduct.h | 458 ---------------- Eigen/src/Core/Inverse.h | 4 - Eigen/src/Core/Map.h | 18 - Eigen/src/Core/MapBase.h | 14 - Eigen/src/Core/Matrix.h | 4 - Eigen/src/Core/MatrixBase.h | 33 +- Eigen/src/Core/NoAlias.h | 63 --- Eigen/src/Core/PermutationMatrix.h | 73 --- Eigen/src/Core/PlainObjectBase.h | 25 - Eigen/src/Core/Product.h | 7 - Eigen/src/Core/ProductBase.h | 252 --------- Eigen/src/Core/Redux.h | 14 - Eigen/src/Core/Ref.h | 4 - Eigen/src/Core/Replicate.h | 5 - Eigen/src/Core/ReturnByValue.h | 11 +- Eigen/src/Core/Reverse.h | 10 - Eigen/src/Core/Select.h | 7 - Eigen/src/Core/SelfAdjointView.h | 137 ----- Eigen/src/Core/SelfCwiseBinaryOp.h | 209 -------- Eigen/src/Core/Solve.h | 2 - Eigen/src/Core/Swap.h | 131 ----- Eigen/src/Core/Transpose.h | 71 --- Eigen/src/Core/TriangularMatrix.h | 415 --------------- Eigen/src/Core/VectorwiseOp.h | 16 - Eigen/src/Core/Visitor.h | 13 - Eigen/src/Core/products/CoeffBasedProduct.h | 460 ---------------- Eigen/src/Core/products/GeneralMatrixMatrix.h | 82 --- .../Core/products/GeneralMatrixMatrixTriangular.h | 13 - Eigen/src/Core/products/SelfadjointMatrixMatrix.h | 54 -- Eigen/src/Core/products/SelfadjointMatrixVector.h | 113 ---- Eigen/src/Core/products/TriangularMatrixMatrix.h | 51 -- Eigen/src/Core/products/TriangularMatrixVector.h | 51 -- Eigen/src/Core/util/ForwardDeclarations.h | 4 - Eigen/src/Core/util/Macros.h | 42 -- Eigen/src/Core/util/XprHelper.h | 110 +--- Eigen/src/Geometry/AlignedBox.h | 4 - Eigen/src/Geometry/Homogeneous.h | 41 -- Eigen/src/Geometry/OrthoMethods.h | 15 - Eigen/src/Geometry/Quaternion.h | 4 - Eigen/src/Geometry/Transform.h | 4 - Eigen/src/Householder/HouseholderSequence.h | 3 - .../IterativeLinearSolvers/BasicPreconditioners.h | 29 - Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 37 -- .../src/IterativeLinearSolvers/ConjugateGradient.h | 37 -- Eigen/src/IterativeLinearSolvers/IncompleteLUT.h | 30 -- .../IterativeLinearSolvers/IterativeSolverBase.h | 72 --- Eigen/src/LU/Determinant.h | 4 - Eigen/src/LU/FullPivLU.h | 35 -- Eigen/src/LU/InverseImpl.h | 58 -- Eigen/src/LU/PartialPivLU.h | 35 -- Eigen/src/PaStiXSupport/PaStiXSupport.h | 64 --- Eigen/src/PardisoSupport/PardisoSupport.h | 62 --- Eigen/src/QR/ColPivHouseholderQR.h | 37 -- Eigen/src/QR/FullPivHouseholderQR.h | 40 -- Eigen/src/QR/HouseholderQR.h | 28 - Eigen/src/SPQRSupport/SuiteSparseQRSupport.h | 34 -- Eigen/src/SVD/SVDBase.h | 28 - Eigen/src/SparseCholesky/SimplicialCholesky.h | 76 +-- .../SparseCore/ConservativeSparseSparseProduct.h | 10 - Eigen/src/SparseCore/MappedSparseMatrix.h | 2 - Eigen/src/SparseCore/SparseAssign.h | 113 ---- Eigen/src/SparseCore/SparseBlock.h | 95 ---- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 254 --------- Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 132 ----- Eigen/src/SparseCore/SparseDenseProduct.h | 248 +-------- Eigen/src/SparseCore/SparseDiagonalProduct.h | 178 ------- Eigen/src/SparseCore/SparseDot.h | 18 +- Eigen/src/SparseCore/SparseMatrix.h | 93 ---- Eigen/src/SparseCore/SparseMatrixBase.h | 55 -- Eigen/src/SparseCore/SparsePermutation.h | 44 -- Eigen/src/SparseCore/SparseProduct.h | 178 ------- Eigen/src/SparseCore/SparseRedux.h | 5 - Eigen/src/SparseCore/SparseSelfAdjointView.h | 149 +----- Eigen/src/SparseCore/SparseSolverBase.h | 9 +- .../SparseCore/SparseSparseProductWithPruning.h | 15 - Eigen/src/SparseCore/SparseTranspose.h | 51 -- Eigen/src/SparseCore/SparseTriangularView.h | 8 - Eigen/src/SparseCore/SparseUtil.h | 24 - Eigen/src/SparseCore/SparseVector.h | 25 - Eigen/src/SparseCore/SparseView.h | 43 -- Eigen/src/SparseCore/TriangularSolver.h | 156 ------ Eigen/src/SparseLU/SparseLU.h | 63 --- Eigen/src/SparseQR/SparseQR.h | 51 -- Eigen/src/SuperLUSupport/SuperLUSupport.h | 59 --- Eigen/src/UmfPackSupport/UmfPackSupport.h | 59 --- Eigen/src/misc/Solve.h | 78 --- Eigen/src/misc/SparseSolve.h | 134 ----- test/CMakeLists.txt | 5 - test/evaluators.cpp | 12 - test/mixingtypes.cpp | 10 +- test/nesting_ops.cpp | 5 - test/sparse_vector.cpp | 3 - test/vectorization_logic.cpp | 22 - unsupported/Eigen/IterativeSolvers | 3 - unsupported/Eigen/SparseExtra | 3 - unsupported/Eigen/src/IterativeSolvers/DGMRES.h | 36 -- unsupported/Eigen/src/IterativeSolvers/GMRES.h | 36 -- .../src/IterativeSolvers/IncompleteCholesky.h | 31 -- .../Eigen/src/IterativeSolvers/IncompleteLU.h | 30 -- unsupported/Eigen/src/IterativeSolvers/MINRES.h | 37 -- .../Eigen/src/SparseExtra/DynamicSparseMatrix.h | 2 - unsupported/test/CMakeLists.txt | 26 +- 137 files changed, 41 insertions(+), 7806 deletions(-) delete mode 100644 Eigen/src/Core/products/CoeffBasedProduct.h delete mode 100644 Eigen/src/misc/Solve.h delete mode 100644 Eigen/src/misc/SparseSolve.h diff --git a/Eigen/Cholesky b/Eigen/Cholesky index 7314d326c..dd0ca911c 100644 --- a/Eigen/Cholesky +++ b/Eigen/Cholesky @@ -21,7 +21,6 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" #ifdef EIGEN_USE_LAPACKE diff --git a/Eigen/CholmodSupport b/Eigen/CholmodSupport index 745b884e7..687cd9777 100644 --- a/Eigen/CholmodSupport +++ b/Eigen/CholmodSupport @@ -33,12 +33,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/CholmodSupport/CholmodSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLMODSUPPORT_MODULE_H diff --git a/Eigen/Core b/Eigen/Core index 47c4f6299..2510e4898 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -11,16 +11,6 @@ #ifndef EIGEN_CORE_H #define EIGEN_CORE_H -// EIGEN_TEST_EVALUATORS => EIGEN_ENABLE_EVALUATORS -#ifndef EIGEN_TEST_NO_EVALUATORS - #ifndef EIGEN_TEST_EVALUATORS - #define EIGEN_TEST_EVALUATORS - #endif - #ifndef EIGEN_ENABLE_EVALUATORS - #define EIGEN_ENABLE_EVALUATORS - #endif -#endif - // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" @@ -317,11 +307,9 @@ using std::ptrdiff_t; #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" -#ifdef EIGEN_ENABLE_EVALUATORS #include "src/Core/Product.h" #include "src/Core/CoreEvaluators.h" #include "src/Core/AssignEvaluator.h" -#endif #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 @@ -332,10 +320,10 @@ using std::ptrdiff_t; #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" -#ifndef EIGEN_ENABLE_EVALUATORS -#include "src/Core/ForceAlignedAccess.h" -#include "src/Core/Flagged.h" -#endif + +// #include "src/Core/ForceAlignedAccess.h" +// #include "src/Core/Flagged.h" + #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" @@ -368,18 +356,13 @@ using std::ptrdiff_t; #include "src/Core/CommaInitializer.h" #include "src/Core/ProductBase.h" #include "src/Core/GeneralProduct.h" -#ifdef EIGEN_ENABLE_EVALUATORS #include "src/Core/Solve.h" #include "src/Core/Inverse.h" -#endif #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" -#include "src/Core/products/CoeffBasedProduct.h" -#ifdef EIGEN_ENABLE_EVALUATORS #include "src/Core/ProductEvaluators.h" -#endif #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" diff --git a/Eigen/IterativeLinearSolvers b/Eigen/IterativeLinearSolvers index 4df2c5a14..c06668bd2 100644 --- a/Eigen/IterativeLinearSolvers +++ b/Eigen/IterativeLinearSolvers @@ -26,13 +26,7 @@ * \endcode */ -#ifndef EIGEN_TEST_EVALUATORS -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" -#else #include "src/IterativeLinearSolvers/SolveWithGuess.h" -#endif - #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" #include "src/IterativeLinearSolvers/ConjugateGradient.h" diff --git a/Eigen/LU b/Eigen/LU index 38e9067c7..132ecc42c 100644 --- a/Eigen/LU +++ b/Eigen/LU @@ -16,7 +16,6 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/misc/Kernel.h" #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" diff --git a/Eigen/PaStiXSupport b/Eigen/PaStiXSupport index 7c616ee5e..e7d275f97 100644 --- a/Eigen/PaStiXSupport +++ b/Eigen/PaStiXSupport @@ -35,12 +35,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/PaStiXSupport/PaStiXSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/Eigen/QR b/Eigen/QR index 4c2533610..230cb079a 100644 --- a/Eigen/QR +++ b/Eigen/QR @@ -24,7 +24,6 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" diff --git a/Eigen/SPQRSupport b/Eigen/SPQRSupport index 77016442e..e3f49bb5a 100644 --- a/Eigen/SPQRSupport +++ b/Eigen/SPQRSupport @@ -21,8 +21,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/CholmodSupport/CholmodSupport.h" #include "src/SPQRSupport/SuiteSparseQRSupport.h" diff --git a/Eigen/SVD b/Eigen/SVD index c3d24286c..c13472e82 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -20,7 +20,6 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/SVD/SVDBase.h" #include "src/SVD/JacobiSVD.h" #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) diff --git a/Eigen/SparseCholesky b/Eigen/SparseCholesky index 2c4f66105..b6a320c40 100644 --- a/Eigen/SparseCholesky +++ b/Eigen/SparseCholesky @@ -34,11 +34,6 @@ #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif -#ifndef EIGEN_TEST_EVALUATORS -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" -#endif - #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY diff --git a/Eigen/SparseLU b/Eigen/SparseLU index 8527a49bd..38b38b531 100644 --- a/Eigen/SparseLU +++ b/Eigen/SparseLU @@ -20,9 +20,6 @@ * Please, see the documentation of the SparseLU class for more details. */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - // Ordering interface #include "OrderingMethods" diff --git a/Eigen/SparseQR b/Eigen/SparseQR index 4ee42065e..efb2695ba 100644 --- a/Eigen/SparseQR +++ b/Eigen/SparseQR @@ -21,9 +21,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "OrderingMethods" #include "src/SparseCore/SparseColEtree.h" #include "src/SparseQR/SparseQR.h" diff --git a/Eigen/SuperLUSupport b/Eigen/SuperLUSupport index 575e14fbc..d1eac9464 100644 --- a/Eigen/SuperLUSupport +++ b/Eigen/SuperLUSupport @@ -48,12 +48,8 @@ namespace Eigen { struct SluMatrix; } * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/SuperLUSupport/SuperLUSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/Eigen/UmfPackSupport b/Eigen/UmfPackSupport index 984f64a84..0efad5dee 100644 --- a/Eigen/UmfPackSupport +++ b/Eigen/UmfPackSupport @@ -26,9 +26,6 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/UmfPackSupport/UmfPackSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index f621323a3..32c770654 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -174,7 +174,6 @@ template class LDLT * * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -184,17 +183,6 @@ template class LDLT && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - eigen_assert(m_matrix.rows()==b.rows() - && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif template bool solveInPlace(MatrixBase &bAndX) const; @@ -524,23 +512,6 @@ void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) cons dst = m_transpositions.transpose() * dst; } #endif - -namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LDLT<_MatrixType,_UpLo> LDLTType; - EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; -#endif -} /** \internal use x = ldlt_object.solve(x); * diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 89fb9a011..cb9e0eb7b 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -117,7 +117,6 @@ template class LLT * * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -127,17 +126,6 @@ template class LLT && "LLT::solve(): invalid number of rows of the right hand side matrix b"); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(m_matrix.rows()==b.rows() - && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif template void solveInPlace(MatrixBase &bAndX) const; @@ -433,24 +421,6 @@ void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const } #endif -namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LLT<_MatrixType,UpLo> LLTType; - EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) - - template void evalTo(Dest& dst) const - { - dst = rhs(); - dec().solveInPlace(dst); - } -}; -#endif -} - /** \internal use x = llt_object.solve(x); * * This is the \em in-place version of solve(). diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index d3db51d0b..3524ffb2d 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -217,36 +217,6 @@ class CholmodBase : public SparseSolverBase return derived(); } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif // EIGEN_TEST_EVALUATORS - /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. @@ -574,38 +544,6 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom } }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_CHOLMODSUPPORT_H diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index f5bae6357..4e80634b9 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -64,9 +64,6 @@ template class ArrayBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; -#ifndef EIGEN_TEST_EVALUATORS - using Base::CoeffReadCost; -#endif using Base::derived; using Base::const_cast_derived; @@ -123,11 +120,7 @@ template class ArrayBase EIGEN_DEVICE_FUNC Derived& operator=(const ArrayBase& other) { -#ifndef EIGEN_TEST_EVALUATORS - return internal::assign_selector::run(derived(), other.derived()); -#else internal::call_assignment(derived(), other.derived()); -#endif } EIGEN_DEVICE_FUNC @@ -183,7 +176,6 @@ template class ArrayBase {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; -#ifdef EIGEN_TEST_EVALUATORS /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this @@ -235,63 +227,6 @@ ArrayBase::operator/=(const ArrayBase& other) call_assignment(derived(), other.derived(), internal::div_assign_op()); return derived(); } -#else // EIGEN_TEST_EVALUATORS -/** replaces \c *this by \c *this - \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator-=(const ArrayBase &other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this + \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator+=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this * \a other coefficient wise. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator*=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this / \a other coefficient wise. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator/=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} -#endif } // end namespace Eigen diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 5395e5436..53806ba33 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -13,487 +13,6 @@ #define EIGEN_ASSIGN_H namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for traversal and unrolling * -***************************************************************************/ - -template -struct assign_traits -{ -public: - enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned - }; - -private: - enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size - }; - - enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), - MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), - MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 - && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), - MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess - && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), - /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, - so it's only good for large enough sizes. */ - MaySliceVectorize = MightVectorize && DstHasDirectAccess - && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) - /* slice vectorization can be slow, so we only want it if the slices are big, which is - indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block - in a fixed-size matrix */ - }; - -public: - enum { - Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) - : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(MayLinearize) ? int(LinearTraversal) - : int(DefaultTraversal), - Vectorized = int(Traversal) == InnerVectorizedTraversal - || int(Traversal) == LinearVectorizedTraversal - || int(Traversal) == SliceVectorizedTraversal - }; - -private: - enum { - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), - MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) - }; - -public: - enum { - Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) - ? ( - int(MayUnrollCompletely) ? int(CompleteUnrolling) - : int(MayUnrollInner) ? int(InnerUnrolling) - : int(NoUnrolling) - ) - : int(Traversal) == int(LinearVectorizedTraversal) - ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(Traversal) == int(LinearTraversal) - ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(NoUnrolling) - }; - -#ifdef EIGEN_DEBUG_ASSIGN - static void debug() - { - EIGEN_DEBUG_VAR(DstIsAligned) - EIGEN_DEBUG_VAR(SrcIsAligned) - EIGEN_DEBUG_VAR(JointAlignment) - EIGEN_DEBUG_VAR(Derived::SizeAtCompileTime) - EIGEN_DEBUG_VAR(OtherDerived::CoeffReadCost) - EIGEN_DEBUG_VAR(InnerSize) - EIGEN_DEBUG_VAR(InnerMaxSize) - EIGEN_DEBUG_VAR(PacketSize) - EIGEN_DEBUG_VAR(StorageOrdersAgree) - EIGEN_DEBUG_VAR(MightVectorize) - EIGEN_DEBUG_VAR(MayLinearize) - EIGEN_DEBUG_VAR(MayInnerVectorize) - EIGEN_DEBUG_VAR(MayLinearVectorize) - EIGEN_DEBUG_VAR(MaySliceVectorize) - EIGEN_DEBUG_VAR(Traversal) - EIGEN_DEBUG_VAR(UnrollingLimit) - EIGEN_DEBUG_VAR(MayUnrollCompletely) - EIGEN_DEBUG_VAR(MayUnrollInner) - EIGEN_DEBUG_VAR(Unrolling) - } -#endif -}; - -/*************************************************************************** -* Part 2 : meta-unrollers -***************************************************************************/ - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime - }; - - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeffByOuterInner(outer, inner, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.copyCoeffByOuterInner(outer, Index, src); - assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); - } -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeff(Index, src); - assign_LinearTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_innervec_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime, - JointAlignment = assign_traits::JointAlignment - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.template copyPacketByOuterInner(outer, inner, src); - assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); - } -}; - -template -struct assign_innervec_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.template copyPacketByOuterInner(outer, Index, src); - assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); - } -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = assign_traits::Unrolling, - int Version = Specialized> -struct assign_impl; - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_impl -{ - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &, const Derived2 &) { } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; ++inner) - dst.copyCoeffByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_DefaultTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_DefaultTraversal_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - for(Index i = 0; i < size; ++i) - dst.copyCoeff(i, src); - } -}; - -template -struct assign_impl -{ - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_LinearTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index packetSize = packet_traits::size; - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; inner+=packetSize) - dst.template copyPacketByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_innervec_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_innervec_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*************************** -*** Linear vectorization *** -***************************/ - -template -struct unaligned_assign_impl -{ - template - static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} -}; - -template <> -struct 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, typename Derived::Index start, typename Derived::Index end) -#else - template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#endif - { - for (typename Derived::Index index = start; index < end; ++index) - dst.copyCoeff(index, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index alignedStart = assign_traits::DstIsAligned ? 0 - : internal::first_aligned(&dst.coeffRef(0), size); - const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; - - unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); - - for(Index index = alignedStart; index < alignedEnd; index += packetSize) - { - dst.template copyPacket(index, src); - } - - unaligned_assign_impl<>::run(src,dst,alignedEnd,size); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - enum { size = Derived1::SizeAtCompileTime, - packetSize = packet_traits::size, - alignedSize = (size/packetSize)*packetSize }; - - assign_innervec_CompleteUnrolling::run(dst, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -/************************** -*** Slice vectorization *** -***************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - alignable = PacketTraits::AlignedOnScalar, - dstAlignment = alignable ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index packetAlignedMask = packetSize - 1; - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || assign_traits::DstIsAligned) ? 0 - : internal::first_aligned(&dst.coeffRef(0,0), innerSize); - - for(Index outer = 0; outer < outerSize; ++outer) - { - const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); - // do the non-vectorizable part of the assignment - for(Index inner = 0; inner(outer, inner, src); - - // do the non-vectorizable part of the assignment - for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); - } - } -}; - -} // end namespace internal - -#endif // EIGEN_TEST_EVALUATORS - -/*************************************************************************** -* Part 4 : implementation of DenseBase methods -***************************************************************************/ template template @@ -508,71 +27,12 @@ EIGEN_STRONG_INLINE Derived& DenseBase EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) -#ifdef EIGEN_TEST_EVALUATORS - eigen_assert(rows() == other.rows() && cols() == other.cols()); internal::call_assignment_no_alias(derived(),other.derived()); -#else // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); -#endif - eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::assign_impl::Traversal) - : int(InvalidTraversal)>::run(derived(),other.derived()); - -#ifndef EIGEN_NO_DEBUG - checkTransposeAliasing(other.derived()); -#endif - -#endif // EIGEN_TEST_EVALUATORS - return derived(); } -namespace internal { - -#ifndef EIGEN_TEST_EVALUATORS -template::Flags) & EvalBeforeAssigningBit) != 0, - bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) - && int(Derived::SizeAtCompileTime) != 1> -struct assign_selector; - -template -struct assign_selector { - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } - template - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; -template -struct assign_selector { - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } -}; -template -struct assign_selector { - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } - template - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } -}; -template -struct assign_selector { - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } -}; -#endif // EIGEN_TEST_EVALUATORS -} // end namespace internal - -#ifdef EIGEN_TEST_EVALUATORS template template EIGEN_DEVICE_FUNC @@ -624,53 +84,6 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue< other.derived().evalTo(derived()); return derived(); } -#else // EIGEN_TEST_EVALUATORS -template -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} - -template -template -EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} -#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 4e35e432e..8ab71446c 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -695,13 +695,7 @@ void call_assignment(const Dst& dst, const Src& src) template void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) { -#ifdef EIGEN_TEST_EVALUATORS typename plain_matrix_type::type tmp(src); -#else - typename Src::PlainObject tmp(src.rows(), src.cols()); - call_assignment_no_alias(tmp, src, internal::assign_op()); -#endif - call_assignment_no_alias(dst, tmp, func); } diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index ba4749707..b0ebe1160 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -328,8 +328,6 @@ class TridiagonalMatrix : public BandMatrix @@ -347,8 +345,6 @@ struct evaluator_traits struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; -#endif - } // end namespace internal diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 2d62f7a46..737e5dc24 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -84,26 +84,11 @@ struct traits > : traits::size) == 0) - && (InnerStrideAtCompileTime == 1) - ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, - FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), - Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit -#else // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, Flags = (traits::Flags & DirectAccessBit) | FlagsLvalueBit | FlagsRowMajorBit // FIXME DirectAccessBit should not be handled by expressions -#endif }; }; diff --git a/Eigen/src/Core/BooleanRedux.h b/Eigen/src/Core/BooleanRedux.h index 192e1db53..dac1887e0 100644 --- a/Eigen/src/Core/BooleanRedux.h +++ b/Eigen/src/Core/BooleanRedux.h @@ -17,18 +17,11 @@ namespace internal { template struct all_unroller { -#ifdef EIGEN_TEST_EVALUATORS typedef typename Derived::ExpressionTraits Traits; enum { col = (UnrollCount-1) / Traits::RowsAtCompileTime, row = (UnrollCount-1) % Traits::RowsAtCompileTime }; -#else - enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime - }; -#endif static inline bool run(const Derived &mat) { @@ -51,18 +44,11 @@ struct all_unroller template struct any_unroller { -#ifdef EIGEN_TEST_EVALUATORS typedef typename Derived::ExpressionTraits Traits; enum { col = (UnrollCount-1) / Traits::RowsAtCompileTime, row = (UnrollCount-1) % Traits::RowsAtCompileTime }; -#else - enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime - }; -#endif static inline bool run(const Derived &mat) { @@ -94,7 +80,6 @@ struct any_unroller template inline bool DenseBase::all() const { -#ifdef EIGEN_TEST_EVALUATORS typedef typename internal::evaluator::type Evaluator; enum { unroll = SizeAtCompileTime != Dynamic @@ -112,24 +97,6 @@ inline bool DenseBase::all() const if (!evaluator.coeff(i, j)) return false; return true; } -#else - enum { - unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT - }; - - if(unroll) - return internal::all_unroller::run(derived()); - else - { - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if (!coeff(i, j)) return false; - return true; - } -#endif } /** \returns true if at least one coefficient is true @@ -139,7 +106,6 @@ inline bool DenseBase::all() const template inline bool DenseBase::any() const { -#ifdef EIGEN_TEST_EVALUATORS typedef typename internal::evaluator::type Evaluator; enum { unroll = SizeAtCompileTime != Dynamic @@ -157,23 +123,6 @@ inline bool DenseBase::any() const if (evaluator.coeff(i, j)) return true; return false; } -#else - enum { - unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT - }; - if(unroll) - return internal::any_unroller::run(derived()); - else - { - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if (coeff(i, j)) return true; - return false; - } -#endif } /** \returns the number of coefficients which evaluate to true diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index b4662907e..de9109e53 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -66,28 +66,7 @@ struct traits > typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { -#ifndef EIGEN_TEST_EVALUATORS - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - SameType = is_same::value, - StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), - Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( - HereditaryBits - | (int(LhsFlags) & int(RhsFlags) & - ( AlignedBit - | (StorageOrdersAgree ? LinearAccessBit : 0) - | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) - ) - ) - ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits::Cost -#else Flags = _LhsNested::Flags & RowMajorBit -#endif }; }; } // end namespace internal @@ -163,46 +142,6 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp m_functor; }; -#ifndef EIGEN_TEST_EVALUATORS -template -class CwiseBinaryOpImpl - : public internal::dense_xpr_base >::type -{ - typedef CwiseBinaryOp Derived; - public: - - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) - - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().lhs().coeff(rowId, colId), - derived().rhs().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), - derived().rhs().template packet(rowId, colId)); - } - - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().lhs().coeff(index), - derived().rhs().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().lhs().template packet(index), - derived().rhs().template packet(index)); - } -}; -#else // Generic API dispatcher template class CwiseBinaryOpImpl @@ -211,7 +150,6 @@ class CwiseBinaryOpImpl public: typedef typename internal::generic_xpr_base >::type Base; }; -#endif /** replaces \c *this by \c *this - \a other. * @@ -222,12 +160,7 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { -#ifdef EIGEN_TEST_EVALUATORS call_assignment(derived(), other.derived(), internal::sub_assign_op()); -#else - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); -#endif return derived(); } @@ -240,12 +173,7 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { -#ifdef EIGEN_TEST_EVALUATORS call_assignment(derived(), other.derived(), internal::add_assign_op()); -#else - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); -#endif return derived(); } diff --git a/Eigen/src/Core/CwiseNullaryOp.h b/Eigen/src/Core/CwiseNullaryOp.h index f9f127cc2..8b8397da6 100644 --- a/Eigen/src/Core/CwiseNullaryOp.h +++ b/Eigen/src/Core/CwiseNullaryOp.h @@ -35,16 +35,7 @@ template struct traits > : traits { enum { -#ifndef EIGEN_TEST_EVALUATORS - Flags = (traits::Flags - & ( HereditaryBits - | (functor_has_linear_access::ret ? LinearAccessBit : 0) - | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), - CoeffReadCost = functor_traits::Cost -#else Flags = traits::Flags & RowMajorBit -#endif }; }; } diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index c2bc47c93..79a872934 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -44,14 +44,7 @@ struct traits > typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { -#ifndef EIGEN_TEST_EVALUATORS - Flags = _XprTypeNested::Flags & ( - HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits::Cost -#else Flags = _XprTypeNested::Flags & RowMajorBit -#endif }; }; } @@ -97,45 +90,6 @@ class CwiseUnaryOp : internal::no_assignment_operator, const UnaryOp m_functor; }; -#ifndef EIGEN_TEST_EVALUATORS -// This is the generic implementation for dense storage. -// It can be used for any expression types implementing the dense concept. -template -class CwiseUnaryOpImpl - : public internal::dense_xpr_base >::type -{ - public: - - typedef CwiseUnaryOp Derived; - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); - } - - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(index)); - } -}; -#else // EIGEN_TEST_EVALUATORS // Generic API dispatcher template class CwiseUnaryOpImpl @@ -144,7 +98,6 @@ class CwiseUnaryOpImpl public: typedef typename internal::generic_xpr_base >::type Base; }; -#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 99cc03ac1..71249a39c 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -37,12 +37,7 @@ struct traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { -#ifndef EIGEN_TEST_EVALUATORS - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), - CoeffReadCost = traits<_MatrixTypeNested>::CoeffReadCost + functor_traits::Cost, -#else Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | LvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions -#endif MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values @@ -93,7 +88,6 @@ class CwiseUnaryView : public CwiseUnaryViewImpl class CwiseUnaryViewImpl @@ -102,7 +96,6 @@ class CwiseUnaryViewImpl public: typedef typename internal::generic_xpr_base >::type Base; }; -#endif template class CwiseUnaryViewImpl @@ -128,30 +121,6 @@ class CwiseUnaryViewImpl { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - -#ifndef EIGEN_TEST_EVALUATORS - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - return derived().functor()(derived().nestedExpression().coeff(row, col)); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); - } - -#endif }; } // end namespace Eigen diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index f35c2edc4..6078af553 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -74,18 +74,6 @@ template class DenseBase using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; -#ifndef EIGEN_TEST_EVALUATORS - using Base::packet; - using Base::packetByOuterInner; - using Base::writePacket; - using Base::writePacketByOuterInner; - using Base::coeffRef; - using Base::coeffRefByOuterInner; - using Base::copyCoeff; - using Base::copyCoeffByOuterInner; - using Base::copyPacket; - using Base::copyPacketByOuterInner; -#endif using Base::operator(); using Base::operator[]; using Base::x; @@ -171,13 +159,6 @@ template class DenseBase InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ -#endif - InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; @@ -292,15 +273,10 @@ template class DenseBase EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); -#ifndef EIGEN_TEST_EVALUATORS - template - const Flagged flagged() const; -#else // TODO flagged is temporarly disabled. It seems useless now template const Derived& flagged() const { return derived(); } -#endif template EIGEN_DEVICE_FUNC @@ -313,15 +289,6 @@ template class DenseBase ConstTransposeReturnType transpose() const; EIGEN_DEVICE_FUNC void transposeInPlace(); -#ifndef EIGEN_NO_DEBUG -#ifndef EIGEN_TEST_EVALUATORS - protected: - template - void checkTransposeAliasing(const OtherDerived& other) const; - public: -#endif -#endif - EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); @@ -402,7 +369,6 @@ template class DenseBase return typename internal::eval::type(derived()); } -#ifdef EIGEN_TEST_EVALUATORS /** swaps *this with the expression \a other. * */ @@ -425,28 +391,6 @@ template class DenseBase eigen_assert(rows()==other.rows() && cols()==other.cols()); call_assignment(derived(), other.derived(), internal::swap_assign_op()); } -#else // EIGEN_TEST_EVALUATORS - /** swaps *this with the expression \a other. - * - */ - template - EIGEN_DEVICE_FUNC - void swap(const DenseBase& other, - int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) - { - SwapWrapper(derived()).lazyAssign(other.derived()); - } - - /** swaps *this with the matrix or array \a other. - * - */ - template - EIGEN_DEVICE_FUNC - void swap(PlainObjectBase& other) - { - SwapWrapper(derived()).lazyAssign(other.derived()); - } -#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; diff --git a/Eigen/src/Core/DenseCoeffsBase.h b/Eigen/src/Core/DenseCoeffsBase.h index de31b8df2..a9e4dbaf9 100644 --- a/Eigen/src/Core/DenseCoeffsBase.h +++ b/Eigen/src/Core/DenseCoeffsBase.h @@ -98,11 +98,7 @@ class DenseCoeffsBase : public EigenBase { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().coeff(row, col); -#else return typename internal::evaluator::type(derived()).coeff(row,col); -#endif } EIGEN_DEVICE_FUNC @@ -144,11 +140,7 @@ class DenseCoeffsBase : public EigenBase coeff(Index index) const { eigen_internal_assert(index >= 0 && index < size()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().coeff(index); -#else return typename internal::evaluator::type(derived()).coeff(index); -#endif } @@ -226,11 +218,7 @@ class DenseCoeffsBase : public EigenBase EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().template packet(row,col); -#else return typename internal::evaluator::type(derived()).template packet(row,col); -#endif } @@ -256,11 +244,7 @@ class DenseCoeffsBase : public EigenBase EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { eigen_internal_assert(index >= 0 && index < size()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().template packet(index); -#else return typename internal::evaluator::type(derived()).template packet(index); -#endif } protected: @@ -341,11 +325,7 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() && col >= 0 && col < cols()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().coeffRef(row, col); -#else return typename internal::evaluator::type(derived()).coeffRef(row,col); -#endif } EIGEN_DEVICE_FUNC @@ -391,11 +371,7 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); -#ifndef EIGEN_TEST_EVALUATORS - return derived().coeffRef(index); -#else return typename internal::evaluator::type(derived()).coeffRef(index); -#endif } /** \returns a reference to the coefficient at given index. @@ -455,146 +431,6 @@ class DenseCoeffsBase : public DenseCoeffsBase - EIGEN_STRONG_INLINE void writePacket - (Index row, Index col, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row,col,val); - } - - - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacketByOuterInner - (Index outer, Index inner, const typename internal::packet_traits::type& val) - { - writePacket(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner), - val); - } - - /** \internal - * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - template - EIGEN_STRONG_INLINE void writePacket - (Index index, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index,val); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Copies the coefficient at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().coeffRef(row, col) = other.derived().coeff(row, col); - } - - /** \internal Copies the coefficient at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); - } - - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().copyCoeff(row, col, other); - } - - /** \internal Copies the packet at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row, col, - other.derived().template packet(row, col)); - } - - /** \internal Copies the packet at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index, - other.derived().template packet(index)); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); - } -#endif -#endif // EIGEN_TEST_EVALUATORS - }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 3ff6a3e66..1ffcd97f9 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -51,14 +51,8 @@ struct traits > : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, -#ifndef EIGEN_TEST_EVALUATORS - MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost, -#else MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions -#endif MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 801131b54..44c249aa6 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -45,20 +45,6 @@ class DiagonalBase : public EigenBase EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } -#ifndef EIGEN_TEST_EVALUATORS - template - EIGEN_DEVICE_FUNC - void evalTo(MatrixBase &other) const; - template - EIGEN_DEVICE_FUNC - void addTo(MatrixBase &other) const - { other.diagonal() += diagonal(); } - template - EIGEN_DEVICE_FUNC - void subTo(MatrixBase &other) const - { other.diagonal() -= diagonal(); } -#endif // EIGEN_TEST_EVALUATORS - EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } EIGEN_DEVICE_FUNC @@ -69,17 +55,6 @@ class DiagonalBase : public EigenBase EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. - */ - template - EIGEN_DEVICE_FUNC - const DiagonalProduct - operator*(const MatrixBase &matrix) const - { - return DiagonalProduct(matrix.derived(), derived()); - } -#else template EIGEN_DEVICE_FUNC const Product @@ -87,7 +62,6 @@ class DiagonalBase : public EigenBase { return Product(derived(),matrix.derived()); } -#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC inline const DiagonalWrapper, const DiagonalVectorType> > @@ -110,16 +84,6 @@ class DiagonalBase : public EigenBase } }; -#ifndef EIGEN_TEST_EVALUATORS -template -template -void DiagonalBase::evalTo(MatrixBase &other) const -{ - other.setZero(); - other.diagonal() = diagonal(); -} -#endif // EIGEN_TEST_EVALUATORS - #endif /** \class DiagonalMatrix @@ -273,10 +237,6 @@ struct traits > MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit -#ifndef EIGEN_TEST_EVALUATORS - , - CoeffReadCost = traits<_DiagonalVectorType>::CoeffReadCost -#endif }; }; } @@ -347,7 +307,6 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const return true; } -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; @@ -368,7 +327,6 @@ struct Assignment }; } // namespace internal -#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/DiagonalProduct.h b/Eigen/src/Core/DiagonalProduct.h index c6dafdddc..d372b938f 100644 --- a/Eigen/src/Core/DiagonalProduct.h +++ b/Eigen/src/Core/DiagonalProduct.h @@ -13,122 +13,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { -template -struct traits > - : traits -{ - typedef typename scalar_product_traits::ReturnType Scalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - -#ifndef EIGEN_TEST_EVALUATORS - _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, - _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) - ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), - _SameTypes = is_same::value, - // FIXME currently we need same types, but in the future the next rule should be the one - //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit, //(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - CoeffReadCost = NumTraits::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost -#else - Flags = RowMajorBit & (unsigned int)(MatrixType::Flags) -#endif - }; -}; -} - -template -class DiagonalProduct : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) - - inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) - : m_matrix(matrix), m_diagonal(diagonal) - { - eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const - { - enum { - StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor - }; - const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; - return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< - ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) - ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - protected: - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const - { - return internal::pmul(m_matrix.template packet(row, col), - internal::pset1(m_diagonal.diagonal().coeff(id))); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const - { - enum { - InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) - }; - return internal::pmul(m_matrix.template packet(row, col), - m_diagonal.diagonal().template packet(id)); - } - - typename MatrixType::Nested m_matrix; - typename DiagonalType::Nested m_diagonal; -}; - -/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. - */ -template -template -inline const DiagonalProduct -MatrixBase::operator*(const DiagonalBase &a_diagonal) const -{ - return DiagonalProduct(derived(), a_diagonal.derived()); -} -#else // EIGEN_TEST_EVALUATORS /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. */ template @@ -138,7 +22,6 @@ MatrixBase::operator*(const DiagonalBase &a_diagonal) { return Product(derived(),a_diagonal.derived()); } -#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index d6441c6a5..68e9c2660 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -113,13 +113,7 @@ template inline const typename MatrixBase::PlainObject MatrixBase::normalized() const { -#ifndef EIGEN_TEST_EVALUATORS - typedef typename internal::nested::type Nested; - typedef typename internal::remove_reference::type _Nested; -#else typedef typename internal::nested_eval::type _Nested; -// typedef typename internal::remove_reference::type _Nested; -#endif // EIGEN_TEST_EVALUATORS _Nested n(derived()); return n / n.norm(); } @@ -211,13 +205,8 @@ template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { -#ifndef EIGEN_TEST_EVALUATORS - typename internal::nested::type nested(derived()); - typename internal::nested::type otherNested(other.derived()); -#else typename internal::nested_eval::type nested(derived()); typename internal::nested_eval::type otherNested(other.derived()); -#endif return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } diff --git a/Eigen/src/Core/EigenBase.h b/Eigen/src/Core/EigenBase.h index 986e2a196..52b66e6dc 100644 --- a/Eigen/src/Core/EigenBase.h +++ b/Eigen/src/Core/EigenBase.h @@ -121,11 +121,7 @@ template template Derived& DenseBase::operator=(const EigenBase &other) { -#ifndef EIGEN_TEST_EVALUATORS - other.derived().evalTo(derived()); -#else call_assignment(derived(), other.derived()); -#endif return derived(); } @@ -133,11 +129,7 @@ template template Derived& DenseBase::operator+=(const EigenBase &other) { -#ifndef EIGEN_TEST_EVALUATORS - other.derived().addTo(derived()); -#else call_assignment(derived(), other.derived(), internal::add_assign_op()); -#endif return derived(); } @@ -145,11 +137,7 @@ template template Derived& DenseBase::operator-=(const EigenBase &other) { -#ifndef EIGEN_TEST_EVALUATORS - other.derived().subTo(derived()); -#else call_assignment(derived(), other.derived(), internal::sub_assign_op()); -#endif return derived(); } diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index 9c8d10683..8cd069a0d 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -23,13 +23,8 @@ struct isApprox_selector static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { EIGEN_USING_STD_MATH(min); -#ifdef EIGEN_TEST_EVALUATORS typename internal::nested_eval::type nested(x); typename internal::nested_eval::type otherNested(y); -#else - typename internal::nested::type nested(x); - typename internal::nested::type otherNested(y); -#endif return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index abbf69549..e05ff8dce 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -13,31 +13,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS -/** \class GeneralProduct - * \ingroup Core_Module - * - * \brief Expression of the product of two general matrices or vectors - * - * \param LhsNested the type used to store the left-hand side - * \param RhsNested the type used to store the right-hand side - * \param ProductMode the type of the product - * - * This class represents an expression of the product of two general matrices. - * We call a general matrix, a dense matrix with full storage. For instance, - * This excludes triangular, selfadjoint, and sparse matrices. - * It is the return type of the operator* between general matrices. Its template - * arguments are determined automatically by ProductReturnType. Therefore, - * GeneralProduct should never be used direclty. To determine the result type of a - * function which involves a matrix product, use ProductReturnType::Type. - * - * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) - */ -template::value> -class GeneralProduct; -#endif // EIGEN_TEST_EVALUATORS - - enum { Large = 2, Small = 3 @@ -156,56 +131,6 @@ template<> struct product_type_selector { enum } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS -/** \class ProductReturnType - * \ingroup Core_Module - * - * \brief Helper class to get the correct and optimized returned type of operator* - * - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * \param ProductMode the type of the product (determined automatically by internal::product_mode) - * - * This class defines the typename Type representing the optimized product expression - * between two matrix expressions. In practice, using ProductReturnType::Type - * is the recommended way to define the result type of a function returning an expression - * which involve a matrix product. The class Product should never be - * used directly. - * - * \sa class Product, MatrixBase::operator*(const MatrixBase&) - */ -template -struct ProductReturnType -{ - // TODO use the nested type to reduce instanciations ???? -// typedef typename internal::nested::type LhsNested; -// typedef typename internal::nested::type RhsNested; - - typedef GeneralProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -// this is a workaround for sun CC -template -struct LazyProductReturnType : public ProductReturnType -{}; -#endif - /*********************************************************************** * Implementation of Inner Vector Vector Product ***********************************************************************/ @@ -216,124 +141,11 @@ struct LazyProductReturnType : public ProductReturnType with: operator=(Scalar x); -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct traits > - : traits::ReturnType,1,1> > -{}; - -} - -template -class GeneralProduct - : internal::no_assignment_operator, - public Matrix::ReturnType,1,1> -{ - typedef Matrix::ReturnType,1,1> Base; - public: - GeneralProduct(const Lhs& lhs, const Rhs& rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); - } - - /** Convertion to scalar */ - operator const typename Base::Scalar() const { - return Base::coeff(0,0); - } -}; -#endif // EIGEN_TEST_EVALUATORS /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -// Column major -template -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) -{ - typedef typename Dest::Index Index; - // FIXME make sure lhs is sequentially stored - // FIXME not very good if rhs is real and lhs complex while alpha is real too - const Index cols = dest.cols(); - for (Index j=0; j -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { - typedef typename Dest::Index Index; - // FIXME make sure rhs is sequentially stored - // FIXME not very good if lhs is real and rhs complex while alpha is real too - const Index rows = dest.rows(); - for (Index i=0; i -struct traits > - : traits, Lhs, Rhs> > -{}; - -} - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - template struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; - - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; - struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; - struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; - struct adds { - Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} - template void operator()(const Dst& dst, const Src& src) const { - dst.const_cast_derived() += m_scale * src; - } - }; - - template - inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), IsRowMajor()); - } - - template - inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), IsRowMajor()); - } - - template - inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), IsRowMajor()); - } - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::outer_product_selector_run(*this, dest, adds(alpha), IsRowMajor()); - } -}; - -#endif // EIGEN_TEST_EVALUATORS - /*********************************************************************** * Implementation of General Matrix Vector Product ***********************************************************************/ @@ -347,50 +159,11 @@ class GeneralProduct */ namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct traits > - : traits, Lhs, Rhs> > -{}; -template -struct gemv_selector; -#endif -#ifdef EIGEN_ENABLE_EVALUATORS template struct gemv_dense_sense_selector; -#endif } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - - GeneralProduct(const Lhs& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_rhs) - { -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; - typedef typename internal::conditional::type MatrixType; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); - } -}; -#endif - namespace internal { template struct gemv_static_vector_if; @@ -429,177 +202,6 @@ struct gemv_static_vector_if #endif }; -#ifndef EIGEN_TEST_EVALUATORS - -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - -template<> struct gemv_selector -{ - template - static inline void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - typedef Map, Aligned> MappedDest; - - ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1, - ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), - MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal - }; - - gemv_static_vector_if static_dest; - - bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); - bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - - RhsScalar compatibleAlpha = get_factor::run(actualAlpha); - - ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), - evalToDest ? dest.data() : static_dest.data()); - - if(!evalToDest) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - Index size = dest.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - if(!alphaIsCompatible) - { - MappedDest(actualDestPtr, dest.size()).setZero(); - compatibleAlpha = RhsScalar(1); - } - else - MappedDest(actualDestPtr, dest.size()) = dest; - } - - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhs.data(), actualRhs.innerStride(), - actualDestPtr, 1, - compatibleAlpha); - - if (!evalToDest) - { - if(!alphaIsCompatible) - dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); - else - dest = MappedDest(actualDestPtr, dest.size()); - } - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 - }; - - gemv_static_vector_if static_rhs; - - ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), - DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); - - if(!DirectlyUseRhs) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - Index size = actualRhs.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; - } - - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhsPtr, 1, - dest.data(), dest.innerStride(), - actualAlpha); - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure dest is sequentially stored in memory, otherwise use a temp - const Index size = prod.rhs().rows(); - for(Index k=0; k struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp - const Index rows = prod.rows(); - for(Index i=0; i transposition template struct gemv_dense_sense_selector @@ -767,8 +369,6 @@ template<> struct gemv_dense_sense_selector } }; -#endif // EIGEN_ENABLE_EVALUATORS - } // end namespace internal /*************************************************************************** @@ -783,7 +383,6 @@ template<> struct gemv_dense_sense_selector */ #ifndef __CUDACC__ -#ifdef EIGEN_TEST_EVALUATORS template template inline const Product @@ -814,37 +413,6 @@ MatrixBase::operator*(const MatrixBase &other) const return Product(derived(), other.derived()); } -#else // EIGEN_TEST_EVALUATORS -template -template -inline const typename ProductReturnType::Type -MatrixBase::operator*(const MatrixBase &other) const -{ - // A note regarding the function declaration: In MSVC, this function will sometimes - // not be inlined since DenseStorage is an unwindable object for dynamic - // matrices and product types are holding a member to store the result. - // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. - 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) -#ifdef EIGEN_DEBUG_PRODUCT - internal::product_type::debug(); -#endif - return typename ProductReturnType::Type(derived(), other.derived()); -} -#endif // EIGEN_TEST_EVALUATORS #endif // __CUDACC__ @@ -859,7 +427,6 @@ MatrixBase::operator*(const MatrixBase &other) const * * \sa operator*(const MatrixBase&) */ -#ifdef EIGEN_TEST_EVALUATORS template template const Product @@ -883,31 +450,6 @@ MatrixBase::lazyProduct(const MatrixBase &other) const return Product(derived(), other.derived()); } -#else // EIGEN_TEST_EVALUATORS -template -template -const typename LazyProductReturnType::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 LazyProductReturnType::Type(derived(), other.derived()); -} -#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 84abd258e..5cfa7e50c 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -12,8 +12,6 @@ namespace Eigen { -#ifdef EIGEN_TEST_EVALUATORS - // TODO move the general declaration in Core, and rename this file DenseInverseImpl.h, or something like this... template class InverseImpl; @@ -127,8 +125,6 @@ protected: } // end namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_INVERSE_H diff --git a/Eigen/src/Core/Map.h b/Eigen/src/Core/Map.h index 7dfdc3d59..87c1787bf 100644 --- a/Eigen/src/Core/Map.h +++ b/Eigen/src/Core/Map.h @@ -80,26 +80,8 @@ struct traits > ? int(PlainObjectType::OuterStrideAtCompileTime) : int(StrideType::OuterStrideAtCompileTime), IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), -#ifndef EIGEN_TEST_EVALUATORS - HasNoInnerStride = InnerStrideAtCompileTime == 1, - HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, - HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, - KeepsPacketAccess = bool(HasNoInnerStride) - && ( bool(IsDynamicSize) - || HasNoOuterStride - || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%EIGEN_ALIGN_BYTES)==0 ) ), - Flags0 = TraitsBase::Flags & (~NestByRefBit), - Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), - Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) - ? int(Flags1) : int(Flags1 & ~LinearAccessBit), - Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), - Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) -#else Flags0 = TraitsBase::Flags & (~NestByRefBit), Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) -#endif }; private: enum { Options }; // Expressions don't have Options diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 591ea26fb..6d3b344e8 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -11,15 +11,9 @@ #ifndef EIGEN_MAPBASE_H #define EIGEN_MAPBASE_H -#ifndef EIGEN_TEST_EVALUATORS -#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ - EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ - YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) -#else #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) -#endif namespace Eigen { @@ -167,15 +161,7 @@ template class MapBase EIGEN_DEVICE_FUNC void checkSanity() const { -#ifndef EIGEN_TEST_EVALUATORS - // moved to evaluator - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, - internal::inner_stride_at_compile_time::ret==1), - PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % EIGEN_ALIGN_BYTES) == 0) && "data is not aligned"); -#else eigen_assert(EIGEN_IMPLIES(internal::traits::IsAligned, (size_t(m_data) % EIGEN_ALIGN_BYTES) == 0) && "data is not aligned"); -#endif } PointerType m_data; diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 1daaabb07..8a5821548 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -115,12 +115,8 @@ struct traits > MaxRowsAtCompileTime = _MaxRows, MaxColsAtCompileTime = _MaxCols, Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = NumTraits::ReadCost, -#else // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase EvaluatorFlags = compute_matrix_evaluator_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, -#endif Options = _Options, InnerStrideAtCompileTime = 1, OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index bb49b9e84..9dbbd6fb5 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -66,9 +66,6 @@ template class MatrixBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; -#ifndef EIGEN_TEST_EVALUATORS - using Base::CoeffReadCost; -#endif using Base::derived; using Base::const_cast_derived; @@ -188,25 +185,15 @@ template class MatrixBase { return this->lazyProduct(other); } #else -#ifdef EIGEN_TEST_EVALUATORS template const Product operator*(const MatrixBase &other) const; -#else - template - const typename ProductReturnType::Type - operator*(const MatrixBase &other) const; -#endif #endif template EIGEN_DEVICE_FUNC -#ifdef EIGEN_TEST_EVALUATORS const Product -#else - const typename LazyProductReturnType::Type -#endif lazyProduct(const MatrixBase &other) const; template @@ -218,17 +205,10 @@ template class MatrixBase template void applyOnTheRight(const EigenBase& other); -#ifndef EIGEN_TEST_EVALUATORS - template - EIGEN_DEVICE_FUNC - const DiagonalProduct - operator*(const DiagonalBase &diagonal) const; -#else // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC const Product operator*(const DiagonalBase &diagonal) const; -#endif // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC @@ -347,19 +327,12 @@ template class MatrixBase NoAlias noalias(); -#ifndef EIGEN_TEST_EVALUATORS - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); -#else // TODO forceAlignedAccess is temporarly disabled // Need to find a nicer workaround. inline const Derived& forceAlignedAccess() const { return derived(); } inline Derived& forceAlignedAccess() { return derived(); } template inline const Derived& forceAlignedAccessIf() const { return derived(); } template inline Derived& forceAlignedAccessIf() { return derived(); } -#endif Scalar trace() const; @@ -382,13 +355,9 @@ template class MatrixBase const PartialPivLU lu() const; - #ifdef EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC const Inverse inverse() const; - #else - EIGEN_DEVICE_FUNC - const internal::inverse_impl inverse() const; - #endif + template void computeInverseAndDetWithCheck( ResultType& inverse, diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index fe6dded60..097c9c062 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -35,7 +35,6 @@ class NoAlias NoAlias(ExpressionType& expression) : m_expression(expression) {} -#ifdef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) @@ -59,68 +58,6 @@ class NoAlias call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } - -#else - - /** Behaves like MatrixBase::lazyAssign(other) - * \sa MatrixBase::lazyAssign() */ - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) - { return internal::assign_selector::run(m_expression,other.derived()); } - - /** \sa MatrixBase::operator+= */ - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) - { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); - return m_expression; - } - - /** \sa MatrixBase::operator-= */ - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) - { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); - return m_expression; - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) - { other.derived().addTo(m_expression); return m_expression; } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) - { other.derived().subTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - ExpressionType& operator=(const ReturnByValue& func) - { return m_expression = func; } -#endif - -#endif EIGEN_DEVICE_FUNC ExpressionType& expression() const diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 31e0697a1..200518173 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -61,9 +61,6 @@ class PermutationBase : public EigenBase typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = Traits::CoeffReadCost, -#endif RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, @@ -291,9 +288,7 @@ class PermutationMatrix : public PermutationBase Traits; public: -#ifdef EIGEN_TEST_EVALUATORS typedef const PermutationMatrix& Nested; -#endif #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; @@ -484,18 +479,9 @@ struct traits > enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, -#ifdef EIGEN_TEST_EVALUATORS MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, -#else - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, // is this a bug in Eigen 2.2 ? - MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, -#endif Flags = 0 -#ifndef EIGEN_TEST_EVALUATORS - , - CoeffReadCost = _IndicesType::CoeffReadCost -#endif }; }; } @@ -524,7 +510,6 @@ class PermutationWrapper : public PermutationBase &permutation, (permutation.derived(), matrix.derived()); } -#else // EIGEN_TEST_EVALUATORS - -/** \returns the matrix with the permutation applied to the columns. - */ -template -inline const internal::permut_matrix_product_retval -operator*(const MatrixBase& matrix, - const PermutationBase &permutation) -{ - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); -} - -/** \returns the matrix with the permutation applied to the rows. - */ -template -inline const internal::permut_matrix_product_retval - -operator*(const PermutationBase &permutation, - const MatrixBase& matrix) -{ - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); -} - -#endif // EIGEN_TEST_EVALUATORS - namespace internal { template @@ -682,9 +638,6 @@ class Transpose > typedef typename Derived::DenseMatrixType DenseMatrixType; enum { Flags = Traits::Flags, -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = Traits::CoeffReadCost, -#endif RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, @@ -713,8 +666,6 @@ class Transpose > DenseMatrixType toDenseMatrix() const { return *this; } -#ifdef EIGEN_TEST_EVALUATORS - /** \returns the matrix with the inverse permutation applied to the columns. */ template friend @@ -733,28 +684,6 @@ class Transpose > return Product(*this, matrix.derived()); } -#else // EIGEN_TEST_EVALUATORS - - /** \returns the matrix with the inverse permutation applied to the columns. - */ - template friend - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trPerm) - { - return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); - } - - /** \returns the matrix with the inverse permutation applied to the rows. - */ - template - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix) const - { - return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); - } - -#endif // EIGEN_TEST_EVALUATORS - const PermutationType& nestedPermutation() const { return m_permutation; } protected: @@ -767,7 +696,6 @@ const PermutationWrapper MatrixBase::asPermutation() con return derived(); } -#ifdef EIGEN_TEST_EVALUATORS namespace internal { // TODO currently a permutation matrix expression has the form PermutationMatrix or PermutationWrapper @@ -799,7 +727,6 @@ struct evaluator_traits > > template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 3637b6256..11aec1552 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -128,11 +128,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type DenseStorage m_storage; public: -#ifndef EIGEN_TEST_EVALUATORS - enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; -#else enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::EvaluatorFlags & AlignedBit) != 0 }; -#endif EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) EIGEN_DEVICE_FUNC @@ -643,7 +639,6 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \internal */ -#ifdef EIGEN_TEST_EVALUATORS // aliasing is dealt once in internall::call_assignment // so at this stage we have to assume aliasing... and resising has to be done later. template @@ -654,23 +649,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type return this->derived(); return this->derived(); } -#else - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) - { - _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); - return this->derived(); - } - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } -#endif /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * @@ -685,12 +664,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. -#ifdef EIGEN_TEST_EVALUATORS internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); return this->derived(); -#else - return internal::assign_selector::run(this->derived(), other.derived()); -#endif } template diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 6825873d5..ae64d5200 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -79,11 +79,6 @@ struct traits > // FIXME: only needed by GeneralMatrixMatrixTriangular InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), -#ifndef EIGEN_TEST_EVALUATORS - // dummy, for evaluators unit test only - CoeffReadCost = Dynamic, -#endif - // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. Flags = ( (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) || ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) @@ -164,7 +159,6 @@ public: } // namespace internal -#ifdef EIGEN_TEST_EVALUATORS // Generic API dispatcher template class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type @@ -172,7 +166,6 @@ class ProductImpl : public internal::generic_xpr_base, M public: typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; }; -#endif template class ProductImpl diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 4b1fe356b..050343b2d 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -12,258 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS - -/** \class ProductBase - * \ingroup Core_Module - * - */ - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename product_promote_storage_type::StorageKind, - typename traits::StorageKind, - 0>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - // Note that EvalBeforeNestingBit and NestByRefBit - // are not used in practice because nested is overloaded for products - CoeffReadCost = 0 // FIXME why is it needed ? - }; -}; -} - -#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef ProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Base::LhsNested LhsNested; \ - typedef typename Base::_LhsNested _LhsNested; \ - typedef typename Base::LhsBlasTraits LhsBlasTraits; \ - typedef typename Base::ActualLhsType ActualLhsType; \ - typedef typename Base::_ActualLhsType _ActualLhsType; \ - typedef typename Base::RhsNested RhsNested; \ - typedef typename Base::_RhsNested _RhsNested; \ - typedef typename Base::RhsBlasTraits RhsBlasTraits; \ - typedef typename Base::ActualRhsType ActualRhsType; \ - typedef typename Base::_ActualRhsType _ActualRhsType; \ - using Base::m_lhs; \ - using Base::m_rhs; - -template -class ProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - - typedef typename Lhs::Nested LhsNested; - typedef typename internal::remove_all::type _LhsNested; - typedef internal::blas_traits<_LhsNested> LhsBlasTraits; - typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; - typedef typename internal::remove_all::type _ActualLhsType; - typedef typename internal::traits::Scalar LhsScalar; - - typedef typename Rhs::Nested RhsNested; - typedef typename internal::remove_all::type _RhsNested; - typedef internal::blas_traits<_RhsNested> RhsBlasTraits; - typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - typedef typename internal::remove_all::type _ActualRhsType; - typedef typename internal::traits::Scalar RhsScalar; - - // 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::PlainObject PlainObject; - - ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) - : m_lhs(a_lhs), m_rhs(a_rhs) - { - eigen_assert(a_lhs.cols() == a_rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - operator const PlainObject& () const - { - m_result.resize(m_lhs.rows(), m_rhs.cols()); - derived().evalTo(m_result); - 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(Index index) const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isn't an Lvalue expression - typename Base::CoeffReturnType coeff(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(row,col); - } - - typename Base::CoeffReturnType coeff(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(i); - } - - const Scalar& coeffRef(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(row,col); - } - - const Scalar& coeffRef(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(i); - } - - protected: - - LhsNested m_lhs; - RhsNested m_rhs; - - mutable PlainObject m_result; -}; - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -namespace internal { -template -struct nested, N, PlainObject> -{ - typedef PlainObject const& type; -}; -} - -template -class ScaledProduct; - -// Note that these two operator* functions are not defined as member -// functions of ProductBase, because, otherwise we would have to -// define all overloads defined in MatrixBase. Furthermore, Using -// "using Base::operator*" would not work with MSVC. -// -// Also note that here we accept any compatible scalar types -template -const ScaledProduct -operator*(const ProductBase& prod, const typename Derived::Scalar& x) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const ProductBase& prod, const typename Derived::RealScalar& x) -{ return ScaledProduct(prod.derived(), x); } - - -template -const ScaledProduct -operator*(const typename Derived::Scalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const typename Derived::RealScalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -namespace internal { -template -struct traits > - : traits, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> > -{ - typedef typename traits::StorageKind StorageKind; -}; -} - -template -class ScaledProduct - : public ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> -{ - public: - typedef ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> Base; - typedef typename Base::Scalar Scalar; - typedef typename Base::PlainObject PlainObject; -// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) - - ScaledProduct(const NestedProduct& prod, const Scalar& x) - : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } - - const Scalar& alpha() const { return m_alpha; } - - protected: - const NestedProduct& m_prod; - Scalar m_alpha; -}; - -#endif // EIGEN_TEST_EVALUATORS - /** \internal * Overloaded to perform an efficient C = (A*B).lazy() */ template diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 0aeae88bc..c6c355d43 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -69,11 +69,7 @@ public: #ifdef EIGEN_DEBUG_ASSIGN static void debug() { -#ifdef EIGEN_TEST_EVALUATORS std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; -#else - std::cerr << "Xpr: " << typeid(Derived).name() << std::endl; -#endif std::cerr.setf(std::ios::hex, std::ios::basefield); EIGEN_DEBUG_VAR(Derived::Flags) std::cerr.unsetf(std::ios::hex); @@ -338,7 +334,6 @@ struct redux_impl } }; -#ifdef EIGEN_ENABLE_EVALUATORS // evaluator adaptor template class redux_evaluator @@ -395,7 +390,6 @@ protected: typename internal::evaluator::nestedType m_evaluator; const XprType &m_xpr; }; -#endif } // end namespace internal @@ -417,7 +411,6 @@ EIGEN_STRONG_INLINE typename internal::result_of::redux(const Func& func) const { eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); -#ifdef EIGEN_TEST_EVALUATORS // FIXME, eval_nest should be handled by redux_evaluator, however: // - it is currently difficult to provide the right Flags since they are still handled by the expressions @@ -433,13 +426,6 @@ DenseBase::redux(const Func& func) const ThisEvaluator thisEval(derived()); return internal::redux_impl::run(thisEval, func); - -#else - typedef typename internal::remove_all::type ThisNested; - - return internal::redux_impl - ::run(derived(), func); -#endif } /** \returns the minimum of all coefficients of \c *this. diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 6390a8b64..09921c9e7 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -243,11 +243,7 @@ template class Ref< template void construct(const Expression& expr, internal::false_type) { -#ifdef EIGEN_TEST_EVALUATORS internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); -#else - m_object.lazyAssign(expr); -#endif Base::construct(m_object); } diff --git a/Eigen/src/Core/Replicate.h b/Eigen/src/Core/Replicate.h index e63f0d421..3777049ee 100644 --- a/Eigen/src/Core/Replicate.h +++ b/Eigen/src/Core/Replicate.h @@ -54,13 +54,8 @@ struct traits > : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, -#ifndef EIGEN_TEST_EVALUATORS - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost -#else // FIXME enable DirectAccess with negative strides? Flags = IsRowMajor ? RowMajorBit : 0 -#endif }; }; } diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 9d53fba27..f4e12a93b 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -33,25 +33,18 @@ struct traits > }; }; -#ifndef EIGEN_TEST_EVALUATORS /* The ReturnByValue object doesn't even have a coeff() method. * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators */ template -struct nested, n, PlainObject> -{ - typedef typename traits::ReturnType type; -}; -#else -template struct nested_eval, n, PlainObject> { typedef typename traits::ReturnType type; }; -#endif } // end namespace internal @@ -93,7 +86,6 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } -#ifdef EIGEN_TEST_EVALUATORS namespace internal { // Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that @@ -123,7 +115,6 @@ protected: }; } // end namespace internal -#endif } // end namespace Eigen diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index ceb6e4701..01de90800 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -44,17 +44,7 @@ struct traits > ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - -#ifndef EIGEN_TEST_EVALUATORS - // let's enable LinearAccess only with vectorization because of the product overhead - LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) - ? LinearAccessBit : 0, - - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost -#else Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) -#endif }; }; diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h index d4fd88e62..0cb85a4ad 100644 --- a/Eigen/src/Core/Select.h +++ b/Eigen/src/Core/Select.h @@ -43,14 +43,7 @@ struct traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, -#ifndef EIGEN_TEST_EVALUATORS - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, - CoeffReadCost = traits::type>::CoeffReadCost - + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, - traits::type>::CoeffReadCost) -#else Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit -#endif }; }; } diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 546f61252..19cb232c9 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -40,20 +40,10 @@ struct traits > : traits Mode = UpLo | SelfAdjoint, Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)) // FIXME these flags should be preserved -#ifndef EIGEN_TEST_EVALUATORS - , - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost -#endif }; }; } -#ifndef EIGEN_TEST_EVALUATORS -template -struct SelfadjointProductMatrix; -#endif - // FIXME could also be called SelfAdjointWrapper to be consistent with DiagonalWrapper ?? template class SelfAdjointView : public TriangularBase > @@ -118,8 +108,6 @@ template class SelfAdjointView EIGEN_DEVICE_FUNC MatrixTypeNestedCleaned& nestedExpression() { return *const_cast(&m_matrix); } -#ifdef EIGEN_TEST_EVALUATORS - /** Efficient triangular matrix times vector/matrix product */ template EIGEN_DEVICE_FUNC @@ -145,31 +133,6 @@ template class SelfAdjointView return (s*mat.nestedExpression()).template selfadjointView(); } -#else // EIGEN_TEST_EVALUATORS - - /** Efficient self-adjoint matrix times vector/matrix product */ - template - EIGEN_DEVICE_FUNC - SelfadjointProductMatrix - operator*(const MatrixBase& rhs) const - { - return SelfadjointProductMatrix - - (m_matrix, rhs.derived()); - } - - /** Efficient vector/matrix times self-adjoint matrix product */ - template friend - EIGEN_DEVICE_FUNC - SelfadjointProductMatrix - operator*(const MatrixBase& lhs, const SelfAdjointView& rhs) - { - return SelfadjointProductMatrix - - (lhs.derived(),rhs.m_matrix); - } -#endif - /** Perform a symmetric rank 2 update of the selfadjoint matrix \c *this: * \f$ this = this + \alpha u v^* + conj(\alpha) v u^* \f$ * \returns a reference to \c *this @@ -231,104 +194,6 @@ template class SelfAdjointView namespace internal { -#ifndef EIGEN_TEST_EVALUATORS - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row < col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector -{ - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - if(row == col) - dst.coeffRef(row, col) = numext::real(src.coeff(row, col)); - else if(row > col) - dst.coeffRef(col, row) = numext::conj(dst.coeffRef(row, col) = src.coeff(row, col)); - } -}; - -template -struct triangular_assignment_selector -{ - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = 0; i < j; ++i) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(j, j, src); - } - } -}; - -template -struct triangular_assignment_selector -{ - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef typename Derived1::Index Index; - for(Index i = 0; i < dst.rows(); ++i) - { - for(Index j = 0; j < i; ++j) - { - dst.copyCoeff(i, j, src); - dst.coeffRef(j,i) = numext::conj(dst.coeff(i,j)); - } - dst.copyCoeff(i, i, src); - } - } -}; - -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_ENABLE_EVALUATORS - // TODO currently a selfadjoint expression has the form SelfAdjointView<.,.> // in the future selfadjoint-ness should be defined by the expression traits // such that Transpose > is valid. (currently TriangularBase::transpose() is overloaded to make it work) @@ -382,8 +247,6 @@ public: { eigen_internal_assert(false && "should never be called"); } }; -#endif // EIGEN_ENABLE_EVALUATORS - } // end namespace internal /*************************************************************************** diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index bec6f4968..38185d9d7 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -12,178 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS - -/** \class SelfCwiseBinaryOp - * \ingroup Core_Module - * - * \internal - * - * \brief Internal helper class for optimizing operators like +=, -= - * - * This is a pseudo expression class re-implementing the copyCoeff/copyPacket - * method to directly performs a +=/-= operations in an optimal way. In particular, - * this allows to make sure that the input/output data are loaded only once using - * aligned packet loads. - * - * \sa class SwapWrapper for a similar trick. - */ - -namespace internal { -template -struct traits > - : traits > -{ - enum { - // Note that it is still a good idea to preserve the DirectAccessBit - // so that assign can correctly align the data. - Flags = traits >::Flags | (Lhs::Flags&AlignedBit) | (Lhs::Flags&DirectAccessBit) | (Lhs::Flags&LvalueBit), - OuterStrideAtCompileTime = Lhs::OuterStrideAtCompileTime, - InnerStrideAtCompileTime = Lhs::InnerStrideAtCompileTime - }; -}; -} - -template class SelfCwiseBinaryOp - : public internal::dense_xpr_base< SelfCwiseBinaryOp >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SelfCwiseBinaryOp) - - typedef typename internal::packet_traits::type Packet; - - EIGEN_DEVICE_FUNC - inline SelfCwiseBinaryOp(Lhs& xpr, const BinaryOp& func = BinaryOp()) : m_matrix(xpr), m_functor(func) {} - - EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } - EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_matrix.outerStride(); } - EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.innerStride(); } - EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_matrix.data(); } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index row, Index col) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(row, col); - } - EIGEN_DEVICE_FUNC - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.coeffRef(row, col); - } - - // note that this function is needed by assign to correctly align loads/stores - // TODO make Assign use .data() - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(Lhs) - return m_matrix.const_cast_derived().coeffRef(index); - } - EIGEN_DEVICE_FUNC - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - EIGEN_DEVICE_FUNC - void copyCoeff(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - Scalar& tmp = m_matrix.coeffRef(row,col); - tmp = m_functor(tmp, _other.coeff(row,col)); - } - - template - EIGEN_DEVICE_FUNC - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - Scalar& tmp = m_matrix.coeffRef(index); - tmp = m_functor(tmp, _other.coeff(index)); - } - - template - void copyPacket(Index row, Index col, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - m_matrix.template writePacket(row, col, - m_functor.packetOp(m_matrix.template packet(row, col),_other.template packet(row, col)) ); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_matrix.size()); - m_matrix.template writePacket(index, - m_functor.packetOp(m_matrix.template packet(index),_other.template packet(index)) ); - } - - // reimplement lazyAssign to handle complex *= real - // see CwiseBinaryOp ctor for details - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE SelfCwiseBinaryOp& lazyAssign(const DenseBase& rhs) - { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs,RhsDerived) - EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename RhsDerived::Scalar); - - #ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); - #endif - eigen_assert(rows() == rhs.rows() && cols() == rhs.cols()); - internal::assign_impl::run(*this,rhs.derived()); - #ifndef EIGEN_NO_DEBUG - this->checkTransposeAliasing(rhs.derived()); - #endif - return *this; - } - - // overloaded to honor evaluation of special matrices - // maybe another solution would be to not use SelfCwiseBinaryOp - // at first... - EIGEN_DEVICE_FUNC - SelfCwiseBinaryOp& operator=(const Rhs& _rhs) - { - typename internal::nested::type rhs(_rhs); - return Base::operator=(rhs); - } - - EIGEN_DEVICE_FUNC - Lhs& expression() const - { - return m_matrix; - } - - EIGEN_DEVICE_FUNC - const BinaryOp& functor() const - { - return m_functor; - } - - protected: - Lhs& m_matrix; - const BinaryOp& m_functor; - - private: - SelfCwiseBinaryOp& operator=(const SelfCwiseBinaryOp&); -}; - -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_TEST_EVALUATORS template inline Derived& DenseBase::operator*=(const Scalar& other) { @@ -215,43 +43,6 @@ inline Derived& DenseBase::operator/=(const Scalar& other) internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::div_assign_op()); return derived(); } -#else -template -inline Derived& DenseBase::operator*=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(),other); - return derived(); -} - -template -inline Derived& ArrayBase::operator+=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(),other); - return derived(); -} - -template -inline Derived& ArrayBase::operator-=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(),other); - return derived(); -} - -template -inline Derived& DenseBase::operator/=(const Scalar& other) -{ - typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - tmp = PlainObject::Constant(rows(),cols(), other); - return derived(); -} -#endif } // end namespace Eigen diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index a1501c259..7b12be1e6 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -99,7 +99,6 @@ private: Scalar coeff(Index i) const; }; -#ifdef EIGEN_TEST_EVALUATORS // Generic API dispatcher template class SolveImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type @@ -107,7 +106,6 @@ class SolveImpl : public internal::generic_xpr_base public: typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; }; -#endif namespace internal { diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 9a1c5f4f8..3277cb5ba 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -12,135 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS - -/** \class SwapWrapper - * \ingroup Core_Module - * - * \internal - * - * \brief Internal helper class for swapping two expressions - */ -namespace internal { -template -struct traits > : traits {}; -} - -template class SwapWrapper - : public internal::dense_xpr_base >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SwapWrapper) - typedef typename internal::packet_traits::type Packet; - - EIGEN_DEVICE_FUNC - inline SwapWrapper(ExpressionType& xpr) : m_expression(xpr) {} - - EIGEN_DEVICE_FUNC - inline Index rows() const { return m_expression.rows(); } - EIGEN_DEVICE_FUNC - inline Index cols() const { return m_expression.cols(); } - EIGEN_DEVICE_FUNC - inline Index outerStride() const { return m_expression.outerStride(); } - EIGEN_DEVICE_FUNC - inline Index innerStride() const { return m_expression.innerStride(); } - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - EIGEN_DEVICE_FUNC - inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } - EIGEN_DEVICE_FUNC - inline const Scalar* data() const { return m_expression.data(); } - - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index rowId, Index colId) const - { - return m_expression.coeffRef(rowId, colId); - } - - EIGEN_DEVICE_FUNC - inline Scalar& coeffRef(Index index) const - { - return m_expression.coeffRef(index); - } - - template - EIGEN_DEVICE_FUNC - void copyCoeff(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Scalar tmp = m_expression.coeff(rowId, colId); - m_expression.coeffRef(rowId, colId) = _other.coeff(rowId, colId); - _other.coeffRef(rowId, colId) = tmp; - } - - template - EIGEN_DEVICE_FUNC - void copyCoeff(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Scalar tmp = m_expression.coeff(index); - m_expression.coeffRef(index) = _other.coeff(index); - _other.coeffRef(index) = tmp; - } - - template - void copyPacket(Index rowId, Index colId, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(rowId >= 0 && rowId < rows() - && colId >= 0 && colId < cols()); - Packet tmp = m_expression.template packet(rowId, colId); - m_expression.template writePacket(rowId, colId, - _other.template packet(rowId, colId) - ); - _other.template writePacket(rowId, colId, tmp); - } - - template - void copyPacket(Index index, const DenseBase& other) - { - OtherDerived& _other = other.const_cast_derived(); - eigen_internal_assert(index >= 0 && index < m_expression.size()); - Packet tmp = m_expression.template packet(index); - m_expression.template writePacket(index, - _other.template packet(index) - ); - _other.template writePacket(index, tmp); - } - - EIGEN_DEVICE_FUNC - ExpressionType& expression() const { return m_expression; } - - protected: - ExpressionType& m_expression; -}; - -#endif - -#ifdef EIGEN_ENABLE_EVALUATORS - namespace internal { // Overload default assignPacket behavior for swapping them @@ -189,8 +60,6 @@ public: } // namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_SWAP_H diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index dd6180a8f..144bb2c01 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -42,18 +42,10 @@ struct traits > ColsAtCompileTime = MatrixType::RowsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime, -#ifndef EIGEN_TEST_EVALUATORS FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), Flags1 = Flags0 | FlagsLvalueBit, Flags = Flags1 ^ RowMajorBit, - CoeffReadCost = MatrixTypeNestedPlain::CoeffReadCost, -#else - FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags0 = MatrixTypeNestedPlain::Flags & ~(LvalueBit | NestByRefBit), - Flags1 = Flags0 | FlagsLvalueBit, - Flags = Flags1 ^ RowMajorBit, -#endif InnerStrideAtCompileTime = inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = outer_stride_at_compile_time::ret }; @@ -109,7 +101,6 @@ struct TransposeImpl_base } // end namespace internal -#ifdef EIGEN_TEST_EVALUATORS // Generic API dispatcher template class TransposeImpl @@ -118,7 +109,6 @@ class TransposeImpl public: typedef typename internal::generic_xpr_base >::type Base; }; -#endif template class TransposeImpl : public internal::TransposeImpl_base::type @@ -141,59 +131,6 @@ template class TransposeImpl inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } inline const Scalar* data() const { return derived().nestedExpression().data(); } - -#ifndef EIGEN_TEST_EVALUATORS - - EIGEN_DEVICE_FUNC - inline ScalarWithConstIfNotLvalue& coeffRef(Index rowId, Index colId) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return derived().nestedExpression().const_cast_derived().coeffRef(colId, rowId); - } - - EIGEN_DEVICE_FUNC - inline ScalarWithConstIfNotLvalue& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return derived().nestedExpression().const_cast_derived().coeffRef(index); - } - - EIGEN_DEVICE_FUNC - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return derived().nestedExpression().coeff(colId, rowId); - } - - EIGEN_DEVICE_FUNC - inline CoeffReturnType coeff(Index index) const - { - return derived().nestedExpression().coeff(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return derived().nestedExpression().template packet(colId, rowId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& x) - { - derived().nestedExpression().const_cast_derived().template writePacket(colId, rowId, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return derived().nestedExpression().template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - derived().nestedExpression().const_cast_derived().template writePacket(index, x); - } -#endif // FIXME: shall we keep the const version of coeffRef? EIGEN_DEVICE_FUNC @@ -446,14 +383,6 @@ void check_for_aliasing(const Dst &dst, const Src &src) } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS -template -template -void DenseBase::checkTransposeAliasing(const OtherDerived& other) const -{ - internal::checkTransposeAliasing_impl::run(derived(), other); -} -#endif // EIGEN_TEST_EVALUATORS #endif // EIGEN_NO_DEBUG } // end namespace Eigen diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index cc585bc6c..0d315dd50 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -32,9 +32,6 @@ template class TriangularBase : public EigenBase enum { Mode = internal::traits::Mode, -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = internal::traits::CoeffReadCost, -#endif RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, @@ -177,21 +174,10 @@ struct traits > : traits enum { Mode = _Mode, Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) -#ifndef EIGEN_TEST_EVALUATORS - , - CoeffReadCost = MatrixTypeNestedCleaned::CoeffReadCost -#endif }; }; } -#ifndef EIGEN_TEST_EVALUATORS -template -struct TriangularProduct; -#endif - template class TriangularViewImpl; template class TriangularView @@ -270,7 +256,6 @@ template class TriangularView return m_matrix.transpose(); } -#ifdef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC inline const Solve @@ -287,7 +272,6 @@ template class TriangularView #else using Base::solve; #endif -#endif // EIGEN_TEST_EVALUATORS EIGEN_DEVICE_FUNC const SelfAdjointView selfadjointView() const @@ -348,8 +332,6 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride(); } -#ifdef EIGEN_TEST_EVALUATORS - /** \sa MatrixBase::operator+=() */ template EIGEN_DEVICE_FUNC @@ -365,16 +347,6 @@ template class TriangularViewImpl<_Mat return derived(); } -#else - /** \sa MatrixBase::operator+=() */ - template - EIGEN_DEVICE_FUNC - TriangularViewType& operator+=(const DenseBase& other) { return *this = derived().nestedExpression() + other.derived(); } - /** \sa MatrixBase::operator-=() */ - template - EIGEN_DEVICE_FUNC - TriangularViewType& operator-=(const DenseBase& other) { return *this = derived().nestedExpression() - other.derived(); } -#endif /** \sa MatrixBase::operator*=() */ EIGEN_DEVICE_FUNC TriangularViewType& operator*=(const typename internal::traits::Scalar& other) { return *this = derived().nestedExpression() * other; } @@ -437,8 +409,6 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC void lazyAssign(const MatrixBase& other); -#ifdef EIGEN_TEST_EVALUATORS - /** Efficient triangular matrix times vector/matrix product */ template EIGEN_DEVICE_FUNC @@ -456,30 +426,6 @@ template class TriangularViewImpl<_Mat { return Product(lhs.derived(),rhs.derived()); } - -#else // EIGEN_TEST_EVALUATORS - /** Efficient triangular matrix times vector/matrix product */ - template - EIGEN_DEVICE_FUNC - TriangularProduct - operator*(const MatrixBase& rhs) const - { - return TriangularProduct - - (derived().nestedExpression(), rhs.derived()); - } - - /** Efficient vector/matrix times triangular matrix product */ - template friend - EIGEN_DEVICE_FUNC - TriangularProduct - operator*(const MatrixBase& lhs, const TriangularViewImpl& rhs) - { - return TriangularProduct - - (lhs.derived(),rhs.derived().nestedExpression()); - } -#endif template EIGEN_DEVICE_FUNC @@ -490,14 +436,6 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const; -#ifndef EIGEN_TEST_EVALUATORS - template - EIGEN_DEVICE_FUNC - inline const internal::triangular_solve_retval - solve(const MatrixBase& other) const - { return solve(other); } -#endif // EIGEN_TEST_EVALUATORS - template EIGEN_DEVICE_FUNC void solveInPlace(const MatrixBase& other) const @@ -507,11 +445,7 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC void swap(TriangularBase const & other) { - #ifdef EIGEN_TEST_EVALUATORS call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); - #else - TriangularView,Mode>(const_cast(derived().nestedExpression())).lazyAssign(other.const_cast_derived().nestedExpression()); - #endif } // TODO: this overload is ambiguous and it should be deprecated (Gael) @@ -519,65 +453,8 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC void swap(MatrixBase const & other) { - #ifdef EIGEN_TEST_EVALUATORS call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); - #else - SwapWrapper swaper(const_cast(derived().nestedExpression())); - TriangularView,Mode>(swaper).lazyAssign(other.derived()); - #endif - } - -#ifndef EIGEN_TEST_EVALUATORS - - // TODO simplify the following: - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator=(const ProductBase& other) - { - setZero(); - return assignProduct(other,1); - } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator+=(const ProductBase& other) - { - return assignProduct(other,1); } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator-=(const ProductBase& other) - { - return assignProduct(other,-1); - } - - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator=(const ScaledProduct& other) - { - setZero(); - return assignProduct(other,other.alpha()); - } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator+=(const ScaledProduct& other) - { - return assignProduct(other,other.alpha()); - } - - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& operator-=(const ScaledProduct& other) - { - return assignProduct(other,-other.alpha()); - } - -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC @@ -590,194 +467,12 @@ template class TriangularViewImpl<_Mat template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TriangularViewType& _assignProduct(const ProductType& prod, const Scalar& alpha); - - protected: -#else - protected: - template - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE TriangularViewType& assignProduct(const ProductBase& prod, const Scalar& alpha); -#endif }; /*************************************************************************** * Implementation of triangular evaluation/assignment ***************************************************************************/ -namespace internal { - -#ifndef EIGEN_TEST_EVALUATORS - -template -struct triangular_assignment_selector -{ - enum { - col = (UnrollCount-1) / Derived1::RowsAtCompileTime, - row = (UnrollCount-1) % Derived1::RowsAtCompileTime - }; - - typedef typename Derived1::Scalar Scalar; - - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - triangular_assignment_selector::run(dst, src); - - eigen_assert( Mode == Upper || Mode == Lower - || Mode == StrictlyUpper || Mode == StrictlyLower - || Mode == UnitUpper || Mode == UnitLower); - if((Mode == Upper && row <= col) - || (Mode == Lower && row >= col) - || (Mode == StrictlyUpper && row < col) - || (Mode == StrictlyLower && row > col) - || (Mode == UnitUpper && row < col) - || (Mode == UnitLower && row > col)) - dst.copyCoeff(row, col, src); - else if(ClearOpposite) - { - if (Mode&UnitDiag && row==col) - dst.coeffRef(row, col) = Scalar(1); - else - dst.coeffRef(row, col) = Scalar(0); - } - } -}; - -// prevent buggy user code from causing an infinite recursion -template -struct triangular_assignment_selector -{ - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &, const Derived2 &) {} -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()-1); - for(Index i = 0; i <= maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()); - if (ClearOpposite) - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - typedef typename Derived1::Scalar Scalar; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - for(Index i = maxi; i < dst.rows(); ++i) - dst.coeffRef(i, j) = Scalar(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - for(Index i = j+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - Index maxi = (std::min)(j, dst.rows()-1); - if (ClearOpposite) - for(Index i = 0; i <= maxi; ++i) - dst.coeffRef(i, j) = static_cast(0); - } - } -}; - -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = 0; i < maxi; ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; -template -struct triangular_assignment_selector -{ - typedef typename Derived1::Index Index; - EIGEN_DEVICE_FUNC - static inline void run(Derived1 &dst, const Derived2 &src) - { - for(Index j = 0; j < dst.cols(); ++j) - { - Index maxi = (std::min)(j, dst.rows()); - for(Index i = maxi+1; i < dst.rows(); ++i) - dst.copyCoeff(i, j, src); - if (ClearOpposite) - { - for(Index i = 0; i < maxi; ++i) - dst.coeffRef(i, j) = 0; - } - } - dst.diagonal().setOnes(); - } -}; - -#endif // EIGEN_TEST_EVALUATORS - -} // end namespace internal - -#ifdef EIGEN_TEST_EVALUATORS - // FIXME should we keep that possibility template template @@ -816,84 +511,6 @@ void TriangularViewImpl::lazyAssign(const TriangularBas internal::call_assignment(derived().noalias(), other.derived()); } -#else - -// FIXME should we keep that possibility -template -template -inline TriangularView& -TriangularViewImpl::operator=(const MatrixBase& other) -{ - if(OtherDerived::Flags & EvalBeforeAssigningBit) - { - typename internal::plain_matrix_type::type other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived()); - return derived(); -} - -// FIXME should we keep that possibility -template -template -void TriangularViewImpl::lazyAssign(const MatrixBase& other) -{ - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime*internal::traits::CoeffReadCost/2 <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(derived().rows() == other.rows() && derived().cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(derived().nestedExpression().const_cast_derived(), other.derived()); -} - - - -template -template -inline TriangularView& -TriangularViewImpl::operator=(const TriangularBase& other) -{ - eigen_assert(Mode == int(OtherDerived::Mode)); - if(internal::traits::Flags & EvalBeforeAssigningBit) - { - typename OtherDerived::DenseMatrixType other_evaluated(other.rows(), other.cols()); - other_evaluated.template triangularView().lazyAssign(other.derived().nestedExpression()); - lazyAssign(other_evaluated); - } - else - lazyAssign(other.derived().nestedExpression()); - return derived(); -} - -template -template -void TriangularViewImpl::lazyAssign(const TriangularBase& other) -{ - enum { - unroll = MatrixType::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && MatrixType::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - eigen_assert(derived().rows() == other.rows() && derived().cols() == other.cols()); - - internal::triangular_assignment_selector - ::run(derived().nestedExpression().const_cast_derived(), other.derived().nestedExpression()); -} - -#endif // EIGEN_TEST_EVALUATORS - /*************************************************************************** * Implementation of TriangularBase methods ***************************************************************************/ @@ -914,31 +531,6 @@ void TriangularBase::evalTo(MatrixBase &other) const evalToLazy(other.derived()); } -#ifndef EIGEN_TEST_EVALUATORS - -/** Assigns a triangular or selfadjoint matrix to a dense matrix. - * If the matrix is triangular, the opposite part is set to zero. */ -template -template -void TriangularBase::evalToLazy(MatrixBase &other) const -{ - enum { - unroll = DenseDerived::SizeAtCompileTime != Dynamic - && internal::traits::CoeffReadCost != Dynamic - && DenseDerived::SizeAtCompileTime * internal::traits::CoeffReadCost / 2 - <= EIGEN_UNROLLING_LIMIT - }; - other.derived().resize(this->rows(), this->cols()); - - internal::triangular_assignment_selector - ::MatrixTypeNestedCleaned, Derived::Mode, - unroll ? int(DenseDerived::SizeAtCompileTime) : Dynamic, - true // clear the opposite triangular part - >::run(other.derived(), derived().nestedExpression()); -} - -#endif // EIGEN_TEST_EVALUATORS - /*************************************************************************** * Implementation of TriangularView methods ***************************************************************************/ @@ -1028,8 +620,6 @@ bool MatrixBase::isLowerTriangular(const RealScalar& prec) const } -#ifdef EIGEN_ENABLE_EVALUATORS - /*************************************************************************** **************************************************************************** * Evaluators and Assignment of triangular expressions @@ -1268,7 +858,6 @@ struct triangular_assignment_loop } // end namespace internal -#ifdef EIGEN_TEST_EVALUATORS /** Assigns a triangular or selfadjoint matrix to a dense matrix. * If the matrix is triangular, the opposite part is set to zero. */ template @@ -1315,11 +904,7 @@ struct Assignment, internal::sub_ass } }; - } // end namespace internal -#endif - -#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index 1a9eead43..a8130e902 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -48,25 +48,9 @@ struct traits > ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::MaxColsAtCompileTime, -#ifndef EIGEN_TEST_EVALUATORS - Flags0 = (unsigned int)_MatrixTypeNested::Flags & HereditaryBits, - Flags = (Flags0 & ~RowMajorBit) | (RowsAtCompileTime == 1 ? RowMajorBit : 0), -#else Flags = RowsAtCompileTime == 1 ? RowMajorBit : 0, -#endif TraversalSize = Direction==Vertical ? MatrixType::RowsAtCompileTime : MatrixType::ColsAtCompileTime }; -#ifndef EIGEN_TEST_EVALUATORS - #if EIGEN_GNUC_AT_LEAST(3,4) - typedef typename MemberOp::template Cost CostOpType; - #else - typedef typename MemberOp::template Cost CostOpType; - #endif - enum { - CoeffReadCost = TraversalSize==Dynamic ? Dynamic - : TraversalSize * traits<_MatrixTypeNested>::CoeffReadCost + int(CostOpType::value) - }; -#endif }; } diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h index 76d452d9a..810ec28e7 100644 --- a/Eigen/src/Core/Visitor.h +++ b/Eigen/src/Core/Visitor.h @@ -53,7 +53,6 @@ struct visitor_impl } }; -#ifdef EIGEN_ENABLE_EVALUATORS // evaluator adaptor template class visitor_evaluator @@ -81,7 +80,6 @@ protected: typename internal::evaluator::nestedType m_evaluator; const XprType &m_xpr; }; -#endif } // end namespace internal /** Applies the visitor \a visitor to the whole coefficients of the matrix or vector. @@ -105,7 +103,6 @@ template template void DenseBase::visit(Visitor& visitor) const { -#ifdef EIGEN_TEST_EVALUATORS typedef typename internal::visitor_evaluator ThisEvaluator; ThisEvaluator thisEval(derived()); @@ -117,16 +114,6 @@ void DenseBase::visit(Visitor& visitor) const return internal::visitor_impl::run(thisEval, visitor); -#else - enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && (SizeAtCompileTime == 1 || internal::functor_traits::Cost != Dynamic) - && SizeAtCompileTime * CoeffReadCost + (SizeAtCompileTime-1) * internal::functor_traits::Cost - <= EIGEN_UNROLLING_LIMIT }; - return internal::visitor_impl::run(derived(), visitor); -#endif } namespace internal { diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h deleted file mode 100644 index 76806fd62..000000000 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ /dev/null @@ -1,460 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_COEFFBASED_PRODUCT_H -#define EIGEN_COEFFBASED_PRODUCT_H - -namespace Eigen { - -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -/********************************************************************************* -* 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 - * on the generic Assign mechanism to evaluate the product per coeff (or packet). - * - * Note that here the inner-loops should always be unrolled. - */ - -template -struct product_coeff_impl; - -template -struct product_packet_impl; - -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename product_promote_storage_type::StorageKind, - typename traits<_RhsNested>::StorageKind, - 0>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsFlags = traits<_LhsNested>::Flags, - RhsFlags = traits<_RhsNested>::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - LhsRowMajor = LhsFlags & RowMajorBit, - RhsRowMajor = RhsFlags & RowMajorBit, - - SameType = is_same::value, - - CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit) - && (ColsAtCompileTime == Dynamic - || ( (ColsAtCompileTime % packet_traits::size) == 0 - && (RhsFlags&AlignedBit) - ) - ), - - CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) - && (RowsAtCompileTime == Dynamic - || ( (RowsAtCompileTime % packet_traits::size) == 0 - && (LhsFlags&AlignedBit) - ) - ), - - EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 - : (RhsRowMajor && !CanVectorizeLhs), - - Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) - | (EvalToRowMajor ? RowMajorBit : 0) - | NestingFlags - | (CanVectorizeLhs ? (LhsFlags & AlignedBit) : 0) - | (CanVectorizeRhs ? (RhsFlags & AlignedBit) : 0) - // TODO enable vectorization for mixed types - | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), -#ifndef EIGEN_TEST_EVALUATORS - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, - CoeffReadCost = (InnerSize == Dynamic || LhsCoeffReadCost==Dynamic || RhsCoeffReadCost==Dynamic || NumTraits::AddCost==Dynamic || NumTraits::MulCost==Dynamic) ? Dynamic - : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) - + (InnerSize - 1) * NumTraits::AddCost, -#endif - /* 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 - * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect - * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. - */ - CanVectorizeInner = SameType - && LhsRowMajor - && (!RhsRowMajor) - && (LhsFlags & RhsFlags & ActualPacketAccessBit) - && (LhsFlags & RhsFlags & AlignedBit) - && (InnerSize % packet_traits::size == 0) - }; -}; - -} // end namespace internal - -#ifndef EIGEN_TEST_EVALUATORS - -template -class CoeffBasedProduct - : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct) - typedef typename Base::PlainObject PlainObject; - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - enum { - PacketSize = internal::packet_traits::size, - InnerSize = internal::traits::InnerSize, - Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT, - CanVectorizeInner = internal::traits::CanVectorizeInner - }; - - typedef internal::product_coeff_impl ScalarCoeffImpl; - - typedef CoeffBasedProduct LazyCoeffBasedProductType; - - public: - - EIGEN_DEVICE_FUNC - inline CoeffBasedProduct(const CoeffBasedProduct& other) - : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs) - {} - - template - EIGEN_DEVICE_FUNC - 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. - // We still allow to mix T and complex. - EIGEN_STATIC_ASSERT((internal::scalar_product_traits::Defined), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(lhs.cols() == rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - Scalar res; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, - * which is why we don't set the LinearAccessBit. - */ - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - Scalar res; - const Index row = RowsAtCompileTime == 1 ? 0 : index; - const Index col = RowsAtCompileTime == 1 ? index : 0; - ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res); - return res; - } - - template - EIGEN_STRONG_INLINE const PacketScalar packet(Index row, Index col) const - { - PacketScalar res; - internal::product_packet_impl - ::run(row, col, m_lhs, m_rhs, res); - return res; - } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE operator const PlainObject& () const - { - m_result.lazyAssign(*this); - return m_result; - } - - EIGEN_DEVICE_FUNC const _LhsNested& lhs() const { return m_lhs; } - EIGEN_DEVICE_FUNC const _RhsNested& rhs() const { return m_rhs; } - - EIGEN_DEVICE_FUNC - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - template - EIGEN_DEVICE_FUNC - const Diagonal diagonal() const - { return reinterpret_cast(*this); } - - EIGEN_DEVICE_FUNC - const Diagonal diagonal(Index index) const - { return reinterpret_cast(*this).diagonal(index); } - - protected: - typename internal::add_const_on_value_type::type m_lhs; - typename internal::add_const_on_value_type::type m_rhs; - - mutable PlainObject m_result; -}; - -namespace internal { - -// 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 nested, N, PlainObject> -{ - typedef PlainObject const& type; -}; - -/*************************************************************************** -* Normal product .coeff() implementation (with meta-unrolling) -***************************************************************************/ - -/************************************** -*** Scalar path - no vectorization *** -**************************************/ - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - product_coeff_impl::run(row, col, lhs, rhs, res); - res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - EIGEN_DEVICE_FUNC - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - for(Index i = 1; i < lhs.cols(); ++i) - res += lhs.coeff(row, i) * rhs.coeff(i, col); - } -}; - -/******************************************* -*** Scalar path with inner vectorization *** -*******************************************/ - -template -struct product_coeff_vectorized_unroller -{ - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) - { - product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); - pres = padd(pres, pmul( lhs.template packet(row, UnrollingIndex) , rhs.template packet(UnrollingIndex, col) )); - } -}; - -template -struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres) - { - pres = pmul(lhs.template packet(row, 0) , rhs.template packet(0, col)); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::PacketScalar Packet; - typedef typename Lhs::Index Index; - enum { PacketSize = packet_traits::size }; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) - { - Packet pres; - product_coeff_vectorized_unroller::run(row, col, lhs, rhs, pres); - res = predux(pres); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -// NOTE the 3 following specializations are because taking .col(0) on a vector is a bit slower -// NOTE maybe they are now useless since we have a specialization for Block -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs.col(col)).sum(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.row(row).transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct product_coeff_vectorized_dyn_selector -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - res = lhs.transpose().cwiseProduct(rhs).sum(); - } -}; - -template -struct product_coeff_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) - { - product_coeff_vectorized_dyn_selector::run(row, col, lhs, rhs, res); - } -}; - -/******************* -*** Packet path *** -*******************/ - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(pset1(lhs.coeff(row, UnrollingIndex)), rhs.template packet(UnrollingIndex, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - product_packet_impl::run(row, col, lhs, rhs, res); - res = pmadd(lhs.template packet(row, UnrollingIndex), pset1(rhs.coeff(UnrollingIndex, col)), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) - { - res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(pset1(lhs.coeff(row, 0)),rhs.template packet(0, col)); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); - } -}; - -template -struct product_packet_impl -{ - typedef typename Lhs::Index Index; - static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) - { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(lhs.template packet(row, 0), pset1(rhs.coeff(0, col))); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); - } -}; - -} // end namespace internal - -#endif // EIGEN_TEST_EVALUATORS - -#endif // -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - enum { - MaxDepthAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(Lhs::MaxColsAtCompileTime,Rhs::MaxRowsAtCompileTime) - }; - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - typedef Scalar ResScalar; - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - typedef internal::scalar_product_op BinOp; - EIGEN_CHECK_BINARY_COMPATIBILIY(BinOp,LhsScalar,RhsScalar); - } - - template - inline void evalTo(Dest& dst) const - { - if((m_rhs.rows()+dst.rows()+dst.cols())<20 && m_rhs.rows()>0) - dst.noalias() = m_lhs .lazyProduct( m_rhs ); - else - { - dst.setZero(); - scaleAndAddTo(dst,Scalar(1)); - } - } - - template - inline void addTo(Dest& dst) const - { - if((m_rhs.rows()+dst.rows()+dst.cols())<20 && m_rhs.rows()>0) - dst.noalias() += m_lhs .lazyProduct( m_rhs ); - else - scaleAndAddTo(dst,Scalar(1)); - } - - template - inline void subTo(Dest& dst) const - { - if((m_rhs.rows()+dst.rows()+dst.cols())<20 && m_rhs.rows()>0) - dst.noalias() -= m_lhs .lazyProduct( m_rhs ); - else - scaleAndAddTo(dst,Scalar(-1)); - } - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); - - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); - - typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,LhsScalar,RhsScalar, - Dest::MaxRowsAtCompileTime,Dest::MaxColsAtCompileTime,MaxDepthAtCompileTime> BlockingType; - - typedef internal::gemm_functor< - Scalar, Index, - internal::general_matrix_matrix_product< - Index, - LhsScalar, (_ActualLhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(LhsBlasTraits::NeedToConjugate), - RhsScalar, (_ActualRhsType::Flags&RowMajorBit) ? RowMajor : ColMajor, bool(RhsBlasTraits::NeedToConjugate), - (Dest::Flags&RowMajorBit) ? RowMajor : ColMajor>, - _ActualLhsType, _ActualRhsType, Dest, BlockingType> GemmFunctor; - - BlockingType blocking(dst.rows(), dst.cols(), lhs.cols(), true); - - internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>(GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), this->rows(), this->cols(), Dest::Flags&RowMajorBit); - } -}; -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -534,7 +453,6 @@ struct generic_product_impl }; } // end namespace internal -#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 06c64714a..7db3e3d38 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h @@ -261,7 +261,6 @@ struct general_product_to_triangular_selector } }; -#ifdef EIGEN_TEST_EVALUATORS template template TriangularView& TriangularViewImpl::_assignProduct(const ProductType& prod, const Scalar& alpha) @@ -272,19 +271,7 @@ TriangularView& TriangularViewImpl::_ass return derived(); } -#else -template -template -TriangularView& TriangularViewImpl::assignProduct(const ProductBase& prod, const Scalar& alpha) -{ - eigen_assert(derived().rows() == prod.rows() && derived().cols() == prod.cols()); - general_product_to_triangular_selector - ::run(derived().nestedExpression().const_cast_derived(), prod.derived(), alpha); - - return derived(); -} -#endif } // end namespace Eigen #endif // EIGEN_GENERAL_MATRIX_MATRIX_TRIANGULAR_H diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h index 0ab3f3a56..4e507b6cf 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h @@ -459,58 +459,6 @@ EIGEN_DONT_INLINE void product_selfadjoint_matrix -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - enum { - LhsIsUpper = (LhsMode&(Upper|Lower))==Upper, - LhsIsSelfAdjoint = (LhsMode&SelfAdjoint)==SelfAdjoint, - RhsIsUpper = (RhsMode&(Upper|Lower))==Upper, - RhsIsSelfAdjoint = (RhsMode&SelfAdjoint)==SelfAdjoint - }; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); - - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); - - internal::product_selfadjoint_matrix::Flags &RowMajorBit) ? RowMajor : ColMajor, LhsIsSelfAdjoint, - NumTraits::IsComplex && EIGEN_LOGICAL_XOR(LhsIsUpper,bool(LhsBlasTraits::NeedToConjugate)), - EIGEN_LOGICAL_XOR(RhsIsUpper, - internal::traits::Flags &RowMajorBit) ? RowMajor : ColMajor, RhsIsSelfAdjoint, - NumTraits::IsComplex && EIGEN_LOGICAL_XOR(RhsIsUpper,bool(RhsBlasTraits::NeedToConjugate)), - internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor> - ::run( - lhs.rows(), rhs.cols(), // sizes - &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info - &dst.coeffRef(0,0), dst.outerStride(), // result info - actualAlpha // alpha - ); - } -}; -#endif // EIGEN_TEST_EVALUATORS -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -560,8 +508,6 @@ struct selfadjoint_product_impl } // end namespace internal -#endif // EIGEN_ENABLE_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_MATRIX_H diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index 020205c12..d9c041f0c 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -168,117 +168,6 @@ EIGEN_DONT_INLINE void selfadjoint_matrix_vector_product -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) - - enum { - LhsUpLo = LhsMode&(Upper|Lower) - }; - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - typedef typename Dest::Scalar ResScalar; - typedef typename Base::RhsScalar RhsScalar; - typedef Map, Aligned> MappedDest; - - eigen_assert(dest.rows()==m_lhs.rows() && dest.cols()==m_rhs.cols()); - - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); - - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); - - enum { - EvalToDest = (Dest::InnerStrideAtCompileTime==1), - UseRhs = (_ActualRhsType::InnerStrideAtCompileTime==1) - }; - - internal::gemv_static_vector_if static_dest; - internal::gemv_static_vector_if static_rhs; - - ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), - EvalToDest ? dest.data() : static_dest.data()); - - ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,rhs.size(), - UseRhs ? const_cast(rhs.data()) : static_rhs.data()); - - if(!EvalToDest) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - Index size = dest.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - MappedDest(actualDestPtr, dest.size()) = dest; - } - - if(!UseRhs) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - Index size = rhs.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - Map(actualRhsPtr, rhs.size()) = rhs; - } - - - internal::selfadjoint_matrix_vector_product::Flags&RowMajorBit) ? RowMajor : ColMajor, int(LhsUpLo), bool(LhsBlasTraits::NeedToConjugate), bool(RhsBlasTraits::NeedToConjugate)>::run - ( - lhs.rows(), // size - &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - actualRhsPtr, 1, // rhs info - actualDestPtr, // result info - actualAlpha // scale factor - ); - - if(!EvalToDest) - dest = MappedDest(actualDestPtr, dest.size()); - } -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -struct SelfadjointProductMatrix - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(SelfadjointProductMatrix) - - enum { - RhsUpLo = RhsMode&(Upper|Lower) - }; - - SelfadjointProductMatrix(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - // let's simply transpose the product - Transpose destT(dest); - SelfadjointProductMatrix, int(RhsUpLo)==Upper ? Lower : Upper, false, - Transpose, 0, true>(m_rhs.transpose(), m_lhs.transpose()).scaleAndAddTo(destT, alpha); - } -}; - -#else // EIGEN_TEST_EVALUATORS - namespace internal { template @@ -378,8 +267,6 @@ struct selfadjoint_product_impl } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SELFADJOINT_MATRIX_VECTOR_H diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix.h b/Eigen/src/Core/products/TriangularMatrixMatrix.h index fda6e2486..c2d0817ea 100644 --- a/Eigen/src/Core/products/TriangularMatrixMatrix.h +++ b/Eigen/src/Core/products/TriangularMatrixMatrix.h @@ -368,59 +368,9 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix -struct traits > - : traits, Lhs, Rhs> > -{}; -#endif } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS -template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - typename internal::add_const_on_value_type::type lhs = LhsBlasTraits::extract(m_lhs); - typename internal::add_const_on_value_type::type rhs = RhsBlasTraits::extract(m_rhs); - - Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(m_lhs) - * RhsBlasTraits::extractScalarFactor(m_rhs); - - typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar, - Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType; - - enum { IsLower = (Mode&Lower) == Lower }; - Index stripedRows = ((!LhsIsTriangular) || (IsLower)) ? lhs.rows() : (std::min)(lhs.rows(),lhs.cols()); - Index stripedCols = ((LhsIsTriangular) || (!IsLower)) ? rhs.cols() : (std::min)(rhs.cols(),rhs.rows()); - Index stripedDepth = LhsIsTriangular ? ((!IsLower) ? lhs.cols() : (std::min)(lhs.cols(),lhs.rows())) - : ((IsLower) ? rhs.rows() : (std::min)(rhs.rows(),rhs.cols())); - - BlockingType blocking(stripedRows, stripedCols, stripedDepth); - - internal::product_triangular_matrix_matrix::Flags&RowMajorBit) ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate, - (internal::traits<_ActualRhsType>::Flags&RowMajorBit) ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate, - (internal::traits::Flags&RowMajorBit) ? RowMajor : ColMajor> - ::run( - stripedRows, stripedCols, stripedDepth, // sizes - &lhs.coeffRef(0,0), lhs.outerStride(), // lhs info - &rhs.coeffRef(0,0), rhs.outerStride(), // rhs info - &dst.coeffRef(0,0), dst.outerStride(), // result info - actualAlpha, blocking - ); - } -}; -#endif // EIGEN_TEST_EVALUATORS -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template struct triangular_product_impl @@ -470,7 +420,6 @@ struct triangular_product_impl }; } // end namespace internal -#endif // EIGEN_ENABLE_EVALUATORS } // end namespace Eigen diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index 19167c232..92d64e384 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h @@ -157,61 +157,11 @@ EIGEN_DONT_INLINE void triangular_matrix_vector_product -struct traits > - : traits, Lhs, Rhs> > -{}; - -template -struct traits > - : traits, Lhs, Rhs> > -{}; -#endif - template struct trmv_selector; } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS -template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - - internal::trmv_selector::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(m_lhs, m_rhs, dst, alpha); - } -}; - -template -struct TriangularProduct - : public ProductBase, Lhs, Rhs > -{ - EIGEN_PRODUCT_PUBLIC_INTERFACE(TriangularProduct) - - TriangularProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) {} - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(dst.rows()==m_lhs.rows() && dst.cols()==m_rhs.cols()); - - Transpose dstT(dst); - internal::trmv_selector<(Mode & (UnitDiag|ZeroDiag)) | ((Mode & Lower) ? Upper : Lower), - (int(internal::traits::Flags)&RowMajorBit) ? ColMajor : RowMajor> - ::run(m_rhs.transpose(),m_lhs.transpose(), dstT, alpha); - } -}; - -#else // EIGEN_TEST_EVALUATORS namespace internal { template @@ -240,7 +190,6 @@ struct triangular_product_impl }; } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS namespace internal { diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 99aa9b372..9ec57468b 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -139,10 +139,6 @@ template class ArrayWrapper; template class MatrixWrapper; namespace internal { -#ifndef EIGEN_TEST_EVALUATROS -template struct solve_retval_base; -template struct solve_retval; -#endif template struct kernel_retval_base; template struct kernel_retval; template struct image_retval_base; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index e8ac6bee7..f9b908e22 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -374,46 +374,6 @@ namespace Eigen { * documentation in a single line. **/ -#ifndef EIGEN_TEST_EVALUATORS - -#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ - typedef typename Eigen::internal::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::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - - -#define EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Eigen::internal::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::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - MaxRowsAtCompileTime = Eigen::internal::traits::MaxRowsAtCompileTime, \ - MaxColsAtCompileTime = Eigen::internal::traits::MaxColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ - using Base::const_cast_derived; - -#else - // TODO The EIGEN_DENSE_PUBLIC_INTERFACE should not exists anymore #define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ @@ -450,8 +410,6 @@ namespace Eigen { using Base::derived; \ using Base::const_cast_derived; -#endif // EIGEN_TEST_EVALUATORS - #define EIGEN_PLAIN_ENUM_MIN(a,b) (((int)a <= (int)b) ? (int)a : (int)b) #define EIGEN_PLAIN_ENUM_MAX(a,b) (((int)a >= (int)b) ? (int)a : (int)b) diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index bce009d16..f2536714e 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -125,43 +125,6 @@ template type; }; -#ifndef EIGEN_TEST_EVALUATORS -template -class compute_matrix_flags -{ - enum { - row_major_bit = Options&RowMajor ? RowMajorBit : 0, - is_dynamic_size_storage = MaxRows==Dynamic || MaxCols==Dynamic, - - aligned_bit = - ( - ((Options&DontAlign)==0) - && ( -#if EIGEN_ALIGN_STATICALLY - ((!is_dynamic_size_storage) && (((MaxCols*MaxRows*int(sizeof(Scalar))) % EIGEN_ALIGN_BYTES) == 0)) -#else - 0 -#endif - - || - -#if EIGEN_ALIGN - is_dynamic_size_storage -#else - 0 -#endif - - ) - ) ? AlignedBit : 0, - packet_access_bit = packet_traits::Vectorizable && aligned_bit ? PacketAccessBit : 0 - }; - - public: - enum { ret = LinearAccessBit | LvalueBit | DirectAccessBit | NestByRefBit | packet_access_bit | row_major_bit | aligned_bit }; -}; - -#else // EIGEN_TEST_EVALUATORS - template class compute_matrix_flags { @@ -172,9 +135,7 @@ class compute_matrix_flags // However, I (Gael) think that DirectAccessBit should only matter at the evaluation stage. enum { ret = DirectAccessBit | LvalueBit | NestByRefBit | row_major_bit }; }; -#endif -#ifdef EIGEN_ENABLE_EVALUATORS template class compute_matrix_evaluator_flags { @@ -209,8 +170,6 @@ class compute_matrix_evaluator_flags enum { ret = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit | aligned_bit }; }; -#endif // EIGEN_ENABLE_EVALUATORS - template struct size_at_compile_time { enum { ret = (_Rows==Dynamic || _Cols==Dynamic) ? Dynamic : _Rows * _Cols }; @@ -361,58 +320,6 @@ struct transfer_constness }; - -#ifndef EIGEN_TEST_EVALUATORS - -/** \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 - * evaluating that expression b+c into a temporary variable d, and nest d so that the resulting expression is - * a*d. Evaluating can be beneficial for example if every coefficient access in the resulting expression causes - * many coefficient accesses in the nested expressions -- as is the case with matrix product for example. - * - * \param T the type of the expression being nested - * \param n the number of coefficient accesses in the nested expression for each coefficient access in the bigger expression. - * - * Note that if no evaluation occur, then the constness of T is preserved. - * - * Example. Suppose that a, b, and c are of type Matrix3d. The user forms the expression a*(b+c). - * b+c is an expression "sum of matrices", which we will denote by S. In order to determine how to nest it, - * the Product expression uses: nested::type, which turns out to be Matrix3d because the internal logic of - * nested determined that in this case it was better to evaluate the expression b+c into a temporary. On the other hand, - * since a is of type Matrix3d, the Product expression nests it as nested::type, which turns out to be - * const Matrix3d&, because the internal logic of nested determined that since a was already a matrix, there was no point - * in copying it into another matrix. - */ -template::type> struct nested -{ - enum { - // for the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values. - // the choice of 10000 makes it larger than any practical fixed value and even most dynamic values. - // in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues - // (poor choice of temporaries). - // it's important that this value can still be squared without integer overflowing. - DynamicAsInteger = 10000, - ScalarReadCost = NumTraits::Scalar>::ReadCost, - ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost), - CoeffReadCost = traits::CoeffReadCost, - CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost), - NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n, - CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger, - CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger - }; - - typedef typename conditional< - ( (int(traits::Flags) & EvalBeforeNestingBit) || - int(CostEvalAsInteger) < int(CostNoEvalAsInteger) - ), - PlainObject, - typename ref_selector::type - >::type type; -}; - -#else - // When using evaluators, we never evaluate when assembling the expression!! // TODO: get rid of this nested class since it's just an alias for ref_selector. template struct nested @@ -420,12 +327,20 @@ template struct nested typedef typename ref_selector::type type; }; -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_ENABLE_EVALUATORS // However, we still need a mechanism to detect whether an expression which is evaluated multiple time // has to be evaluated into a temporary. -// That's the purpose of this new nested_eval helper: +// That's the purpose of this new nested_eval helper: +/** \internal Determines how a given expression should be nested when evaluated multiple times. + * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be + * evaluated into the bigger product expression. The choice is between nesting the expression b+c as-is, or + * evaluating that expression b+c into a temporary variable d, and nest d so that the resulting expression is + * a*d. Evaluating can be beneficial for example if every coefficient access in the resulting expression causes + * many coefficient accesses in the nested expressions -- as is the case with matrix product for example. + * + * \param T the type of the expression being nested. + * \param n the number of coefficient accesses in the nested expression for each coefficient access in the bigger expression. + * \param PlainObject the type of the temporary if needed. + */ template::type> struct nested_eval { enum { @@ -453,7 +368,6 @@ template::type> struc typename ref_selector::type >::type type; }; -#endif template EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index 1d1daaa61..d6c5c1293 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -71,11 +71,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) template inline explicit AlignedBox(const MatrixBase& a_p) { -#ifndef EIGEN_TEST_EVALUATORS - typename internal::nested::type p(a_p.derived()); -#else typename internal::nested_eval::type p(a_p.derived()); -#endif m_min = p; m_max = p; } diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 43314b04c..d1881d84d 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -49,9 +49,6 @@ struct traits > Flags = ColsAtCompileTime==1 ? (TmpFlags & ~RowMajorBit) : RowsAtCompileTime==1 ? (TmpFlags | RowMajorBit) : TmpFlags -#ifndef EIGEN_TEST_EVALUATORS - , CoeffReadCost = _MatrixTypeNested::CoeffReadCost -#endif // EIGEN_TEST_EVALUATORS }; }; @@ -80,39 +77,6 @@ template class Homogeneous const NestedExpression& nestedExpression() const { return m_matrix; } -#ifndef EIGEN_TEST_EVALUATORS - inline Scalar coeff(Index row, Index col) const - { - if( (int(Direction)==Vertical && row==m_matrix.rows()) - || (int(Direction)==Horizontal && col==m_matrix.cols())) - return 1; - return m_matrix.coeff(row, col); - } - - template - inline const internal::homogeneous_right_product_impl - operator* (const MatrixBase& rhs) const - { - eigen_assert(int(Direction)==Horizontal); - return internal::homogeneous_right_product_impl(m_matrix,rhs.derived()); - } - - template friend - inline const internal::homogeneous_left_product_impl - operator* (const MatrixBase& lhs, const Homogeneous& rhs) - { - eigen_assert(int(Direction)==Vertical); - return internal::homogeneous_left_product_impl(lhs.derived(),rhs.m_matrix); - } - - template friend - inline const internal::homogeneous_left_product_impl > - operator* (const Transform& lhs, const Homogeneous& rhs) - { - eigen_assert(int(Direction)==Vertical); - return internal::homogeneous_left_product_impl >(lhs,rhs.m_matrix); - } -#else template inline const Product operator* (const MatrixBase& rhs) const @@ -136,7 +100,6 @@ template class Homogeneous eigen_assert(int(Direction)==Vertical); return Product, Homogeneous>(lhs,rhs); } -#endif template EIGEN_STRONG_INLINE typename internal::result_of::type @@ -338,8 +301,6 @@ struct homogeneous_right_product_impl,Rhs> typename Rhs::Nested m_rhs; }; -#ifdef EIGEN_TEST_EVALUATORS - template struct evaluator_traits > { @@ -427,8 +388,6 @@ struct generic_product_impl, Homogeneous::cross(const MatrixBase& other) const // Note that there is no need for an expression here since the compiler // optimize such a small temporary very well (even within a complex expression) -#ifndef EIGEN_TEST_EVALUATORS - typename internal::nested::type lhs(derived()); - typename internal::nested::type rhs(other.derived()); -#else typename internal::nested_eval::type lhs(derived()); typename internal::nested_eval::type rhs(other.derived()); -#endif return typename cross_product_return_type::type( numext::conj(lhs.coeff(1) * rhs.coeff(2) - lhs.coeff(2) * rhs.coeff(1)), numext::conj(lhs.coeff(2) * rhs.coeff(0) - lhs.coeff(0) * rhs.coeff(2)), @@ -81,13 +76,8 @@ MatrixBase::cross3(const MatrixBase& other) const EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived,4) EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,4) -#ifndef EIGEN_TEST_EVALUATORS - typedef typename internal::nested::type DerivedNested; - typedef typename internal::nested::type OtherDerivedNested; -#else typedef typename internal::nested_eval::type DerivedNested; typedef typename internal::nested_eval::type OtherDerivedNested; -#endif DerivedNested lhs(derived()); OtherDerivedNested rhs(other.derived()); @@ -114,13 +104,8 @@ VectorwiseOp::cross(const MatrixBase& ot EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) -#ifndef EIGEN_TEST_EVALUATORS - typename internal::nested::type mat(_expression()); - typename internal::nested::type vec(other.derived()); -#else typename internal::nested_eval::type mat(_expression()); typename internal::nested_eval::type vec(other.derived()); -#endif CrossReturnType res(_expression().rows(),_expression().cols()); if(Direction==Vertical) diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 850940302..3f0067286 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -217,11 +217,7 @@ struct traits > typedef _Scalar Scalar; typedef Matrix<_Scalar,4,1,_Options> Coefficients; enum{ -#ifndef EIGEN_TEST_EVALUATORS - IsAligned = internal::traits::Flags & AlignedBit, -#else IsAligned = (internal::traits::EvaluatorFlags & AlignedBit) != 0, -#endif Flags = IsAligned ? (AlignedBit | LvalueBit) : LvalueBit }; }; diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index bcf3e2723..89e9cc1a4 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -62,7 +62,6 @@ struct transform_construct_from_matrix; template struct transform_take_affine_part; -#ifdef EIGEN_TEST_EVALUATORS template struct traits > { @@ -78,7 +77,6 @@ struct traits > Flags = 0 }; }; -#endif } // end namespace internal @@ -374,10 +372,8 @@ public: inline QTransform toQTransform(void) const; #endif -#ifdef EIGEN_TEST_EVALUATORS Index rows() const { return int(Mode)==int(Projective) ? m_matrix.cols() : (m_matrix.cols()-1); } Index cols() const { return m_matrix.cols(); } -#endif /** shortcut for m_matrix(row,col); * \sa MatrixBase::operator(Index,Index) const */ diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 0c6a09861..4ded2995f 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -73,8 +73,6 @@ struct traits > }; }; -#ifdef EIGEN_TEST_EVALUATORS - struct HouseholderSequenceShape {}; template @@ -83,7 +81,6 @@ struct evaluator_traits > { typedef HouseholderSequenceShape Shape; }; -#endif template struct hseq_side_dependent_impl diff --git a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h index 92af28cc8..98b169868 100644 --- a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +++ b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h @@ -87,16 +87,6 @@ class DiagonalPreconditioner x = m_invdiag.array() * b.array() ; } -#ifndef EIGEN_TEST_EVALUATORS - template inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "DiagonalPreconditioner is not initialized."); - eigen_assert(m_invdiag.size()==b.rows() - && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#else template inline const Solve solve(const MatrixBase& b) const { @@ -105,31 +95,12 @@ class DiagonalPreconditioner && "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); return Solve(*this, b.derived()); } -#endif protected: Vector m_invdiag; bool m_isInitialized; }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef DiagonalPreconditioner<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} -#endif // EIGEN_TEST_EVALUATORS /** \ingroup IterativeLinearSolvers_Module * \brief A naive preconditioner which approximates any matrix as the identity matrix diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index b4d1d2a79..051940dc7 100644 --- a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -182,24 +182,6 @@ public: ~BiCGSTAB() {} -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const internal::solve_retval_with_guess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "BiCGSTAB is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "BiCGSTAB::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval_with_guess - (*this, b.derived(), x0); - } -#endif - /** \internal */ template void _solve_with_guess_impl(const Rhs& b, Dest& x) const @@ -234,25 +216,6 @@ protected: }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef BiCGSTAB<_MatrixType, _Preconditioner> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_BICGSTAB_H diff --git a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index b0273aaaf..f72cf86a5 100644 --- a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -192,24 +192,6 @@ public: ConjugateGradient(const MatrixType& A) : Base(A) {} ~ConjugateGradient() {} - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const internal::solve_retval_with_guess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "ConjugateGradient is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval_with_guess - (*this, b.derived(), x0); - } -#endif /** \internal */ template @@ -245,25 +227,6 @@ protected: }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_CONJUGATE_GRADIENT_H diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index f337c5fb0..7adbbc489 100644 --- a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -171,17 +171,6 @@ class IncompleteLUT : public SparseSolverBase > x = m_P * x; } -#ifndef EIGEN_TEST_EVALUATORS - template inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "IncompleteLUT is not initialized."); - eigen_assert(cols()==b.rows() - && "IncompleteLUT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif - protected: /** keeps off-diagonal entries; drops diagonal entries */ @@ -451,25 +440,6 @@ void IncompleteLUT::factorize(const _MatrixType& amat) m_info = Success; } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef IncompleteLUT<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_INCOMPLETE_LUT_H diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 26487dbb2..fd9285087 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -162,38 +162,6 @@ public: return m_error; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized."); - eigen_assert(rows()==b.rows() - && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(derived(), b.derived()); - } -#endif - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized."); - eigen_assert(rows()==b.rows() - && "IterativeSolverBase::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_TEST_EVALUATORS /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A * and \a x0 as an initial solution. * @@ -207,7 +175,6 @@ public: eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); return SolveWithGuess(derived(), b.derived(), x0); } -#endif // EIGEN_TEST_EVALUATORS /** \returns Success if the iterations converged, and NoConvergence otherwise. */ ComputationInfo info() const @@ -216,25 +183,6 @@ public: return m_info; } -#ifndef EIGEN_TEST_EVALUATORS - /** \internal */ - template - void _solve_sparse(const Rhs& b, SparseMatrix &dest) const - { - eigen_assert(rows()==b.rows()); - - int rhsCols = b.cols(); - int size = b.rows(); - Eigen::Matrix tb(size); - Eigen::Matrix tx(size); - for(int k=0; k void _solve_impl(const Rhs& b, SparseMatrix &dest) const @@ -252,7 +200,6 @@ public: dest.col(k) = tx.sparseView(0); } } -#endif // EIGEN_TEST_EVALUATORS protected: void init() @@ -275,25 +222,6 @@ protected: mutable bool m_analysisIsOk, m_factorizationIsOk; }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef IterativeSolverBase Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec().derived()._solve_sparse(rhs(),dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_ITERATIVE_SOLVER_BASE_H diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h index 9726bd96a..d6a3c1e5a 100644 --- a/Eigen/src/LU/Determinant.h +++ b/Eigen/src/LU/Determinant.h @@ -92,11 +92,7 @@ template inline typename internal::traits::Scalar MatrixBase::determinant() const { eigen_assert(rows() == cols()); -#ifdef EIGEN_TEST_EVALUATORS typedef typename internal::nested_eval::type Nested; -#else - typedef typename internal::nested::type Nested; -#endif return internal::determinant_impl::type>::run(derived()); } diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index daf99e305..fdf2e0642 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -220,7 +220,6 @@ template class FullPivLU * * \sa TriangularView::solve(), kernel(), inverse() */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -228,15 +227,6 @@ template class FullPivLU eigen_assert(m_isInitialized && "LU is not initialized."); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LU is not initialized."); - return internal::solve_retval(*this, b.derived()); - } -#endif /** \returns the determinant of the matrix of which * *this is the LU decomposition. It has only linear complexity @@ -380,22 +370,12 @@ template class FullPivLU * * \sa MatrixBase::inverse() */ -#ifdef EIGEN_TEST_EVALUATORS inline const Inverse inverse() const { eigen_assert(m_isInitialized && "LU is not initialized."); eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); return Inverse(*this); } -#else - inline const internal::solve_retval inverse() const - { - eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); - return internal::solve_retval - (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols())); - } -#endif MatrixType reconstructedMatrix() const; @@ -752,22 +732,8 @@ void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - EIGEN_MAKE_SOLVE_HELPERS(FullPivLU<_MatrixType>,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; -#endif /***** Implementation of inverse() *****************************************************/ -#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -778,7 +744,6 @@ struct Assignment >, internal::assign_ dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; -#endif } // end namespace internal /******* MatrixBase methods *****************************************************************/ diff --git a/Eigen/src/LU/InverseImpl.h b/Eigen/src/LU/InverseImpl.h index e10fee48f..e5f270d19 100644 --- a/Eigen/src/LU/InverseImpl.h +++ b/Eigen/src/LU/InverseImpl.h @@ -43,12 +43,8 @@ struct compute_inverse static inline void run(const MatrixType& matrix, ResultType& result) { typedef typename MatrixType::Scalar Scalar; -#ifdef EIGEN_TEST_EVALUATORS typename internal::evaluator::type matrixEval(matrix); result.coeffRef(0,0) = Scalar(1) / matrixEval.coeff(0,0); -#else - result.coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); -#endif } }; @@ -285,46 +281,8 @@ struct compute_inverse_and_det_with_check *** MatrixBase methods *** *************************/ -#ifndef EIGEN_TEST_EVALUATORS -template -struct traits > -{ - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct inverse_impl : public ReturnByValue > -{ - typedef typename MatrixType::Index Index; - typedef typename internal::eval::type MatrixTypeNested; - typedef typename remove_all::type MatrixTypeNestedCleaned; - MatrixTypeNested m_matrix; - - EIGEN_DEVICE_FUNC - inverse_impl(const MatrixType& matrix) - : m_matrix(matrix) - {} - - EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } - EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - - template - EIGEN_DEVICE_FUNC - inline void evalTo(Dest& dst) const - { - const int Size = EIGEN_PLAIN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime); - EIGEN_ONLY_USED_FOR_DEBUG(Size); - eigen_assert(( (Size<=1) || (Size>4) || (extract_data(m_matrix)!=extract_data(dst))) - && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); - - compute_inverse::run(m_matrix, dst); - } -}; -#endif } // end namespace internal -#ifdef EIGEN_TEST_EVALUATORS - namespace internal { // Specialization for "dense = dense_xpr.inverse()" @@ -352,8 +310,6 @@ struct Assignment, internal::assign_op, Den } // end namespace internal -#endif - /** \lu_module * * \returns the matrix inverse of this matrix. @@ -371,7 +327,6 @@ struct Assignment, internal::assign_op, Den * * \sa computeInverseAndDetWithCheck() */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Inverse MatrixBase::inverse() const { @@ -379,15 +334,6 @@ inline const Inverse MatrixBase::inverse() const eigen_assert(rows() == cols()); return Inverse(derived()); } -#else -template -inline const internal::inverse_impl MatrixBase::inverse() const -{ - EIGEN_STATIC_ASSERT(!NumTraits::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) - eigen_assert(rows() == cols()); - return internal::inverse_impl(derived()); -} -#endif /** \lu_module * @@ -422,11 +368,7 @@ inline void MatrixBase::computeInverseAndDetWithCheck( // for larger sizes, evaluating has negligible cost and limits code size. typedef typename internal::conditional< RowsAtCompileTime == 2, -#ifndef EIGEN_TEST_EVALUATORS - typename internal::remove_all::type>::type, -#else typename internal::remove_all::type>::type, -#endif PlainObject >::type MatrixType; internal::compute_inverse_and_det_with_check::run diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 57076f3a4..a4d22ce5f 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -142,7 +142,6 @@ template class PartialPivLU * * \sa TriangularView::solve(), inverse(), computeInverse() */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -150,15 +149,6 @@ template class PartialPivLU eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); - return internal::solve_retval(*this, b.derived()); - } -#endif /** \returns the inverse of the matrix of which *this is the LU decomposition. * @@ -167,20 +157,11 @@ template class PartialPivLU * * \sa MatrixBase::inverse(), LU::inverse() */ -#ifdef EIGEN_TEST_EVALUATORS inline const Inverse inverse() const { eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); return Inverse(*this); } -#else - inline const internal::solve_retval inverse() const - { - eigen_assert(m_isInitialized && "PartialPivLU is not initialized."); - return internal::solve_retval - (*this, MatrixType::Identity(m_lu.rows(), m_lu.cols())); - } -#endif /** \returns the determinant of the matrix of which * *this is the LU decomposition. It has only linear complexity @@ -490,22 +471,7 @@ MatrixType PartialPivLU::reconstructedMatrix() const namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - EIGEN_MAKE_SOLVE_HELPERS(PartialPivLU<_MatrixType>,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; -#endif - /***** Implementation of inverse() *****************************************************/ -#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -516,7 +482,6 @@ struct Assignment >, internal::assi dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; -#endif } // end namespace internal /******** MatrixBase methods *******/ diff --git a/Eigen/src/PaStiXSupport/PaStiXSupport.h b/Eigen/src/PaStiXSupport/PaStiXSupport.h index 95d53c850..bb8e0d1a8 100644 --- a/Eigen/src/PaStiXSupport/PaStiXSupport.h +++ b/Eigen/src/PaStiXSupport/PaStiXSupport.h @@ -153,22 +153,6 @@ class PastixBase : public SparseSolverBase { clean(); } - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "Pastix solver is not initialized."); - eigen_assert(rows()==b.rows() - && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif template bool _solve_impl(const MatrixBase &b, MatrixBase &x) const; @@ -227,22 +211,6 @@ class PastixBase : public SparseSolverBase return m_info; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "Pastix LU, LLT or LDLT is not initialized."); - eigen_assert(rows()==b.rows() - && "PastixBase::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif // EIGEN_TEST_EVALUATORS - protected: // Initialize the Pastix data structure, check the matrix @@ -693,38 +661,6 @@ class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > } }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef PastixBase<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef PastixBase<_MatrixType> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif diff --git a/Eigen/src/PardisoSupport/PardisoSupport.h b/Eigen/src/PardisoSupport/PardisoSupport.h index e3b1c5bc0..e1b0e1818 100644 --- a/Eigen/src/PardisoSupport/PardisoSupport.h +++ b/Eigen/src/PardisoSupport/PardisoSupport.h @@ -172,36 +172,6 @@ class PardisoImpl : public SparseSolveBase Derived& factorize(const MatrixType& matrix); Derived& compute(const MatrixType& matrix); - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "Pardiso solver is not initialized."); - eigen_assert(rows()==b.rows() - && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "Pardiso solver is not initialized."); - eigen_assert(rows()==b.rows() - && "PardisoImpl::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif template bool _solve_impl(const MatrixBase &b, MatrixBase& x) const; @@ -546,38 +516,6 @@ class PardisoLDLT : public PardisoImpl< PardisoLDLT > } }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef PardisoImpl<_Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef PardisoImpl Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_PARDISOSUPPORT_H diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index 96904c65f..adf737276 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -147,7 +147,6 @@ template class ColPivHouseholderQR * Example: \include ColPivHouseholderQR_solve.cpp * Output: \verbinclude ColPivHouseholderQR_solve.out */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -155,15 +154,6 @@ template class ColPivHouseholderQR eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - return internal::solve_retval(*this, b.derived()); - } -#endif HouseholderSequenceType householderQ() const; HouseholderSequenceType matrixQ() const @@ -304,22 +294,11 @@ template class ColPivHouseholderQR * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. */ -#ifdef EIGEN_TEST_EVALUATORS inline const Inverse inverse() const { eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); return Inverse(*this); } -#else - inline const - internal::solve_retval - inverse() const - { - eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - return internal::solve_retval - (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols())); - } -#endif inline Index rows() const { return m_qr.rows(); } inline Index cols() const { return m_qr.cols(); } @@ -582,21 +561,6 @@ void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType & namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - EIGEN_MAKE_SOLVE_HELPERS(ColPivHouseholderQR<_MatrixType>,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; -#endif - -#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -607,7 +571,6 @@ struct Assignment >, interna dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; -#endif } // end namespace internal diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index ea15da041..710c64a45 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -151,7 +151,6 @@ template class FullPivHouseholderQR * Example: \include FullPivHouseholderQR_solve.cpp * Output: \verbinclude FullPivHouseholderQR_solve.out */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -159,15 +158,6 @@ template class FullPivHouseholderQR eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - return internal::solve_retval(*this, b.derived()); - } -#endif /** \returns Expression object representing the matrix Q */ @@ -298,22 +288,11 @@ template class FullPivHouseholderQR * \note If this matrix is not invertible, the returned matrix has undefined coefficients. * Use isInvertible() to first determine whether this matrix is invertible. */ -#ifdef EIGEN_TEST_EVALUATORS inline const Inverse inverse() const { eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); return Inverse(*this); } -#else - inline const - internal::solve_retval - inverse() const - { - eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - return internal::solve_retval - (*this, MatrixType::Identity(m_qr.rows(), m_qr.cols())); - } -#endif inline Index rows() const { return m_qr.rows(); } inline Index cols() const { return m_qr.cols(); } @@ -556,21 +535,6 @@ void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - EIGEN_MAKE_SOLVE_HELPERS(FullPivHouseholderQR<_MatrixType>,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_TEST_EVALUATORS template struct Assignment >, internal::assign_op, Dense2Dense, Scalar> { @@ -581,7 +545,6 @@ struct Assignment >, intern dst = src.nestedExpression().solve(MatrixType::Identity(src.rows(), src.cols())); } }; -#endif /** \ingroup QR_Module * @@ -589,7 +552,6 @@ struct Assignment >, intern * * \tparam MatrixType type of underlying dense matrix */ -// #ifndef EIGEN_TEST_EVALUATORS template struct FullPivHouseholderQRMatrixQReturnType : public ReturnByValue > { @@ -645,12 +607,10 @@ protected: typename IntDiagSizeVectorType::Nested m_rowsTranspositions; }; -// #ifdef EIGEN_TEST_EVALUATORS // template // struct evaluator > // : public evaluator > > // {}; -// #endif } // end namespace internal diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 8604fff6f..0b0c9d1bd 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -117,7 +117,6 @@ template class HouseholderQR * Example: \include HouseholderQR_solve.cpp * Output: \verbinclude HouseholderQR_solve.out */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -125,15 +124,6 @@ template class HouseholderQR eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); return Solve(*this, b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - return internal::solve_retval(*this, b.derived()); - } -#endif /** This method returns an expression of the unitary matrix Q as a sequence of Householder transformations. * @@ -351,24 +341,6 @@ void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) c } #endif -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - EIGEN_MAKE_SOLVE_HELPERS(HouseholderQR<_MatrixType>,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(), dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - /** Performs the QR factorization of the given matrix \a matrix. The result of * the factorization is stored into \c *this, and a reference to \c *this * is returned. diff --git a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h index 483aaef07..bcdc981d7 100644 --- a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +++ b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h @@ -124,21 +124,6 @@ class SPQR : public SparseSolverBase > * Get the number of columns of the input matrix. */ inline Index cols() const { return m_cR->ncol; } - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval solve(const MatrixBase& B) const - { - eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()"); - eigen_assert(this->rows()==B.rows() - && "SPQR::solve(): invalid number of rows of the right hand side matrix B"); - return internal::solve_retval(*this, B.derived()); - } -#endif // EIGEN_TEST_EVALUATORS template void _solve_impl(const MatrixBase &b, MatrixBase &dest) const @@ -292,24 +277,5 @@ struct SPQRMatrixQTransposeReturnType{ const SPQRType& m_spqr; }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SPQR<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif - }// End namespace Eigen #endif diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h index 60a5aabb6..27b732b80 100644 --- a/Eigen/src/SVD/SVDBase.h +++ b/Eigen/src/SVD/SVDBase.h @@ -200,7 +200,6 @@ public: * \note SVD solving is implicitly least-squares. Thus, this method serves both purposes of exact solving and least-squares solving. * In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$. */ -#ifdef EIGEN_TEST_EVALUATORS template inline const Solve solve(const MatrixBase& b) const @@ -209,16 +208,6 @@ public: eigen_assert(computeU() && computeV() && "SVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); return Solve(derived(), b.derived()); } -#else - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "SVD is not initialized."); - eigen_assert(computeU() && computeV() && "SVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return internal::solve_retval(*this, b.derived()); - } -#endif #ifndef EIGEN_PARSED_BY_DOXYGEN template @@ -273,23 +262,6 @@ void SVDBase::_solve_impl(const RhsType &rhs, DstType &dst) const } #endif -namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SVDBase SVDType; - EIGEN_MAKE_SOLVE_HELPERS(SVDType,Rhs) - - template void evalTo(Dest& dst) const - { - dec().derived()._solve_impl(rhs(), dst); - } -}; -#endif -} // end namespace internal - template bool SVDBase::allocate(Index rows, Index cols, unsigned int computationOptions) { diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index ac8cd29b0..3c8cef5db 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -84,36 +84,6 @@ class SimplicialCholeskyBase : public SparseSolverBase return m_info; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); - eigen_assert(rows()==b.rows() - && "SimplicialCholeskyBase::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "Simplicial LLT or LDLT is not initialized."); - eigen_assert(rows()==b.rows() - && "SimplicialCholesky::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif // EIGEN_TEST_EVALUATORS - /** \returns the permutation P * \sa permutationPinv() */ const PermutationMatrix& permutationP() const @@ -157,11 +127,7 @@ class SimplicialCholeskyBase : public SparseSolverBase /** \internal */ template -#ifndef EIGEN_TEST_EVALUATORS - void _solve(const MatrixBase &b, MatrixBase &dest) const -#else void _solve_impl(const MatrixBase &b, MatrixBase &dest) const -#endif { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); eigen_assert(m_matrix.rows()==b.rows()); @@ -186,14 +152,12 @@ class SimplicialCholeskyBase : public SparseSolverBase if(m_P.size()>0) dest = m_Pinv * dest; } - -#ifdef EIGEN_TEST_EVALUATORS + template void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const { internal::solve_sparse_through_dense_panels(derived(), b, dest); } -#endif #endif // EIGEN_PARSED_BY_DOXYGEN @@ -578,11 +542,7 @@ public: /** \internal */ template -#ifndef EIGEN_TEST_EVALUATORS - void _solve(const MatrixBase &b, MatrixBase &dest) const -#else void _solve_impl(const MatrixBase &b, MatrixBase &dest) const -#endif { eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); eigen_assert(Base::m_matrix.rows()==b.rows()); @@ -618,14 +578,12 @@ public: dest = Base::m_Pinv * dest; } -#ifdef EIGEN_TEST_EVALUATORS /** \internal */ template void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const { internal::solve_sparse_through_dense_panels(*this, b, dest); } -#endif Scalar determinant() const { @@ -667,38 +625,6 @@ void SimplicialCholeskyBase::ordering(const MatrixType& a, CholMatrixTy ap.template selfadjointView() = a.template selfadjointView().twistedBy(m_P); } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SimplicialCholeskyBase Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec().derived()._solve(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef SimplicialCholeskyBase Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; - -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SIMPLICIAL_CHOLESKY_H diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 398008597..19d9eaa42 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -39,10 +39,8 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) Index estimated_nnz_prod = lhs.nonZeros() + rhs.nonZeros(); -#ifdef EIGEN_TEST_EVALUATORS typename evaluator::type lhsEval(lhs); typename evaluator::type rhsEval(rhs); -#endif res.setZero(); res.reserve(Index(estimated_nnz_prod)); @@ -52,19 +50,11 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r res.startVec(j); Index nnz = 0; -#ifndef EIGEN_TEST_EVALUATORS - for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt) -#else for (typename evaluator::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) -#endif { Scalar y = rhsIt.value(); Index k = rhsIt.index(); -#ifndef EIGEN_TEST_EVALUATORS - for (typename Lhs::InnerIterator lhsIt(lhs, k); lhsIt; ++lhsIt) -#else for (typename evaluator::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt) -#endif { Index i = lhsIt.index(); Scalar x = lhsIt.value(); diff --git a/Eigen/src/SparseCore/MappedSparseMatrix.h b/Eigen/src/SparseCore/MappedSparseMatrix.h index 9205b906f..d9aabd049 100644 --- a/Eigen/src/SparseCore/MappedSparseMatrix.h +++ b/Eigen/src/SparseCore/MappedSparseMatrix.h @@ -176,7 +176,6 @@ class MappedSparseMatrix::ReverseInnerIterator const Index m_end; }; -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -202,7 +201,6 @@ struct evaluator > }; } -#endif } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseAssign.h b/Eigen/src/SparseCore/SparseAssign.h index 36c9fe845..97c079d3f 100644 --- a/Eigen/src/SparseCore/SparseAssign.h +++ b/Eigen/src/SparseCore/SparseAssign.h @@ -12,117 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS - -template -template -Derived& SparseMatrixBase::operator=(const EigenBase &other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -template -template -Derived& SparseMatrixBase::operator=(const ReturnByValue& other) -{ - other.evalTo(derived()); - return derived(); -} - -template -template -inline Derived& SparseMatrixBase::operator=(const SparseMatrixBase& other) -{ - return assign(other.derived()); -} - -template -inline Derived& SparseMatrixBase::operator=(const Derived& other) -{ -// if (other.isRValue()) -// derived().swap(other.const_cast_derived()); -// else - return assign(other.derived()); -} - -template -template -inline Derived& SparseMatrixBase::assign(const OtherDerived& other) -{ - const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - const Index outerSize = (int(OtherDerived::Flags) & RowMajorBit) ? Index(other.rows()) : Index(other.cols()); - if ((!transpose) && other.isRValue()) - { - // eval without temporary - derived().resize(Index(other.rows()), Index(other.cols())); - derived().setZero(); - derived().reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j -template -inline void SparseMatrixBase::assignGeneric(const OtherDerived& other) -{ - //const bool transpose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - eigen_assert(( ((internal::traits::SupportedAccessPatterns&OuterRandomAccessPattern)==OuterRandomAccessPattern) || - (!((Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit)))) && - "the transpose operation is supposed to be handled in SparseMatrix::operator="); - - enum { Flip = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit) }; - - const Index outerSize = Index(other.outerSize()); - //typedef typename internal::conditional, Derived>::type TempType; - // thanks to shallow copies, we always eval to a tempary - Derived temp(Index(other.rows()), Index(other.cols())); - - temp.reserve((std::max)(this->rows(),this->cols())*2); - for (Index j=0; j -// inline Derived& operator=(const SparseSparseProduct& product); -// -// template -// Derived& operator+=(const SparseMatrixBase& other); -// template -// Derived& operator-=(const SparseMatrixBase& other); -// -// Derived& operator*=(const Scalar& other); -// Derived& operator/=(const Scalar& other); -// -// template -// Derived& operator*=(const SparseMatrixBase& other); - -#else // EIGEN_TEST_EVALUATORS - template template Derived& SparseMatrixBase::operator=(const EigenBase &other) @@ -298,8 +187,6 @@ struct Assignment, internal::assign_opindex(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public XprType::ReverseInnerIterator - { - typedef typename BlockImpl::Index Index; - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : XprType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; -#endif // EIGEN_TEST_EVALUATORS inline BlockImpl(const XprType& xpr, Index i) : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) @@ -66,14 +39,6 @@ public: Index nonZeros() const { -#ifndef EIGEN_TEST_EVALUATORS - Index nnz = 0; - Index end = m_outerStart + m_outerSize.value(); - for(Index j=m_outerStart; j::type EvaluatorType; EvaluatorType matEval(m_matrix); Index nnz = 0; @@ -82,7 +47,6 @@ public: for(typename EvaluatorType::InnerIterator it(matEval, j); it; ++it) ++nnz; return nnz; -#endif // EIGEN_TEST_EVALUATORS } inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } @@ -120,31 +84,6 @@ public: protected: enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; public: - -#ifndef EIGEN_TEST_EVALUATORS - class InnerIterator: public SparseMatrixType::InnerIterator - { - public: - inline InnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; - class ReverseInnerIterator: public SparseMatrixType::ReverseInnerIterator - { - public: - inline ReverseInnerIterator(const BlockType& xpr, Index outer) - : SparseMatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) - {} - inline Index row() const { return IsRowMajor ? m_outer : this->index(); } - inline Index col() const { return IsRowMajor ? this->index() : m_outer; } - protected: - Index m_outer; - }; -#endif // EIGEN_TEST_EVALUATORS inline sparse_matrix_block_impl(const SparseMatrixType& xpr, Index i) : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) @@ -434,34 +373,6 @@ public: m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } -#ifndef EIGEN_TEST_EVALUATORS - typedef internal::GenericSparseBlockInnerIteratorImpl InnerIterator; - - class ReverseInnerIterator : public _MatrixTypeNested::ReverseInnerIterator - { - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - const BlockType& m_block; - Index m_begin; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const BlockType& block, Index outer) - : Base(block.derived().nestedExpression(), outer + (IsRowMajor ? block.m_startRow.value() : block.m_startCol.value())), - m_block(block), - m_begin(IsRowMajor ? block.m_startCol.value() : block.m_startRow.value()) - { - while( (Base::operator bool()) && (Base::index() >= (IsRowMajor ? m_block.m_startCol.value()+block.m_blockCols.value() : m_block.m_startRow.value()+block.m_blockRows.value())) ) - Base::operator--(); - } - - inline Index index() const { return Base::index() - (IsRowMajor ? m_block.m_startCol.value() : m_block.m_startRow.value()); } - inline Index outer() const { return Base::outer() - (IsRowMajor ? m_block.m_startRow.value() : m_block.m_startCol.value()); } - inline Index row() const { return Base::row() - m_block.m_startRow.value(); } - inline Index col() const { return Base::col() - m_block.m_startCol.value(); } - - inline operator bool() const { return Base::operator bool() && Base::index() >= m_begin; } - }; -#endif // EIGEN_TEST_EVALUATORS - inline const _MatrixTypeNested& nestedExpression() const { return m_matrix; } Index startRow() const { return m_startRow.value(); } Index startCol() const { return m_startCol.value(); } @@ -574,9 +485,6 @@ namespace internal { inline operator bool() const { return m_outerPos < m_end; } }; -#ifdef EIGEN_TEST_EVALUATORS - -// template struct unary_evaluator, IteratorBased > : public evaluator_base > @@ -690,9 +598,6 @@ public: inline operator bool() const { return m_outerPos < m_end; } }; - -#endif // EIGEN_TEST_EVALUATORS - } // end namespace internal diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 3a7e72cd2..5993c1caf 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -38,256 +38,6 @@ class sparse_cwise_binary_op_inner_iterator_selector; } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS - -template -class CwiseBinaryOpImpl - : public SparseMatrixBase > -{ - public: - class InnerIterator; - class ReverseInnerIterator; - typedef CwiseBinaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - CwiseBinaryOpImpl() - { - typedef typename internal::traits::StorageKind LhsStorageKind; - typedef typename internal::traits::StorageKind RhsStorageKind; - EIGEN_STATIC_ASSERT(( - (!internal::is_same::value) - || ((Lhs::Flags&RowMajorBit) == (Rhs::Flags&RowMajorBit))), - THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH); - } -}; - -template -class CwiseBinaryOpImpl::InnerIterator - : public internal::sparse_cwise_binary_op_inner_iterator_selector::InnerIterator> -{ - public: - typedef internal::sparse_cwise_binary_op_inner_iterator_selector< - BinaryOp,Lhs,Rhs, InnerIterator> Base; - - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, Index outer) - : Base(binOp.derived(),outer) - {} -}; - -/*************************************************************************** -* Implementation of inner-iterators -***************************************************************************/ - -// template struct internal::func_is_conjunction { enum { ret = false }; }; -// template struct internal::func_is_conjunction > { enum { ret = true }; }; - -// TODO generalize the internal::scalar_product_op specialization to all conjunctions if any ! - -namespace internal { - -// sparse - sparse (generic) -template -class sparse_cwise_binary_op_inner_iterator_selector -{ - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename traits::Scalar Scalar; - typedef typename traits::Index Index; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename _RhsNested::InnerIterator RhsIterator; - - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - this->operator++(); - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), m_rhsIter.value()); - ++m_lhsIter; - ++m_rhsIter; - } - else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) - { - m_id = m_lhsIter.index(); - m_value = m_functor(m_lhsIter.value(), Scalar(0)); - ++m_lhsIter; - } - else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) - { - m_id = m_rhsIter.index(); - m_value = m_functor(Scalar(0), m_rhsIter.value()); - ++m_rhsIter; - } - else - { - m_value = 0; // this is to avoid a compilation warning - m_id = -1; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_value; } - - EIGEN_STRONG_INLINE Index index() const { return m_id; } - EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); } - EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryOp& m_functor; - Scalar m_value; - Index m_id; -}; - -// sparse - sparse (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename CwiseBinaryXpr::Index Index; - typedef typename traits::_LhsNested _LhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_lhsIter(xpr.lhs(),outer), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()) - { - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - } - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - ++m_rhsIter; - while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) - { - if (m_lhsIter.index() < m_rhsIter.index()) - ++m_lhsIter; - else - ++m_rhsIter; - } - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return (m_lhsIter && m_rhsIter); } - - protected: - LhsIterator m_lhsIter; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Sparse, Dense> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename CwiseBinaryXpr::Index Index; - typedef typename traits::_LhsNested _LhsNested; - typedef typename traits::RhsNested RhsNested; - typedef typename _LhsNested::InnerIterator LhsIterator; - enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_rhs(xpr.rhs()), m_lhsIter(xpr.lhs(),typename _LhsNested::Index(outer)), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_lhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_lhsIter.value(), - m_rhs.coeff(IsRowMajor?m_outer:m_lhsIter.index(),IsRowMajor?m_lhsIter.index():m_outer)); } - - EIGEN_STRONG_INLINE Index index() const { return m_lhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; } - - protected: - RhsNested m_rhs; - LhsIterator m_lhsIter; - const BinaryFunc m_functor; - const Index m_outer; -}; - -// sparse - dense (product) -template -class sparse_cwise_binary_op_inner_iterator_selector, Lhs, Rhs, Derived, Dense, Sparse> -{ - typedef scalar_product_op BinaryFunc; - typedef CwiseBinaryOp CwiseBinaryXpr; - typedef typename CwiseBinaryXpr::Scalar Scalar; - typedef typename CwiseBinaryXpr::Index Index; - typedef typename traits::_RhsNested _RhsNested; - typedef typename _RhsNested::InnerIterator RhsIterator; - - enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit }; - public: - - EIGEN_STRONG_INLINE sparse_cwise_binary_op_inner_iterator_selector(const CwiseBinaryXpr& xpr, Index outer) - : m_xpr(xpr), m_rhsIter(xpr.rhs(),outer), m_functor(xpr.functor()), m_outer(outer) - {} - - EIGEN_STRONG_INLINE Derived& operator++() - { - ++m_rhsIter; - return *static_cast(this); - } - - EIGEN_STRONG_INLINE Scalar value() const - { return m_functor(m_xpr.lhs().coeff(IsRowMajor?m_outer:m_rhsIter.index(),IsRowMajor?m_rhsIter.index():m_outer), m_rhsIter.value()); } - - EIGEN_STRONG_INLINE Index index() const { return m_rhsIter.index(); } - EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); } - EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); } - - EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; } - - protected: - const CwiseBinaryXpr& m_xpr; - RhsIterator m_rhsIter; - const BinaryFunc& m_functor; - const Index m_outer; -}; - -} // end namespace internal - -#else // EIGEN_TEST_EVALUATORS - namespace internal { @@ -590,10 +340,6 @@ protected: } -#endif - - - /*************************************************************************** * Implementation of SparseMatrixBase and SparseCwise functions/operators ***************************************************************************/ diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index 0e0f9f5f5..6036fd0a7 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -11,136 +11,6 @@ #define EIGEN_SPARSE_CWISE_UNARY_OP_H namespace Eigen { - -#ifndef EIGEN_TEST_EVALUATORS - -template -class CwiseUnaryOpImpl - : public SparseMatrixBase > -{ - public: - - typedef CwiseUnaryOp Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - - class InnerIterator; - class ReverseInnerIterator; - - protected: - typedef typename internal::traits::_XprTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; -}; - -template -class CwiseUnaryOpImpl::InnerIterator - : public CwiseUnaryOpImpl::MatrixTypeIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { Base::operator++(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); -}; - -template -class CwiseUnaryOpImpl::ReverseInnerIterator - : public CwiseUnaryOpImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryOpImpl::Scalar Scalar; - typedef typename CwiseUnaryOpImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryOpImpl& unaryOp, typename CwiseUnaryOpImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryOpImpl::Scalar value() const { return m_functor(Base::value()); } - - protected: - const UnaryOp m_functor; - private: - typename CwiseUnaryOpImpl::Scalar& valueRef(); -}; - -template -class CwiseUnaryViewImpl - : public SparseMatrixBase > -{ - public: - - class InnerIterator; - class ReverseInnerIterator; - - typedef CwiseUnaryView Derived; - EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) - - protected: - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator; - typedef typename _MatrixTypeNested::ReverseInnerIterator MatrixTypeReverseIterator; -}; - -template -class CwiseUnaryViewImpl::InnerIterator - : public CwiseUnaryViewImpl::MatrixTypeIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeIterator Base; - public: - - EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { Base::operator++(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; - -template -class CwiseUnaryViewImpl::ReverseInnerIterator - : public CwiseUnaryViewImpl::MatrixTypeReverseIterator -{ - typedef typename CwiseUnaryViewImpl::Scalar Scalar; - typedef typename CwiseUnaryViewImpl::MatrixTypeReverseIterator Base; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const CwiseUnaryViewImpl& unaryOp, typename CwiseUnaryViewImpl::Index outer) - : Base(unaryOp.derived().nestedExpression(),outer), m_functor(unaryOp.derived().functor()) - {} - - EIGEN_STRONG_INLINE ReverseInnerIterator& operator--() - { Base::operator--(); return *this; } - - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar value() const { return m_functor(Base::value()); } - EIGEN_STRONG_INLINE typename CwiseUnaryViewImpl::Scalar& valueRef() { return m_functor(Base::valueRef()); } - - protected: - const ViewOp m_functor; -}; - -#else // EIGEN_TEST_EVALUATORS namespace internal { @@ -291,8 +161,6 @@ class unary_evaluator, IteratorBased>::InnerItera } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - template EIGEN_STRONG_INLINE Derived& SparseMatrixBase::operator*=(const Scalar& other) diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 803d98e2d..04c838a71 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -30,18 +30,10 @@ struct sparse_time_dense_product_impl::type Rhs; typedef typename internal::remove_all::type Res; typedef typename Lhs::Index Index; -#ifndef EIGEN_TEST_EVALUATORS - typedef typename Lhs::InnerIterator LhsInnerIterator; -#else typedef typename evaluator::InnerIterator LhsInnerIterator; -#endif static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { -#ifndef EIGEN_TEST_EVALUATORS - const Lhs &lhsEval(lhs); -#else - typename evaluator::type lhsEval(lhs); -#endif + typename evaluator::type lhsEval(lhs); for(Index c=0; c::type Rhs; typedef typename internal::remove_all::type Res; typedef typename Lhs::Index Index; -#ifndef EIGEN_TEST_EVALUATORS - typedef typename Lhs::InnerIterator LhsInnerIterator; -#else typedef typename evaluator::InnerIterator LhsInnerIterator; -#endif static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const AlphaType& alpha) { -#ifndef EIGEN_TEST_EVALUATORS - const Lhs &lhsEval(lhs); -#else - typename evaluator::type lhsEval(lhs); -#endif + typename evaluator::type lhsEval(lhs); for(Index c=0; c::type Rhs; typedef typename internal::remove_all::type Res; typedef typename Lhs::Index Index; -#ifndef EIGEN_TEST_EVALUATORS - typedef typename Lhs::InnerIterator LhsInnerIterator; -#else typedef typename evaluator::InnerIterator LhsInnerIterator; -#endif static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { -#ifndef EIGEN_TEST_EVALUATORS - const Lhs &lhsEval(lhs); -#else - typename evaluator::type lhsEval(lhs); -#endif + typename evaluator::type lhsEval(lhs); for(Index j=0; j::type Rhs; typedef typename internal::remove_all::type Res; typedef typename Lhs::Index Index; -#ifndef EIGEN_TEST_EVALUATORS - typedef typename Lhs::InnerIterator LhsInnerIterator; -#else typedef typename evaluator::InnerIterator LhsInnerIterator; -#endif static void run(const SparseLhsType& lhs, const DenseRhsType& rhs, DenseResType& res, const typename Res::Scalar& alpha) { -#ifndef EIGEN_TEST_EVALUATORS - const Lhs &lhsEval(lhs); -#else - typename evaluator::type lhsEval(lhs); -#endif + typename evaluator::type lhsEval(lhs); for(Index j=0; j struct SparseDenseProductReturnType -{ - typedef SparseTimeDenseProduct Type; -}; - -template struct SparseDenseProductReturnType -{ - typedef typename internal::conditional< - Lhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef DenseTimeSparseProduct Type; -}; - -template struct DenseSparseProductReturnType -{ - typedef typename internal::conditional< - Rhs::IsRowMajor, - SparseDenseOuterProduct, - SparseDenseOuterProduct >::type Type; -}; - -namespace internal { - -template -struct traits > -{ - typedef Sparse StorageKind; - typedef typename scalar_product_traits::Scalar, - typename traits::Scalar>::ReturnType Scalar; - typedef typename Lhs::Index Index; - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - - enum { - LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost, - RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost, - - RowsAtCompileTime = Tr ? int(traits::RowsAtCompileTime) : int(traits::RowsAtCompileTime), - ColsAtCompileTime = Tr ? int(traits::ColsAtCompileTime) : int(traits::ColsAtCompileTime), - MaxRowsAtCompileTime = Tr ? int(traits::MaxRowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Tr ? int(traits::MaxColsAtCompileTime) : int(traits::MaxColsAtCompileTime), - - Flags = Tr ? RowMajorBit : 0, - - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + NumTraits::MulCost - }; -}; - -} // end namespace internal - -template -class SparseDenseOuterProduct - : public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseDenseOuterProduct) - typedef internal::traits Traits; - - private: - - typedef typename Traits::LhsNested LhsNested; - typedef typename Traits::RhsNested RhsNested; - typedef typename Traits::_LhsNested _LhsNested; - typedef typename Traits::_RhsNested _RhsNested; - - public: - - class InnerIterator; - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(!Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE SparseDenseOuterProduct(const Rhs& rhs, const Lhs& lhs) - : m_lhs(lhs), m_rhs(rhs) - { - EIGEN_STATIC_ASSERT(Tr,YOU_MADE_A_PROGRAMMING_MISTAKE); - } - - EIGEN_STRONG_INLINE Index rows() const { return Tr ? Index(m_rhs.rows()) : m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return Tr ? m_lhs.cols() : Index(m_rhs.cols()); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; - -template -class SparseDenseOuterProduct::InnerIterator : public _LhsNested::InnerIterator -{ - typedef typename _LhsNested::InnerIterator Base; - typedef typename SparseDenseOuterProduct::Index Index; - public: - EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_empty(false), m_factor(get(prod.rhs(), outer, typename internal::traits::StorageKind() )) - {} - - inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? m_outer : Base::index(); } - inline Index col() const { return Transpose ? Base::index() : m_outer; } - - inline Scalar value() const { return Base::value() * m_factor; } - inline operator bool() const { return Base::operator bool() && !m_empty; } - - protected: - Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) const - { - return rhs.coeff(outer); - } - - Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) - { - typename Traits::_RhsNested::InnerIterator it(rhs, outer); - if (it && it.index()==0 && it.value()!=Scalar(0)) - return it.value(); - m_empty = true; - return Scalar(0); - } - - Index m_outer; - bool m_empty; - Scalar m_factor; -}; - -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; - typedef MatrixXpr XprKind; -}; - -} // end namespace internal - -template -class SparseTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseTimeDenseProduct) - - SparseTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::sparse_time_dense_product(m_lhs, m_rhs, dest, alpha); - } - - private: - SparseTimeDenseProduct& operator=(const SparseTimeDenseProduct&); -}; - - -// dense = dense * sparse -namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} // end namespace internal - -template -class DenseTimeSparseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseProduct) - - DenseTimeSparseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - Transpose lhs_t(m_lhs); - Transpose rhs_t(m_rhs); - Transpose dest_t(dest); - internal::sparse_time_dense_product(rhs_t, lhs_t, dest_t, alpha); - } - - private: - DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); -}; - -#endif // EIGEN_TEST_EVALUATORS - -#ifdef EIGEN_TEST_EVALUATORS - namespace internal { template @@ -514,8 +276,6 @@ struct product_evaluator, OuterProduct, DenseS } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index 9f465a828..0cb2bd572 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -24,171 +24,8 @@ namespace Eigen { // for that particular case // The two other cases are symmetric. -#ifndef EIGEN_TEST_EVALUATORS - -namespace internal { - -template -struct traits > -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - typedef typename _Lhs::Scalar Scalar; - // propagate the index type of the sparse matrix - typedef typename conditional< is_diagonal<_Lhs>::ret, - typename traits::Index, - typename traits::Index>::type Index; - typedef Sparse StorageKind; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Lhs::RowsAtCompileTime, - ColsAtCompileTime = _Rhs::ColsAtCompileTime, - - MaxRowsAtCompileTime = _Lhs::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _Rhs::MaxColsAtCompileTime, - - SparseFlags = is_diagonal<_Lhs>::ret ? int(_Rhs::Flags) : int(_Lhs::Flags), - Flags = (SparseFlags&RowMajorBit), - CoeffReadCost = Dynamic - }; -}; - -enum {SDP_IsDiagonal, SDP_IsSparseRowMajor, SDP_IsSparseColMajor}; -template -class sparse_diagonal_product_inner_iterator_selector; - -} // end namespace internal - -template -class SparseDiagonalProduct - : public SparseMatrixBase >, - internal::no_assignment_operator -{ - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - - typedef typename internal::remove_all::type _LhsNested; - typedef typename internal::remove_all::type _RhsNested; - - enum { - LhsMode = internal::is_diagonal<_LhsNested>::ret ? internal::SDP_IsDiagonal - : (_LhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor, - RhsMode = internal::is_diagonal<_RhsNested>::ret ? internal::SDP_IsDiagonal - : (_RhsNested::Flags&RowMajorBit) ? internal::SDP_IsSparseRowMajor : internal::SDP_IsSparseColMajor - }; - - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) - - typedef internal::sparse_diagonal_product_inner_iterator_selector - <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; - - // We do not want ReverseInnerIterator for diagonal-sparse products, - // but this dummy declaration is needed to make diag * sparse * diag compile. - class ReverseInnerIterator; - - EIGEN_STRONG_INLINE SparseDiagonalProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs) - { - eigen_assert(lhs.cols() == rhs.rows() && "invalid sparse matrix * diagonal matrix product"); - } - - EIGEN_STRONG_INLINE Index rows() const { return Index(m_lhs.rows()); } - EIGEN_STRONG_INLINE Index cols() const { return Index(m_rhs.cols()); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; -}; -#endif - namespace internal { -#ifndef EIGEN_TEST_EVALUATORS - - - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Rhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Rhs>::InnerIterator Base; - typedef typename Rhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs()*(expr.lhs().diagonal().coeff(outer)), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Rhs::ConstInnerVectorReturnType, - const typename Lhs::DiagonalVectorType>::InnerIterator Base; - typedef typename Rhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.rhs().innerVector(outer) .cwiseProduct(expr.lhs().diagonal()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index col() const { return m_outer; } -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseUnaryOp,const Lhs>::InnerIterator -{ - typedef typename CwiseUnaryOp,const Lhs>::InnerIterator Base; - typedef typename Lhs::Index Index; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs()*expr.rhs().diagonal().coeff(outer), outer) - {} -}; - -template -class sparse_diagonal_product_inner_iterator_selector - - : public CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator -{ - typedef typename CwiseBinaryOp< - scalar_product_op, - const typename Lhs::ConstInnerVectorReturnType, - const Transpose >::InnerIterator Base; - typedef typename Lhs::Index Index; - Index m_outer; - public: - inline sparse_diagonal_product_inner_iterator_selector( - const SparseDiagonalProductType& expr, Index outer) - : Base(expr.lhs().innerVector(outer) .cwiseProduct(expr.rhs().diagonal().transpose()), 0), m_outer(outer) - {} - - inline Index outer() const { return m_outer; } - inline Index row() const { return m_outer; } -}; - -#else // EIGEN_TEST_EVALUATORS enum { SDP_AsScalarProduct, SDP_AsCwiseProduct @@ -303,23 +140,8 @@ protected: : SparseXprType::ColsAtCompileTime>::type m_diagCoeffNested; }; -#endif // EIGEN_TEST_EVALUATORS - - } // end namespace internal -#ifndef EIGEN_TEST_EVALUATORS - -// SparseMatrixBase functions -template -template -const SparseDiagonalProduct -SparseMatrixBase::operator*(const DiagonalBase &other) const -{ - return SparseDiagonalProduct(this->derived(), other.derived()); -} -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H diff --git a/Eigen/src/SparseCore/SparseDot.h b/Eigen/src/SparseCore/SparseDot.h index a63cb003c..b10c8058f 100644 --- a/Eigen/src/SparseCore/SparseDot.h +++ b/Eigen/src/SparseCore/SparseDot.h @@ -26,12 +26,8 @@ SparseMatrixBase::dot(const MatrixBase& other) const eigen_assert(size() == other.size()); eigen_assert(other.size()>0 && "you are using a non initialized vector"); -#ifndef EIGEN_TEST_EVALUATORS - typename Derived::InnerIterator i(derived(),0); -#else typename internal::evaluator::type thisEval(derived()); typename internal::evaluator::InnerIterator i(thisEval, 0); -#endif Scalar res(0); while (i) { @@ -54,24 +50,12 @@ SparseMatrixBase::dot(const SparseMatrixBase& other) cons eigen_assert(size() == other.size()); -#ifndef EIGEN_TEST_EVALUATORS - typedef typename Derived::Nested Nested; - typedef typename OtherDerived::Nested OtherNested; - typedef typename internal::remove_all::type NestedCleaned; - typedef typename internal::remove_all::type OtherNestedCleaned; - - Nested nthis(derived()); - OtherNested nother(other.derived()); - - typename NestedCleaned::InnerIterator i(nthis,0); - typename OtherNestedCleaned::InnerIterator j(nother,0); -#else typename internal::evaluator::type thisEval(derived()); typename internal::evaluator::InnerIterator i(thisEval, 0); typename internal::evaluator::type otherEval(other.derived()); typename internal::evaluator::InnerIterator j(otherEval, 0); -#endif + Scalar res(0); while (i && j) { diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 9e2dae1b3..72368ebf3 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -52,9 +52,6 @@ struct traits > MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic, Flags = _Options | NestByRefBit | LvalueBit, -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = NumTraits::ReadCost, -#endif SupportedAccessPatterns = InnerRandomAccessPattern }; }; @@ -77,9 +74,6 @@ struct traits, DiagIndex> MaxRowsAtCompileTime = Dynamic, MaxColsAtCompileTime = 1, Flags = 0 -#ifndef EIGEN_TEST_EVALUATORS - , CoeffReadCost = _MatrixTypeNested::CoeffReadCost*10 -#endif }; }; @@ -653,13 +647,9 @@ class SparseMatrix EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) check_template_parameters(); -#ifndef EIGEN_TEST_EVALUATORS - *this = other.derived(); -#else const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator::Flags & RowMajorBit); if (needToTranspose) *this = other.derived(); else internal::call_assignment_no_alias(*this, other.derived()); -#endif } /** Constructs a sparse matrix from the sparse selfadjoint view \a other */ @@ -668,11 +658,7 @@ class SparseMatrix : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) { check_template_parameters(); -#ifndef EIGEN_TEST_EVALUATORS - *this = other; -#else Base::operator=(other); -#endif } /** Copy constructor (it performs a deep copy) */ @@ -737,19 +723,6 @@ class SparseMatrix } #ifndef EIGEN_PARSED_BY_DOXYGEN -#ifndef EIGEN_TEST_EVALUATORS - template - inline SparseMatrix& operator=(const SparseSparseProduct& product) - { return Base::operator=(product); } - - template - inline SparseMatrix& operator=(const ReturnByValue& other) - { - initAssignment(other); - return Base::operator=(other.derived()); - } -#endif // EIGEN_TEST_EVALUATORS - template inline SparseMatrix& operator=(const EigenBase& other) { return Base::operator=(other.derived()); } @@ -1071,69 +1044,6 @@ void SparseMatrix::sumupDuplicates() m_data.resize(m_outerIndex[m_outerSize]); } -#ifndef EIGEN_TEST_EVALUATORS -template -template -EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) -{ - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit); - if (needToTranspose) - { - // two passes algorithm: - // 1 - compute the number of coeffs per dest inner vector - // 2 - do the actual copy/eval - // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed - typedef typename internal::nested::type OtherCopy; - typedef typename internal::remove_all::type _OtherCopy; - OtherCopy otherCopy(other.derived()); - - SparseMatrix dest(other.rows(),other.cols()); - Eigen::Map > (dest.m_outerIndex,dest.outerSize()).setZero(); - - // pass 1 - // FIXME the above copy could be merged with that pass - for (Index j=0; j positions(dest.outerSize()); - for (Index j=0; jswap(dest); - return *this; - } - else - { - if(other.isRValue()) - initAssignment(other.derived()); - // there is no special optimization - return Base::operator=(other.derived()); - } -} -#else template template EIGEN_DONT_INLINE SparseMatrix& SparseMatrix::operator=(const SparseMatrixBase& other) @@ -1199,7 +1109,6 @@ EIGEN_DONT_INLINE SparseMatrix& SparseMatrix EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& SparseMatrix<_Scalar,_Options,_Index>::insertUncompressed(Index row, Index col) @@ -1340,7 +1249,6 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse return (m_data.value(p) = 0); } -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -1370,7 +1278,6 @@ struct evaluator > }; } -#endif } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index aff4c8b6f..b5c50d93a 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -79,13 +79,6 @@ template class SparseMatrixBase : public EigenBase * constructed from this one. See the \ref flags "list of flags". */ -#ifndef EIGEN_TEST_EVALUATORS - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ -#endif - IsRowMajor = Flags&RowMajorBit ? 1 : 0, InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) @@ -189,11 +182,6 @@ template class SparseMatrixBase : public EigenBase public: -#ifndef EIGEN_TEST_EVALUATORS - template - inline Derived& operator=(const SparseSparseProduct& product); -#endif - friend std::ostream & operator << (std::ostream & s, const SparseMatrixBase& m) { typedef typename Derived::Nested Nested; @@ -265,36 +253,6 @@ template class SparseMatrixBase : public EigenBase EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE cwiseProduct(const MatrixBase &other) const; -#ifndef EIGEN_TEST_EVALUATORS - // sparse * sparse - template - const typename SparseSparseProductReturnType::Type - operator*(const SparseMatrixBase &other) const; - - // sparse * diagonal - template - const SparseDiagonalProduct - operator*(const DiagonalBase &other) const; - - // diagonal * sparse - template friend - const SparseDiagonalProduct - operator*(const DiagonalBase &lhs, const SparseMatrixBase& rhs) - { return SparseDiagonalProduct(lhs.derived(), rhs.derived()); } - - /** dense * sparse (return a dense object unless it is an outer product) */ - template friend - const typename DenseSparseProductReturnType::Type - operator*(const MatrixBase& lhs, const Derived& rhs) - { return typename DenseSparseProductReturnType::Type(lhs.derived(),rhs); } - - /** sparse * dense (returns a dense object unless it is an outer product) */ - template - const typename SparseDenseProductReturnType::Type - operator*(const MatrixBase &other) const - { return typename SparseDenseProductReturnType::Type(derived(), other.derived()); } - -#else // EIGEN_TEST_EVALUATORS // sparse * diagonal template const Product @@ -323,7 +281,6 @@ template class SparseMatrixBase : public EigenBase const Product operator*(const MatrixBase &lhs, const SparseMatrixBase& rhs) { return Product(lhs.derived(), rhs.derived()); } -#endif // EIGEN_TEST_EVALUATORS /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ SparseSymmetricPermutationProduct twistedBy(const PermutationMatrix& perm) const @@ -360,18 +317,6 @@ template class SparseMatrixBase : public EigenBase Block innerVectors(Index outerStart, Index outerSize); const Block innerVectors(Index outerStart, Index outerSize) const; -#ifndef EIGEN_TEST_EVALUATORS - /** \internal use operator= */ - template - void evalTo(MatrixBase& dst) const - { - dst.setZero(); - for (Index j=0; j toDense() const { return derived(); diff --git a/Eigen/src/SparseCore/SparsePermutation.h b/Eigen/src/SparseCore/SparsePermutation.h index a888ae9e1..228796bf8 100644 --- a/Eigen/src/SparseCore/SparsePermutation.h +++ b/Eigen/src/SparseCore/SparsePermutation.h @@ -103,48 +103,6 @@ struct permut_sparsematrix_product_retval } -#ifndef EIGEN_TEST_EVALUATORS - -/** \returns the matrix with the permutation applied to the columns - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false> -operator*(const SparseMatrixBase& matrix, const PermutationBase& perm) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, false>(perm, matrix.derived()); -} - -/** \returns the matrix with the permutation applied to the rows - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false> -operator*( const PermutationBase& perm, const SparseMatrixBase& matrix) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, false>(perm, matrix.derived()); -} - - - -/** \returns the matrix with the inverse permutation applied to the columns. - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true> -operator*(const SparseMatrixBase& matrix, const Transpose >& tperm) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheRight, true>(tperm.nestedPermutation(), matrix.derived()); -} - -/** \returns the matrix with the inverse permutation applied to the rows. - */ -template -inline const internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true> -operator*(const Transpose >& tperm, const SparseMatrixBase& matrix) -{ - return internal::permut_sparsematrix_product_retval, SparseDerived, OnTheLeft, true>(tperm.nestedPermutation(), matrix.derived()); -} - -#else // EIGEN_TEST_EVALUATORS - namespace internal { template struct product_promote_storage_type { typedef Sparse ret; }; @@ -274,8 +232,6 @@ operator*(const Transpose >& tperm, const SparseMat return Product >, SparseDerived>(tperm, matrix.derived()); } -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SPARSE_SELFADJOINTVIEW_H diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index 18f40b9d9..b68fe986a 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -12,182 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS - -template -struct SparseSparseProductReturnType -{ - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::Index Index; - enum { - LhsRowMajor = internal::traits::Flags & RowMajorBit, - RhsRowMajor = internal::traits::Flags & RowMajorBit, - TransposeRhs = (!LhsRowMajor) && RhsRowMajor, - TransposeLhs = LhsRowMajor && (!RhsRowMajor) - }; - - typedef typename internal::conditional, - typename internal::nested::type>::type LhsNested; - - typedef typename internal::conditional, - typename internal::nested::type>::type RhsNested; - - typedef SparseSparseProduct Type; -}; - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - // clean the nested types: - typedef typename remove_all::type _LhsNested; - typedef typename remove_all::type _RhsNested; - typedef typename _LhsNested::Scalar Scalar; - typedef typename promote_index_type::Index, - typename traits<_RhsNested>::Index>::type Index; - - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - - RowsAtCompileTime = _LhsNested::RowsAtCompileTime, - ColsAtCompileTime = _RhsNested::ColsAtCompileTime, - MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, - MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime, - - InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime), - - EvalToRowMajor = (RhsFlags & LhsFlags & RowMajorBit), - - RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), - - Flags = (int(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit - | EvalBeforeNestingBit, - - CoeffReadCost = Dynamic - }; - - typedef Sparse StorageKind; -}; - -} // end namespace internal - -template -class SparseSparseProduct : internal::no_assignment_operator, - public SparseMatrixBase > -{ - public: - - typedef SparseMatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(SparseSparseProduct) - - private: - - typedef typename internal::traits::_LhsNested _LhsNested; - typedef typename internal::traits::_RhsNested _RhsNested; - - public: - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(0), m_conservative(true) - { - init(); - } - - template - EIGEN_STRONG_INLINE SparseSparseProduct(const Lhs& lhs, const Rhs& rhs, const RealScalar& tolerance) - : m_lhs(lhs), m_rhs(rhs), m_tolerance(tolerance), m_conservative(false) - { - init(); - } - - SparseSparseProduct pruned(const Scalar& reference = 0, const RealScalar& epsilon = NumTraits::dummy_precision()) const - { - using std::abs; - return SparseSparseProduct(m_lhs,m_rhs,abs(reference)*epsilon); - } - - template - void evalTo(Dest& result) const - { - if(m_conservative) - internal::conservative_sparse_sparse_product_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result); - else - internal::sparse_sparse_product_with_pruning_selector<_LhsNested, _RhsNested, Dest>::run(lhs(),rhs(),result,m_tolerance); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } - - EIGEN_STRONG_INLINE const _LhsNested& lhs() const { return m_lhs; } - EIGEN_STRONG_INLINE const _RhsNested& rhs() const { return m_rhs; } - - protected: - void init() - { - eigen_assert(m_lhs.cols() == m_rhs.rows()); - - enum { - ProductIsValid = _LhsNested::ColsAtCompileTime==Dynamic - || _RhsNested::RowsAtCompileTime==Dynamic - || int(_LhsNested::ColsAtCompileTime)==int(_RhsNested::RowsAtCompileTime), - AreVectors = _LhsNested::IsVectorAtCompileTime && _RhsNested::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(_LhsNested,_RhsNested) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwise()*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) - } - - LhsNested m_lhs; - RhsNested m_rhs; - RealScalar m_tolerance; - bool m_conservative; -}; - -// sparse = sparse * sparse -template -template -inline Derived& SparseMatrixBase::operator=(const SparseSparseProduct& product) -{ - product.evalTo(derived()); - return derived(); -} - -/** \returns an expression of the product of two sparse matrices. - * By default a conservative product preserving the symbolic non zeros is performed. - * The automatic pruning of the small values can be achieved by calling the pruned() function - * in which case a totally different product algorithm is employed: - * \code - * C = (A*B).pruned(); // supress numerical zeros (exact) - * C = (A*B).pruned(ref); - * C = (A*B).pruned(ref,epsilon); - * \endcode - * where \c ref is a meaningful non zero reference value. - * */ -template -template -inline const typename SparseSparseProductReturnType::Type -SparseMatrixBase::operator*(const SparseMatrixBase &other) const -{ - return typename SparseSparseProductReturnType::Type(derived(), other.derived()); -} - -#else // EIGEN_TEST_EVALUATORS - - /** \returns an expression of the product of two sparse matrices. * By default a conservative product preserving the symbolic non zeros is performed. * The automatic pruning of the small values can be achieved by calling the pruned() function @@ -256,8 +80,6 @@ protected: } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SPARSEPRODUCT_H diff --git a/Eigen/src/SparseCore/SparseRedux.h b/Eigen/src/SparseCore/SparseRedux.h index cf78d0e91..763f2296b 100644 --- a/Eigen/src/SparseCore/SparseRedux.h +++ b/Eigen/src/SparseCore/SparseRedux.h @@ -18,14 +18,9 @@ SparseMatrixBase::sum() const { eigen_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); Scalar res(0); -#ifndef EIGEN_TEST_EVALUATORS - for (Index j=0; j::type thisEval(derived()); for (Index j=0; j::InnerIterator iter(thisEval,j); iter; ++iter) -#endif res += iter.value(); return res; } diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 4235d6c4c..69ac1a398 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -11,16 +11,6 @@ #define EIGEN_SPARSE_SELFADJOINTVIEW_H namespace Eigen { - -#ifndef EIGEN_TEST_EVALUATORS - -template -class SparseSelfAdjointTimeDenseProduct; - -template -class DenseTimeSparseSelfAdjointProduct; - -#endif // EIGEN_TEST_EVALUATORS /** \ingroup SparseCore_Module * \class SparseSelfAdjointView @@ -80,76 +70,40 @@ template class SparseSelfAdjointView * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ -#ifndef EIGEN_TEST_EVALUATORS - template - SparseSparseProduct - operator*(const SparseMatrixBase& rhs) const - { - return SparseSparseProduct(*this, rhs.derived()); - } -#else template Product operator*(const SparseMatrixBase& rhs) const { return Product(*this, rhs.derived()); } -#endif /** \returns an expression of the matrix product between a sparse matrix \a lhs and a sparse self-adjoint matrix \a rhs. * * Note that there is no algorithmic advantage of performing such a product compared to a general sparse-sparse matrix product. * Indeed, the SparseSelfadjointView operand is first copied into a temporary SparseMatrix before computing the product. */ -#ifndef EIGEN_TEST_EVALUATORS - template friend - SparseSparseProduct - operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return SparseSparseProduct(lhs.derived(), rhs); - } -#else // EIGEN_TEST_EVALUATORS template friend Product operator*(const SparseMatrixBase& lhs, const SparseSelfAdjointView& rhs) { return Product(lhs.derived(), rhs); } -#endif // EIGEN_TEST_EVALUATORS /** Efficient sparse self-adjoint matrix times dense vector/matrix product */ -#ifndef EIGEN_TEST_EVALUATORS - template - SparseSelfAdjointTimeDenseProduct - operator*(const MatrixBase& rhs) const - { - return SparseSelfAdjointTimeDenseProduct(m_matrix, rhs.derived()); - } -#else template Product operator*(const MatrixBase& rhs) const { return Product(*this, rhs.derived()); } -#endif /** Efficient dense vector/matrix times sparse self-adjoint matrix product */ -#ifndef EIGEN_TEST_EVALUATORS - template friend - DenseTimeSparseSelfAdjointProduct - operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) - { - return DenseTimeSparseSelfAdjointProduct(lhs.derived(), rhs.m_matrix); - } -#else template friend Product operator*(const MatrixBase& lhs, const SparseSelfAdjointView& rhs) { return Product(lhs.derived(), rhs); } -#endif /** Perform a symmetric rank K update of the selfadjoint matrix \c *this: * \f$ this = this + \alpha ( u u^* ) \f$ where \a u is a vector or matrix. @@ -177,7 +131,7 @@ template class SparseSelfAdjointView } /** \returns an expression of P H P^-1 */ -// #ifndef EIGEN_TEST_EVALUATORS + // TODO implement twists in a more evaluator friendly fashion SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode> twistedBy(const PermutationMatrix& perm) const { return SparseSymmetricPermutationProduct<_MatrixTypeNested,Mode>(m_matrix, perm); @@ -189,7 +143,6 @@ template class SparseSelfAdjointView permutedMatrix.evalTo(*this); return *this; } -// #endif // EIGEN_TEST_EVALUATORS SparseSelfAdjointView& operator=(const SparseSelfAdjointView& src) { @@ -251,98 +204,6 @@ SparseSelfAdjointView::rankUpdate(const SparseMatrixBase -struct traits > - : traits, Lhs, Rhs> > -{ - typedef Dense StorageKind; -}; -} - -template -class SparseSelfAdjointTimeDenseProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(SparseSelfAdjointTimeDenseProduct) - - SparseSelfAdjointTimeDenseProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - EIGEN_ONLY_USED_FOR_DEBUG(alpha); - // TODO use alpha - eigen_assert(alpha==Scalar(1) && "alpha != 1 is not implemented yet, sorry"); - typedef typename internal::remove_all::type _Lhs; - typedef typename _Lhs::InnerIterator LhsInnerIterator; - enum { - LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit, - ProcessFirstHalf = - ((Mode&(Upper|Lower))==(Upper|Lower)) - || ( (Mode&Upper) && !LhsIsRowMajor) - || ( (Mode&Lower) && LhsIsRowMajor), - ProcessSecondHalf = !ProcessFirstHalf - }; - for (typename _Lhs::Index j=0; j -struct traits > - : traits, Lhs, Rhs> > -{}; -} - -template -class DenseTimeSparseSelfAdjointProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(DenseTimeSparseSelfAdjointProduct) - - DenseTimeSparseSelfAdjointProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - {} - - template void scaleAndAddTo(Dest& /*dest*/, const Scalar& /*alpha*/) const - { - // TODO - } - - private: - DenseTimeSparseSelfAdjointProduct& operator=(const DenseTimeSparseSelfAdjointProduct&); -}; - -#else // EIGEN_TEST_EVALUATORS - namespace internal { template @@ -486,8 +347,6 @@ protected: } // namespace internal -#endif // EIGEN_TEST_EVALUATORS - /*************************************************************************** * Implementation of symmetric copies and permutations ***************************************************************************/ @@ -644,7 +503,7 @@ void permute_symm_to_symm(const MatrixType& mat, SparseMatrix(this); } const Derived& derived() const { return *static_cast(this); } -#ifdef EIGEN_TEST_EVALUATORS /** \returns an expression of the solution x of \f$ A x = b \f$ using the current decomposition of A. * * \sa compute() @@ -91,17 +90,15 @@ class SparseSolverBase : internal::noncopyable eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); return Solve(derived(), b.derived()); } -#endif - - -#ifndef EIGEN_PARSED_BY_DOXYGEN + + #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal default implementation of solving with a sparse rhs */ template void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const { internal::solve_sparse_through_dense_panels(derived(), b.derived(), dest.derived()); } -#endif // EIGEN_PARSED_BY_DOXYGEN + #endif // EIGEN_PARSED_BY_DOXYGEN protected: diff --git a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h index b42b33e55..f291f8cef 100644 --- a/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +++ b/Eigen/src/SparseCore/SparseSparseProductWithPruning.h @@ -47,10 +47,8 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r else res.resize(rows, cols); - #ifdef EIGEN_TEST_EVALUATORS typename evaluator::type lhsEval(lhs); typename evaluator::type rhsEval(rhs); - #endif res.reserve(estimated_nnz_prod); double ratioColRes = double(estimated_nnz_prod)/double(lhs.rows()*rhs.cols()); @@ -61,20 +59,12 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r // let's do a more accurate determination of the nnz ratio for the current column j of res tempVector.init(ratioColRes); tempVector.setZero(); -#ifndef EIGEN_TEST_EVALUATORS - for (typename Rhs::InnerIterator rhsIt(rhs, j); rhsIt; ++rhsIt) -#else for (typename evaluator::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) -#endif { // FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index()) tempVector.restart(); Scalar x = rhsIt.value(); -#ifndef EIGEN_TEST_EVALUATORS - for (typename Lhs::InnerIterator lhsIt(lhs, rhsIt.index()); lhsIt; ++lhsIt) -#else for (typename evaluator::InnerIterator lhsIt(lhsEval, rhsIt.index()); lhsIt; ++lhsIt) -#endif { tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x; } @@ -153,10 +143,6 @@ struct sparse_sparse_product_with_pruning_selector struct sparse_sparse_product_with_pruning_selector { @@ -204,7 +190,6 @@ struct sparse_sparse_product_with_pruning_selector(colLhs, rhs, res, tolerance); } }; -#endif } // end namespace internal diff --git a/Eigen/src/SparseCore/SparseTranspose.h b/Eigen/src/SparseCore/SparseTranspose.h index f5eff6133..fae7cae97 100644 --- a/Eigen/src/SparseCore/SparseTranspose.h +++ b/Eigen/src/SparseCore/SparseTranspose.h @@ -12,55 +12,6 @@ namespace Eigen { -#ifndef EIGEN_TEST_EVALUATORS -template class TransposeImpl - : public SparseMatrixBase > -{ - typedef typename internal::remove_all::type _MatrixTypeNested; - public: - - EIGEN_SPARSE_PUBLIC_INTERFACE(Transpose ) - - class InnerIterator; - class ReverseInnerIterator; - - inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } -}; - -// NOTE: VC10 trigger an ICE if don't put typename TransposeImpl:: in front of Index, -// a typedef typename TransposeImpl::Index Index; -// does not fix the issue. -// An alternative is to define the nested class in the parent class itself. -template class TransposeImpl::InnerIterator - : public _MatrixTypeNested::InnerIterator -{ - typedef typename _MatrixTypeNested::InnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl::Index outer) - : Base(trans.derived().nestedExpression(), outer) - {} - Index row() const { return Base::col(); } - Index col() const { return Base::row(); } -}; - -template class TransposeImpl::ReverseInnerIterator - : public _MatrixTypeNested::ReverseInnerIterator -{ - typedef typename _MatrixTypeNested::ReverseInnerIterator Base; - typedef typename TransposeImpl::Index Index; - public: - - EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl::Index outer) - : Base(xpr.derived().nestedExpression(), outer) - {} - Index row() const { return Base::col(); } - Index col() const { return Base::row(); } -}; - -#else // EIGEN_TEST_EVALUATORS - // Implement nonZeros() for transpose. I'm not sure that's the best approach for that. // Perhaps it should be implemented in Transpose<> itself. template class TransposeImpl @@ -119,8 +70,6 @@ struct unary_evaluator, IteratorBased> } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - } // end namespace Eigen #endif // EIGEN_SPARSETRANSPOSE_H diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 3df7a4cd4..744c3d730 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -40,11 +40,6 @@ protected: typedef typename internal::remove_reference::type MatrixTypeNestedNonRef; typedef typename internal::remove_all::type MatrixTypeNestedCleaned; -#ifndef EIGEN_TEST_EVALUATORS - template - typename internal::plain_matrix_type_column_major::type - solve(const MatrixBase& other) const; -#else // EIGEN_TEST_EVALUATORS template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _solve_impl(const RhsType &rhs, DstType &dst) const { @@ -52,7 +47,6 @@ protected: dst = rhs; this->solveInPlace(dst); } -#endif // EIGEN_TEST_EVALUATORS template void solveInPlace(MatrixBase& other) const; template void solveInPlace(SparseMatrixBase& other) const; @@ -163,7 +157,6 @@ class TriangularViewImpl::ReverseInnerIterator : public } }; -#ifdef EIGEN_TEST_EVALUATORS namespace internal { template @@ -270,7 +263,6 @@ protected: }; } // end namespace internal -#endif template template diff --git a/Eigen/src/SparseCore/SparseUtil.h b/Eigen/src/SparseCore/SparseUtil.h index 28bf89bca..8de227b88 100644 --- a/Eigen/src/SparseCore/SparseUtil.h +++ b/Eigen/src/SparseCore/SparseUtil.h @@ -43,26 +43,6 @@ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) -#ifndef EIGEN_TEST_EVALUATORS - -#define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::internal::traits::Scalar Scalar; \ - typedef typename Eigen::NumTraits::Real RealScalar; \ - typedef typename Eigen::internal::nested::type Nested; \ - typedef typename Eigen::internal::traits::StorageKind StorageKind; \ - typedef typename Eigen::internal::traits::Index Index; \ - enum { RowsAtCompileTime = Eigen::internal::traits::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::internal::traits::ColsAtCompileTime, \ - Flags = Eigen::internal::traits::Flags, \ - CoeffReadCost = Eigen::internal::traits::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; \ - using Base::derived; \ - using Base::const_cast_derived; - -#else // EIGEN_TEST_EVALUATORS - #define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ typedef typename Eigen::internal::traits::Scalar Scalar; \ @@ -78,8 +58,6 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) using Base::derived; \ using Base::const_cast_derived; -#endif // EIGEN_TEST_EVALUATORS - #define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase) @@ -156,13 +134,11 @@ template struct plain_matrix_type typedef SparseMatrix<_Scalar, _Options, _Index> type; }; -#ifdef EIGEN_TEST_EVALUATORS template struct solve_traits { typedef typename sparse_eval::type PlainObject; }; -#endif template struct generic_xpr_base diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index 0f9aa9dd1..c9f9d61e9 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.h @@ -422,30 +422,6 @@ class SparseVector::ReverseInnerIterator namespace internal { -#ifndef EIGEN_TEST_EVALUATORS -template< typename Dest, typename Src> -struct sparse_vector_assign_selector { - static void run(Dest& dst, const Src& src) { - eigen_internal_assert(src.innerSize()==src.size()); - for(typename Src::InnerIterator it(src, 0); it; ++it) - dst.insert(it.index()) = it.value(); - } -}; - -template< typename Dest, typename Src> -struct sparse_vector_assign_selector { - static void run(Dest& dst, const Src& src) { - eigen_internal_assert(src.outerSize()==src.size()); - for(typename Dest::Index i=0; i struct evaluator > : evaluator_base > @@ -492,7 +468,6 @@ struct sparse_vector_assign_selector { } } }; -#endif // EIGEN_TEST_EVALUATORS template< typename Dest, typename Src> struct sparse_vector_assign_selector { diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index c1c50f6e9..d10cc5a35 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -40,10 +40,6 @@ public: RealScalar m_epsilon = NumTraits::dummy_precision()) : m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} -#ifndef EIGEN_TEST_EVALUATORS - class InnerIterator; -#endif // EIGEN_TEST_EVALUATORS - inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } @@ -63,43 +59,6 @@ protected: RealScalar m_epsilon; }; -#ifndef EIGEN_TEST_EVALUATORS -template -class SparseView::InnerIterator : public _MatrixTypeNested::InnerIterator -{ - typedef typename SparseView::Index Index; -public: - typedef typename _MatrixTypeNested::InnerIterator IterBase; - InnerIterator(const SparseView& view, Index outer) : - IterBase(view.m_matrix, outer), m_view(view) - { - incrementToNonZero(); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() - { - IterBase::operator++(); - incrementToNonZero(); - return *this; - } - - using IterBase::value; - -protected: - const SparseView& m_view; - -private: - void incrementToNonZero() - { - while((bool(*this)) && internal::isMuchSmallerThan(value(), m_view.reference(), m_view.epsilon())) - { - IterBase::operator++(); - } - } -}; - -#else // EIGEN_TEST_EVALUATORS - namespace internal { // TODO find a way to unify the two following variants @@ -230,8 +189,6 @@ struct unary_evaluator, IndexBased> } // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - template const SparseView MatrixBase::sparseView(const Scalar& reference, const typename NumTraits::Real& epsilon) const diff --git a/Eigen/src/SparseCore/TriangularSolver.h b/Eigen/src/SparseCore/TriangularSolver.h index 012a1bb75..98062e9c6 100644 --- a/Eigen/src/SparseCore/TriangularSolver.h +++ b/Eigen/src/SparseCore/TriangularSolver.h @@ -23,149 +23,6 @@ template::Flags) & RowMajorBit> struct sparse_solve_triangular_selector; -#ifndef EIGEN_TEST_EVALUATORS -// forward substitution, row-major -template -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename Lhs::Index Index; - static void run(const Lhs& lhs, Rhs& other) - { - for(Index col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename Lhs::Index Index; - static void run(const Lhs& lhs, Rhs& other) - { - for(Index col=0 ; col=0 ; --i) - { - Scalar tmp = other.coeff(i,col); - Scalar l_ii = 0; - typename Lhs::InnerIterator it(lhs, i); - while(it && it.index() -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename Lhs::Index Index; - static void run(const Lhs& lhs, Rhs& other) - { - for(Index col=0 ; col -struct sparse_solve_triangular_selector -{ - typedef typename Rhs::Scalar Scalar; - typedef typename Lhs::Index Index; - static void run(const Lhs& lhs, Rhs& other) - { - for(Index col=0 ; col=0; --i) - { - Scalar& tmp = other.coeffRef(i,col); - if (tmp!=Scalar(0)) // optimization when other is actually sparse - { - if(!(Mode & UnitDiag)) - { - // TODO replace this by a binary search. make sure the binary search is safe for partially sorted elements - typename Lhs::ReverseInnerIterator it(lhs, i); - while(it && it.index()!=i) - --it; - eigen_assert(it && it.index()==i); - other.coeffRef(i,col) /= it.value(); - } - typename Lhs::InnerIterator it(lhs, i); - for(; it && it.index() struct sparse_solve_triangular_selector @@ -316,7 +173,6 @@ struct sparse_solve_triangular_selector } }; -#endif // EIGEN_TEST_EVALUATORS } // end namespace internal template @@ -338,18 +194,6 @@ void TriangularViewImpl::solveInPlace(MatrixBase -template -typename internal::plain_matrix_type_column_major::type -TriangularViewImpl::solve(const MatrixBase& other) const -{ - typename internal::plain_matrix_type_column_major::type res(other); - solveInPlace(res); - return res; -} -#endif - // pure sparse path namespace internal { diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index fb01f99cd..14d7e713e 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -173,36 +173,6 @@ class SparseLU : public SparseSolverBase >, m_diagpivotthresh = thresh; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. - * - * \warning the destination matrix X in X = this->solve(B) must be colmun-major. - * - * \sa compute() - */ - template - inline const internal::solve_retval solve(const MatrixBase& B) const - { - eigen_assert(m_factorizationIsOk && "SparseLU is not initialized."); - eigen_assert(rows()==B.rows() - && "SparseLU::solve(): invalid number of rows of the right hand side matrix B"); - return internal::solve_retval(*this, B.derived()); - } - - /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval solve(const SparseMatrixBase& B) const - { - eigen_assert(m_factorizationIsOk && "SparseLU is not initialized."); - eigen_assert(rows()==B.rows() - && "SparseLU::solve(): invalid number of rows of the right hand side matrix B"); - return internal::sparse_solve_retval(*this, B.derived()); - } -#else - #ifdef EIGEN_PARSED_BY_DOXYGEN /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. * @@ -214,8 +184,6 @@ class SparseLU : public SparseSolverBase >, inline const Solve solve(const MatrixBase& B) const; #endif // EIGEN_PARSED_BY_DOXYGEN -#endif // EIGEN_TEST_EVALUATORS - /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, @@ -749,37 +717,6 @@ struct SparseLUMatrixUReturnType : internal::no_assignment_operator const MatrixUType& m_mapU; }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SparseLU<_MatrixType,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef SparseLU<_MatrixType,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; -} // end namespace internal -#endif - } // End namespace Eigen #endif diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 8e946b045..1a6c84e00 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -202,26 +202,6 @@ class SparseQR : public SparseSolverBase > m_threshold = threshold; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval solve(const MatrixBase& B) const - { - eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); - eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); - return internal::solve_retval(*this, B.derived()); - } - template - inline const internal::sparse_solve_retval solve(const SparseMatrixBase& B) const - { - eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); - eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); - return internal::sparse_solve_retval(*this, B.derived()); - } -#else /** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A. * * \sa compute() @@ -240,7 +220,6 @@ class SparseQR : public SparseSolverBase > eigen_assert(this->rows() == B.rows() && "SparseQR::solve() : invalid number of rows in the right hand side matrix"); return Solve(*this, B.derived()); } -#endif // EIGEN_TEST_EVALUATORS /** \brief Reports whether previous computation was successful. * @@ -577,36 +556,6 @@ void SparseQR::factorize(const MatrixType& mat) m_info = Success; } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SparseQR<_MatrixType,OrderingType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef SparseQR<_MatrixType, OrderingType> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec, Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; -} // end namespace internal -#endif // EIGEN_TEST_EVALUATORS - template struct SparseQR_QProduct : ReturnByValue > { diff --git a/Eigen/src/SuperLUSupport/SuperLUSupport.h b/Eigen/src/SuperLUSupport/SuperLUSupport.h index fcecd4fcf..0137585ca 100644 --- a/Eigen/src/SuperLUSupport/SuperLUSupport.h +++ b/Eigen/src/SuperLUSupport/SuperLUSupport.h @@ -336,34 +336,6 @@ class SuperLUBase : public SparseSolverBase derived().analyzePattern(matrix); derived().factorize(matrix); } - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "SuperLU is not initialized."); - eigen_assert(rows()==b.rows() - && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "SuperLU is not initialized."); - eigen_assert(rows()==b.rows() - && "SuperLU::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif // EIGEN_TEST_EVALUATORS /** Performs a symbolic decomposition on the sparcity of \a matrix. * @@ -995,37 +967,6 @@ void SuperILU::_solve_impl(const MatrixBase &b, MatrixBase -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef SuperLUBase<_MatrixType,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec().derived()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef SuperLUBase<_MatrixType,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; - -} // end namespace internal -#endif } // end namespace Eigen #endif // EIGEN_SUPERLUSUPPORT_H diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index 845c8076a..7fada5567 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -201,34 +201,6 @@ class UmfPackLU : public SparseSolverBase > analyzePattern(matrix); factorize(matrix); } - -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "UmfPackLU is not initialized."); - eigen_assert(rows()==b.rows() - && "UmfPackLU::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "UmfPackLU is not initialized."); - eigen_assert(rows()==b.rows() - && "UmfPackLU::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } -#endif /** Performs a symbolic decomposition on the sparcity of \a matrix. * @@ -401,37 +373,6 @@ bool UmfPackLU::_solve_impl(const MatrixBase &b, MatrixBas return true; } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef UmfPackLU<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef UmfPackLU<_MatrixType> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - this->defaultEvalTo(dst); - } -}; - -} // end namespace internal -#endif } // end namespace Eigen #endif // EIGEN_UMFPACKSUPPORT_H diff --git a/Eigen/src/misc/Solve.h b/Eigen/src/misc/Solve.h deleted file mode 100644 index ebdd981d0..000000000 --- a/Eigen/src/misc/Solve.h +++ /dev/null @@ -1,78 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MISC_SOLVE_H -#define EIGEN_MISC_SOLVE_H - -#ifndef EIGEN_TEST_EVALUATORS - -namespace Eigen { - -namespace internal { - -/** \class solve_retval_base - * - */ -template -struct traits > -{ - typedef typename DecompositionType::MatrixType MatrixType; - typedef Matrix ReturnType; -}; - -template struct solve_retval_base - : public ReturnByValue > -{ - typedef typename remove_all::type RhsNestedCleaned; - typedef _DecompositionType DecompositionType; - typedef ReturnByValue Base; - typedef typename Base::Index Index; - - solve_retval_base(const DecompositionType& dec, const Rhs& rhs) - : m_dec(dec), m_rhs(rhs) - {} - - inline Index rows() const { return m_dec.cols(); } - inline Index cols() const { return m_rhs.cols(); } - inline const DecompositionType& dec() const { return m_dec; } - inline const RhsNestedCleaned& rhs() const { return m_rhs; } - - template inline void evalTo(Dest& dst) const - { - static_cast*>(this)->evalTo(dst); - } - - protected: - const DecompositionType& m_dec; - typename Rhs::Nested m_rhs; -}; - -} // end namespace internal - -#define EIGEN_MAKE_SOLVE_HELPERS(DecompositionType,Rhs) \ - typedef typename DecompositionType::MatrixType MatrixType; \ - typedef typename MatrixType::Scalar Scalar; \ - typedef typename MatrixType::RealScalar RealScalar; \ - typedef typename MatrixType::Index Index; \ - typedef Eigen::internal::solve_retval_base Base; \ - using Base::dec; \ - using Base::rhs; \ - using Base::rows; \ - using Base::cols; \ - solve_retval(const DecompositionType& dec, const Rhs& rhs) \ - : Base(dec, rhs) {} - -} // end namespace Eigen -#endif // EIGEN_TEST_EVALUATORS -#endif // EIGEN_MISC_SOLVE_H diff --git a/Eigen/src/misc/SparseSolve.h b/Eigen/src/misc/SparseSolve.h deleted file mode 100644 index 2396dc8e8..000000000 --- a/Eigen/src/misc/SparseSolve.h +++ /dev/null @@ -1,134 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSE_SOLVE_H -#define EIGEN_SPARSE_SOLVE_H - -#ifndef EIGEN_TEST_EVALUATORS - -namespace Eigen { - -namespace internal { - -template struct sparse_solve_retval_base; -template struct sparse_solve_retval; - -template -struct traits > -{ - typedef typename DecompositionType::MatrixType MatrixType; - typedef SparseMatrix ReturnType; -}; - -template struct sparse_solve_retval_base - : public ReturnByValue > -{ - typedef typename remove_all::type RhsNestedCleaned; - typedef _DecompositionType DecompositionType; - typedef ReturnByValue Base; - typedef typename Base::Index Index; - - sparse_solve_retval_base(const DecompositionType& dec, const Rhs& rhs) - : m_dec(dec), m_rhs(rhs) - {} - - inline Index rows() const { return m_dec.cols(); } - inline Index cols() const { return m_rhs.cols(); } - inline const DecompositionType& dec() const { return m_dec; } - inline const RhsNestedCleaned& rhs() const { return m_rhs; } - - template inline void evalTo(Dest& dst) const - { - static_cast*>(this)->evalTo(dst); - } - - protected: - template - inline void defaultEvalTo(SparseMatrix& dst) const - { - // we process the sparse rhs per block of NbColsAtOnce columns temporarily stored into a dense matrix. - static const int NbColsAtOnce = 4; - int rhsCols = m_rhs.cols(); - int size = m_rhs.rows(); - // the temporary matrices do not need more columns than NbColsAtOnce: - int tmpCols = (std::min)(rhsCols, NbColsAtOnce); - Eigen::Matrix tmp(size,tmpCols); - Eigen::Matrix tmpX(size,tmpCols); - for(int k=0; k(rhsCols-k, NbColsAtOnce); - tmp.leftCols(actualCols) = m_rhs.middleCols(k,actualCols); - tmpX.leftCols(actualCols) = m_dec.solve(tmp.leftCols(actualCols)); - dst.middleCols(k,actualCols) = tmpX.leftCols(actualCols).sparseView(); - } - } - const DecompositionType& m_dec; - typename Rhs::Nested m_rhs; -}; - -#define EIGEN_MAKE_SPARSE_SOLVE_HELPERS(DecompositionType,Rhs) \ - typedef typename DecompositionType::MatrixType MatrixType; \ - typedef typename MatrixType::Scalar Scalar; \ - typedef typename MatrixType::RealScalar RealScalar; \ - typedef typename MatrixType::Index Index; \ - typedef Eigen::internal::sparse_solve_retval_base Base; \ - using Base::dec; \ - using Base::rhs; \ - using Base::rows; \ - using Base::cols; \ - sparse_solve_retval(const DecompositionType& dec, const Rhs& rhs) \ - : Base(dec, rhs) {} - - - -template struct solve_retval_with_guess; - -template -struct traits > -{ - typedef typename DecompositionType::MatrixType MatrixType; - typedef Matrix ReturnType; -}; - -template struct solve_retval_with_guess - : public ReturnByValue > -{ - typedef typename DecompositionType::Index Index; - - solve_retval_with_guess(const DecompositionType& dec, const Rhs& rhs, const Guess& guess) - : m_dec(dec), m_rhs(rhs), m_guess(guess) - {} - - inline Index rows() const { return m_dec.cols(); } - inline Index cols() const { return m_rhs.cols(); } - - template inline void evalTo(Dest& dst) const - { - dst = m_guess; - m_dec._solveWithGuess(m_rhs,dst); - } - - protected: - const DecompositionType& m_dec; - const typename Rhs::Nested m_rhs; - const typename Guess::Nested m_guess; -}; - -} // namepsace internal - -} // end namespace Eigen - -#endif // EIGEN_TEST_EVALUATORS - -#endif // EIGEN_SPARSE_SOLVE_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 075b8d3de..530e9e4e1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -139,11 +139,6 @@ endif(TEST_LIB) set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official") add_custom_target(BuildOfficial) -option(EIGEN_TEST_NO_EVALUATORS "Disable evaluators in unit tests" OFF) -if(EIGEN_TEST_NO_EVALUATORS) - add_definitions("-DEIGEN_TEST_NO_EVALUATORS=1") -endif(EIGEN_TEST_NO_EVALUATORS) - ei_add_test(meta) ei_add_test(sizeof) ei_add_test(dynalloc) diff --git a/test/evaluators.cpp b/test/evaluators.cpp index 2ca453b1c..f41968da8 100644 --- a/test/evaluators.cpp +++ b/test/evaluators.cpp @@ -1,16 +1,4 @@ -#ifndef EIGEN_ENABLE_EVALUATORS -#define EIGEN_ENABLE_EVALUATORS -#endif - -#ifdef EIGEN_TEST_EVALUATORS -#undef EIGEN_TEST_EVALUATORS -#endif - -#ifdef EIGEN_TEST_NO_EVALUATORS -#undef EIGEN_TEST_NO_EVALUATORS -#endif - #include "main.h" namespace Eigen { diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp index 976e21e37..048f7255a 100644 --- a/test/mixingtypes.cpp +++ b/test/mixingtypes.cpp @@ -53,12 +53,10 @@ template void mixingtypes(int size = SizeAtCompileType) mf+mf; VERIFY_RAISES_ASSERT(mf+md); VERIFY_RAISES_ASSERT(mf+mcf); -#ifndef EIGEN_TEST_EVALUATORS - // they do not even compile when using evaluators - VERIFY_RAISES_ASSERT(vf=vd); - VERIFY_RAISES_ASSERT(vf+=vd); - VERIFY_RAISES_ASSERT(mcd=md); -#endif + // the following do not even compile since the introduction of evaluators +// VERIFY_RAISES_ASSERT(vf=vd); +// VERIFY_RAISES_ASSERT(vf+=vd); +// VERIFY_RAISES_ASSERT(mcd=md); // check scalar products VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp index 114dd5e41..6e772c70f 100644 --- a/test/nesting_ops.cpp +++ b/test/nesting_ops.cpp @@ -11,12 +11,7 @@ template void run_nesting_ops(const MatrixType& _m) { -#ifndef EIGEN_TEST_EVALUATORS - // TODO, with evaluator, the following is not correct anymore: - typename MatrixType::Nested m(_m); -#else typename internal::nested_eval::type m(_m); -#endif // Make really sure that we are in debug mode! VERIFY_RAISES_ASSERT(eigen_assert(false)); diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 6cd5a9a8c..5eea9edfd 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -71,10 +71,7 @@ template void sparse_vector(int rows, int cols) VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2)); VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2)); -#ifdef EIGEN_TEST_EVALUATORS - // the following did not compiled without evaluators VERIFY_IS_APPROX(m1*v2, refM1*refV2); -#endif VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2)); int i = internal::random(0,rows-1); VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i))); diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp index 303eb6cf0..2f839cf51 100644 --- a/test/vectorization_logic.cpp +++ b/test/vectorization_logic.cpp @@ -45,22 +45,14 @@ std::string demangle_flags(int f) template bool test_assign(const Dst&, const Src&, int traversal, int unrolling) { -#ifdef EIGEN_TEST_EVALUATORS typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; -#else - typedef internal::assign_traits traits; -#endif bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; -#ifdef EIGEN_TEST_EVALUATORS std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; -#endif std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; -#ifdef EIGEN_TEST_EVALUATORS std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; -#endif traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) << " got " << demangle_traversal(traits::Traversal) << "\n"; @@ -73,22 +65,14 @@ bool test_assign(const Dst&, const Src&, int traversal, int unrolling) template bool test_assign(int traversal, int unrolling) { -#ifdef EIGEN_TEST_EVALUATORS typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; -#else - typedef internal::assign_traits traits; -#endif bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; -#ifdef EIGEN_TEST_EVALUATORS std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; -#endif std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; -#ifdef EIGEN_TEST_EVALUATORS std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; -#endif traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) << " got " << demangle_traversal(traits::Traversal) << "\n"; @@ -101,19 +85,13 @@ bool test_assign(int traversal, int unrolling) template bool test_redux(const Xpr&, int traversal, int unrolling) { -#ifdef EIGEN_TEST_EVALUATORS typedef internal::redux_traits,internal::redux_evaluator > traits; -#else - typedef internal::redux_traits,Xpr> traits; -#endif bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { std::cerr << demangle_flags(Xpr::Flags) << std::endl; -#ifdef EIGEN_TEST_EVALUATORS std::cerr << demangle_flags(internal::evaluator::Flags) << std::endl; -#endif traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) diff --git a/unsupported/Eigen/IterativeSolvers b/unsupported/Eigen/IterativeSolvers index aa15403db..ff0d59b6e 100644 --- a/unsupported/Eigen/IterativeSolvers +++ b/unsupported/Eigen/IterativeSolvers @@ -24,9 +24,6 @@ */ //@{ -#include "../../Eigen/src/misc/Solve.h" -#include "../../Eigen/src/misc/SparseSolve.h" - #ifndef EIGEN_MPL2_ONLY #include "src/IterativeSolvers/IterationController.h" #include "src/IterativeSolvers/ConstrainedConjGrad.h" diff --git a/unsupported/Eigen/SparseExtra b/unsupported/Eigen/SparseExtra index b5597902a..819cffa27 100644 --- a/unsupported/Eigen/SparseExtra +++ b/unsupported/Eigen/SparseExtra @@ -37,9 +37,6 @@ */ -#include "../../Eigen/src/misc/Solve.h" -#include "../../Eigen/src/misc/SparseSolve.h" - #include "src/SparseExtra/DynamicSparseMatrix.h" #include "src/SparseExtra/BlockOfDynamicSparseMatrix.h" #include "src/SparseExtra/RandomSetter.h" diff --git a/unsupported/Eigen/src/IterativeSolvers/DGMRES.h b/unsupported/Eigen/src/IterativeSolvers/DGMRES.h index fe0bfd948..0e1b7d977 100644 --- a/unsupported/Eigen/src/IterativeSolvers/DGMRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/DGMRES.h @@ -139,24 +139,6 @@ class DGMRES : public IterativeSolverBase > ~DGMRES() {} -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const internal::solve_retval_with_guess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "DGMRES is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "DGMRES::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval_with_guess - (*this, b.derived(), x0); - } -#endif - /** \internal */ template void _solve_with_guess_impl(const Rhs& b, Dest& x) const @@ -525,23 +507,5 @@ int DGMRES<_MatrixType, _Preconditioner>::dgmresApplyDeflation(const RhsType &x, return 0; } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - - template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef DGMRES<_MatrixType, _Preconditioner> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; -} // end namespace internal -#endif - } // end namespace Eigen #endif diff --git a/unsupported/Eigen/src/IterativeSolvers/GMRES.h b/unsupported/Eigen/src/IterativeSolvers/GMRES.h index fd76a9d2c..cd15ce0bf 100644 --- a/unsupported/Eigen/src/IterativeSolvers/GMRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/GMRES.h @@ -316,24 +316,6 @@ public: */ void set_restart(const int restart) { m_restart=restart; } -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const internal::solve_retval_with_guess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "GMRES is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "GMRES::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval_with_guess - (*this, b.derived(), x0); - } -#endif - /** \internal */ template void _solve_with_guess_impl(const Rhs& b, Dest& x) const @@ -367,24 +349,6 @@ protected: }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - - template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef GMRES<_MatrixType, _Preconditioner> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif } // end namespace Eigen #endif // EIGEN_GMRES_H diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h index 1ee1c89b2..dd43de6b3 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h @@ -106,18 +106,6 @@ class IncompleteCholesky : public SparseSolverBase inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_factorizationIsOk && "IncompleteLLT did not succeed"); - eigen_assert(m_isInitialized && "IncompleteLLT is not initialized."); - eigen_assert(cols()==b.rows() - && "IncompleteLLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif protected: SparseMatrix m_L; // The lower part stored in CSC @@ -263,25 +251,6 @@ inline void IncompleteCholesky::updateList(const Idx } } -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef IncompleteCholesky<_Scalar, _UpLo, OrderingType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -} // end namespace internal -#endif - } // end namespace Eigen #endif diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h index e86f65644..7d08c3515 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h @@ -81,40 +81,10 @@ class IncompleteLU : public SparseSolverBase > x = m_lu.template triangularView().solve(x); } -#ifndef EIGEN_TEST_EVALUATORS - template inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "IncompleteLU is not initialized."); - eigen_assert(cols()==b.rows() - && "IncompleteLU::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } -#endif - protected: FactorType m_lu; }; -#ifndef EIGEN_TEST_EVALUATORS -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef IncompleteLU<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } -}; - -} // end namespace internal -#endif - } // end namespace Eigen #endif // EIGEN_INCOMPLETE_LU_H diff --git a/unsupported/Eigen/src/IterativeSolvers/MINRES.h b/unsupported/Eigen/src/IterativeSolvers/MINRES.h index 28d5c692d..aaf42c78a 100644 --- a/unsupported/Eigen/src/IterativeSolvers/MINRES.h +++ b/unsupported/Eigen/src/IterativeSolvers/MINRES.h @@ -246,24 +246,6 @@ namespace Eigen { /** Destructor. */ ~MINRES(){} -#ifndef EIGEN_TEST_EVALUATORS - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A - * \a x0 as an initial solution. - * - * \sa compute() - */ - template - inline const internal::solve_retval_with_guess - solveWithGuess(const MatrixBase& b, const Guess& x0) const - { - eigen_assert(m_isInitialized && "MINRES is not initialized."); - eigen_assert(Base::rows()==b.rows() - && "MINRES::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval_with_guess - (*this, b.derived(), x0); - } -#endif - /** \internal */ template void _solve_with_guess_impl(const Rhs& b, Dest& x) const @@ -296,25 +278,6 @@ namespace Eigen { protected: }; - -#ifndef EIGEN_TEST_EVALUATORS - namespace internal { - - template - struct solve_retval, Rhs> - : solve_retval_base, Rhs> - { - typedef MINRES<_MatrixType,_UpLo,_Preconditioner> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve_impl(rhs(),dst); - } - }; - - } // end namespace internal -#endif } // end namespace Eigen diff --git a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h index 4210df68a..e4dc1c1de 100644 --- a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h +++ b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h @@ -352,7 +352,6 @@ class DynamicSparseMatrix::ReverseInnerIterator : public const Index m_outer; }; -#ifdef EIGEN_ENABLE_EVALUATORS namespace internal { template @@ -382,7 +381,6 @@ struct evaluator > }; } -#endif } // end namespace Eigen diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 970a05bbd..e45efbd39 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -6,10 +6,6 @@ include_directories(../../test ../../unsupported ../../Eigen ${CMAKE_CURRENT_BINARY_DIR}/../../test) -if(EIGEN_TEST_NO_EVALUATORS) - add_definitions("-DEIGEN_TEST_NO_EVALUATORS=1") -endif(EIGEN_TEST_NO_EVALUATORS) - find_package(GoogleHash) if(GOOGLEHASH_FOUND) add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT") @@ -33,22 +29,18 @@ endif(ADOLC_FOUND) ei_add_test(NonLinearOptimization) ei_add_test(NumericalDiff) -if(EIGEN_TEST_NO_EVALUATORS) -ei_add_test(autodiff_scalar) -ei_add_test(autodiff) -endif() +# TODO ei_add_test(autodiff_scalar) +# TODO ei_add_test(autodiff) if (NOT CMAKE_CXX_COMPILER MATCHES "clang\\+\\+$") ei_add_test(BVH) endif() -if(EIGEN_TEST_NO_EVALUATORS) -ei_add_test(matrix_exponential) -ei_add_test(matrix_function) -ei_add_test(matrix_power) -ei_add_test(matrix_square_root) -ei_add_test(alignedvector3) -endif() +# TODO ei_add_test(matrix_exponential) +# TODO ei_add_test(matrix_function) +# TODO ei_add_test(matrix_power) +# TODO ei_add_test(matrix_square_root) +# TODO ei_add_test(alignedvector3) ei_add_test(FFT) @@ -101,9 +93,7 @@ ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) ei_add_test(bdcsvd) -if(EIGEN_TEST_NO_EVALUATORS) -ei_add_test(kronecker_product) -endif() +# TODO ei_add_test(kronecker_product) option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF) if(EIGEN_TEST_CXX11) -- cgit v1.2.3 From 060e835ee9f7a3abb9ff3d9f2522027bf2f98efe Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 17:30:21 +0200 Subject: Add evaluator for the experimental AlignedVector3 --- unsupported/Eigen/AlignedVector3 | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index 7b45e6cce..cd5f49edb 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -57,6 +57,9 @@ template class AlignedVector3 inline Index rows() const { return 3; } inline Index cols() const { return 1; } + + Scalar* data() { return m_coeffs.data(); } + const Scalar* data() const { return m_coeffs.data(); } inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); } @@ -183,6 +186,29 @@ template class AlignedVector3 } }; +namespace internal { + +template +struct evaluator > + : evaluator,Aligned> >::type +{ + typedef AlignedVector3 XprType; + typedef Map,Aligned> MapType; + typedef typename evaluator::type Base; + + typedef evaluator type; + typedef evaluator nestedType; + + evaluator(const XprType &m) : Base(MapType(m.data())), m_map(m.data()) + { + ::new (static_cast(this)) Base(m_map); + } + + const MapType m_map; +}; + +} + //@} } -- cgit v1.2.3 From 62bce6e5e6da71dd8d85ae229d24b9f9f13d1681 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 17:31:17 +0200 Subject: Make MatrixFunction use nested_eval instead of nested --- unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h | 5 +++-- unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h | 11 ++++++----- unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h | 11 ++++++----- unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h | 8 +++++--- unsupported/test/CMakeLists.txt | 10 +++++----- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 160120d03..9e0545660 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -392,14 +392,15 @@ template struct MatrixExponentialReturnValue template inline void evalTo(ResultType& result) const { - internal::matrix_exp_compute(m_src, result); + const typename internal::nested_eval::type tmp(m_src); + internal::matrix_exp_compute(tmp, result); } Index rows() const { return m_src.rows(); } Index cols() const { return m_src.cols(); } protected: - const typename internal::nested::type m_src; + const typename internal::nested::type m_src; }; namespace internal { diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h index a35c11be5..b68aae5e8 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h @@ -485,7 +485,7 @@ template class MatrixFunctionReturnValue typedef typename internal::stem_function::type StemFunction; protected: - typedef typename internal::nested::type DerivedNested; + typedef typename internal::nested::type DerivedNested; public: @@ -503,18 +503,19 @@ template class MatrixFunctionReturnValue template inline void evalTo(ResultType& result) const { - typedef typename internal::remove_all::type DerivedNestedClean; - typedef internal::traits Traits; + typedef typename internal::nested_eval::type NestedEvalType; + typedef typename internal::remove_all::type NestedEvalTypeClean; + typedef internal::traits Traits; static const int RowsAtCompileTime = Traits::RowsAtCompileTime; static const int ColsAtCompileTime = Traits::ColsAtCompileTime; - static const int Options = DerivedNestedClean::Options; + static const int Options = NestedEvalTypeClean::Options; typedef std::complex::Real> ComplexScalar; typedef Matrix DynMatrixType; typedef internal::MatrixFunctionAtomic AtomicType; AtomicType atomic(m_f); - internal::matrix_function_compute::run(m_A, atomic, result); + internal::matrix_function_compute::run(m_A, atomic, result); } Index rows() const { return m_A.rows(); } diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h b/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h index d46ccc145..42b60b9b1 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h @@ -310,7 +310,7 @@ public: typedef typename Derived::Index Index; protected: - typedef typename internal::nested::type DerivedNested; + typedef typename internal::nested::type DerivedNested; public: @@ -327,17 +327,18 @@ public: template inline void evalTo(ResultType& result) const { - typedef typename internal::remove_all::type DerivedNestedClean; - typedef internal::traits Traits; + typedef typename internal::nested_eval::type DerivedEvalType; + typedef typename internal::remove_all::type DerivedEvalTypeClean; + typedef internal::traits Traits; static const int RowsAtCompileTime = Traits::RowsAtCompileTime; static const int ColsAtCompileTime = Traits::ColsAtCompileTime; - static const int Options = DerivedNestedClean::Options; + static const int Options = DerivedEvalTypeClean::Options; typedef std::complex::Real> ComplexScalar; typedef Matrix DynMatrixType; typedef internal::MatrixLogarithmAtomic AtomicType; AtomicType atomic; - internal::matrix_function_compute::run(m_A, atomic, result); + internal::matrix_function_compute::run(m_A, atomic, result); } Index rows() const { return m_A.rows(); } diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h b/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h index 8ca4f4864..3a4d6eb3f 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h @@ -320,7 +320,7 @@ template class MatrixSquareRootReturnValue { protected: typedef typename Derived::Index Index; - typedef typename internal::nested::type DerivedNested; + typedef typename internal::nested::type DerivedNested; public: /** \brief Constructor. @@ -338,8 +338,10 @@ template class MatrixSquareRootReturnValue template inline void evalTo(ResultType& result) const { - typedef typename internal::remove_all::type DerivedNestedClean; - internal::matrix_sqrt_compute::run(m_src, result); + typedef typename internal::nested_eval::type DerivedEvalType; + typedef typename internal::remove_all::type DerivedEvalTypeClean; + DerivedEvalType tmp(m_src); + internal::matrix_sqrt_compute::run(tmp, result); } Index rows() const { return m_src.rows(); } diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index e45efbd39..7e2186d2d 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -36,11 +36,11 @@ if (NOT CMAKE_CXX_COMPILER MATCHES "clang\\+\\+$") ei_add_test(BVH) endif() -# TODO ei_add_test(matrix_exponential) -# TODO ei_add_test(matrix_function) -# TODO ei_add_test(matrix_power) -# TODO ei_add_test(matrix_square_root) -# TODO ei_add_test(alignedvector3) +ei_add_test(matrix_exponential) +ei_add_test(matrix_function) +ei_add_test(matrix_power) +ei_add_test(matrix_square_root) +ei_add_test(alignedvector3) ei_add_test(FFT) -- cgit v1.2.3 From 2ae20d558b33653b8ef2fe17255ed171997bcf79 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 22:08:49 +0200 Subject: Update KroneckerProduct wrt evaluator changes --- .../src/KroneckerProduct/KroneckerTensorProduct.h | 36 ++++++++++++++++++---- unsupported/test/CMakeLists.txt | 2 +- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h index ca66d4d89..72e25db19 100644 --- a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h @@ -154,16 +154,41 @@ void KroneckerProductSparse::evalTo(Dest& dst) const dst.resize(this->rows(), this->cols()); dst.resizeNonZeros(0); + // 1 - evaluate the operands if needed: + typedef typename internal::nested_eval::type Lhs1; + typedef typename internal::remove_all::type Lhs1Cleaned; + const Lhs1 lhs1(m_A); + typedef typename internal::nested_eval::type Rhs1; + typedef typename internal::remove_all::type Rhs1Cleaned; + const Rhs1 rhs1(m_B); + + // 2 - construct a SparseView for dense operands + typedef typename internal::conditional::StorageKind,Sparse>::value, Lhs1, SparseView >::type Lhs2; + typedef typename internal::remove_all::type Lhs2Cleaned; + const Lhs2 lhs2(lhs1); + typedef typename internal::conditional::StorageKind,Sparse>::value, Rhs1, SparseView >::type Rhs2; + typedef typename internal::remove_all::type Rhs2Cleaned; + const Rhs2 rhs2(rhs1); + + // 3 - construct respective evaluators + typedef typename internal::evaluator::type LhsEval; + LhsEval lhsEval(lhs2); + typedef typename internal::evaluator::type RhsEval; + RhsEval rhsEval(rhs2); + + typedef typename LhsEval::InnerIterator LhsInnerIterator; + typedef typename RhsEval::InnerIterator RhsInnerIterator; + // compute number of non-zeros per innervectors of dst { VectorXi nnzA = VectorXi::Zero(Dest::IsRowMajor ? m_A.rows() : m_A.cols()); for (Index kA=0; kA < m_A.outerSize(); ++kA) - for (typename Lhs::InnerIterator itA(m_A,kA); itA; ++itA) + for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) nnzA(Dest::IsRowMajor ? itA.row() : itA.col())++; VectorXi nnzB = VectorXi::Zero(Dest::IsRowMajor ? m_B.rows() : m_B.cols()); for (Index kB=0; kB < m_B.outerSize(); ++kB) - for (typename Rhs::InnerIterator itB(m_B,kB); itB; ++itB) + for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) nnzB(Dest::IsRowMajor ? itB.row() : itB.col())++; Matrix nnzAB = nnzB * nnzA.transpose(); @@ -174,9 +199,9 @@ void KroneckerProductSparse::evalTo(Dest& dst) const { for (Index kB=0; kB < m_B.outerSize(); ++kB) { - for (typename Lhs::InnerIterator itA(m_A,kA); itA; ++itA) + for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) { - for (typename Rhs::InnerIterator itB(m_B,kB); itB; ++itB) + for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) { const Index i = itA.row() * Br + itB.row(), j = itA.col() * Bc + itB.col(); @@ -201,8 +226,7 @@ struct traits > Rows = size_at_compile_time::RowsAtCompileTime, traits::RowsAtCompileTime>::ret, Cols = size_at_compile_time::ColsAtCompileTime, traits::ColsAtCompileTime>::ret, MaxRows = size_at_compile_time::MaxRowsAtCompileTime, traits::MaxRowsAtCompileTime>::ret, - MaxCols = size_at_compile_time::MaxColsAtCompileTime, traits::MaxColsAtCompileTime>::ret, - CoeffReadCost = Lhs::CoeffReadCost + Rhs::CoeffReadCost + NumTraits::MulCost + MaxCols = size_at_compile_time::MaxColsAtCompileTime, traits::MaxColsAtCompileTime>::ret }; typedef Matrix ReturnType; diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 7e2186d2d..04863a9ad 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -93,7 +93,7 @@ ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) ei_add_test(bdcsvd) -# TODO ei_add_test(kronecker_product) +ei_add_test(kronecker_product) option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF) if(EIGEN_TEST_CXX11) -- cgit v1.2.3 From e70506dd8f63241d92ebc3df2d9c01c9af5564c8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 18 Sep 2014 22:46:46 +0200 Subject: Fix inner-stride of AlignedVector3 --- unsupported/Eigen/AlignedVector3 | 16 +++++++--------- unsupported/test/CMakeLists.txt | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index cd5f49edb..35493e87b 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -60,6 +60,7 @@ template class AlignedVector3 Scalar* data() { return m_coeffs.data(); } const Scalar* data() const { return m_coeffs.data(); } + Index innerStride() const { return 1; } inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); } @@ -184,27 +185,24 @@ template class AlignedVector3 { return m_coeffs.template head<3>().isApprox(other,eps); } + + CoeffType& coeffs() { return m_coeffs; } + const CoeffType& coeffs() const { return m_coeffs; } }; namespace internal { template struct evaluator > - : evaluator,Aligned> >::type + : evaluator >::type { typedef AlignedVector3 XprType; - typedef Map,Aligned> MapType; - typedef typename evaluator::type Base; + typedef typename evaluator >::type Base; typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType &m) : Base(MapType(m.data())), m_map(m.data()) - { - ::new (static_cast(this)) Base(m_map); - } - - const MapType m_map; + evaluator(const XprType &m) : Base(m.coeffs()) {} }; } diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 04863a9ad..48b61cde0 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -29,8 +29,8 @@ endif(ADOLC_FOUND) ei_add_test(NonLinearOptimization) ei_add_test(NumericalDiff) -# TODO ei_add_test(autodiff_scalar) -# TODO ei_add_test(autodiff) +ei_add_test(autodiff_scalar) +ei_add_test(autodiff) if (NOT CMAKE_CXX_COMPILER MATCHES "clang\\+\\+$") ei_add_test(BVH) -- cgit v1.2.3 From 07c5500d709eb7914bd46a1c4b3629bf42783f1d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 19 Sep 2014 09:58:20 +0200 Subject: Introduce a compilation error when using the wrong InnerIterator type. --- Eigen/src/SparseCore/SparseMatrix.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 72368ebf3..9e7124ff2 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -887,6 +887,11 @@ class SparseMatrix::InnerIterator const Index m_outer; Index m_id; Index m_end; + private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const SparseMatrixBase&,Index outer); }; template -- cgit v1.2.3 From 755e77266f7c1005688654f7e7b070894c43bd18 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 19 Sep 2014 09:58:56 +0200 Subject: Fix SparseQR for row-major inputs. --- Eigen/src/SparseQR/SparseQR.h | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 1a6c84e00..6d85ea9be 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -284,9 +284,11 @@ template void SparseQR::analyzePattern(const MatrixType& mat) { eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR"); + // Copy to a column major matrix if the input is rowmajor + typename internal::conditional::type matCpy(mat); // Compute the column fill reducing ordering OrderingType ord; - ord(mat, m_perm_c); + ord(matCpy, m_perm_c); Index n = mat.cols(); Index m = mat.rows(); Index diagSize = (std::min)(m,n); @@ -299,7 +301,7 @@ void SparseQR::analyzePattern(const MatrixType& mat) // Compute the column elimination tree of the permuted matrix m_outputPerm_c = m_perm_c.inverse(); - internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); + internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); m_isEtreeOk = true; m_R.resize(m, n); @@ -337,21 +339,35 @@ void SparseQR::factorize(const MatrixType& mat) m_R.setZero(); m_Q.setZero(); + m_pmat = mat; if(!m_isEtreeOk) { m_outputPerm_c = m_perm_c.inverse(); - internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); + internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); m_isEtreeOk = true; } - - m_pmat = mat; + m_pmat.uncompress(); // To have the innerNonZeroPtr allocated + // Apply the fill-in reducing permutation lazily: - for (int i = 0; i < n; i++) { - Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i; - m_pmat.outerIndexPtr()[p] = mat.outerIndexPtr()[i]; - m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i]; + // If the input is row major, copy the original column indices, + // otherwise directly use the input matrix + // + IndexVector originalOuterIndicesCpy; + const Index *originalOuterIndices = mat.outerIndexPtr(); + if(MatrixType::IsRowMajor) + { + originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1); + originalOuterIndices = originalOuterIndicesCpy.data(); + } + + for (int i = 0; i < n; i++) + { + Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i; + m_pmat.outerIndexPtr()[p] = originalOuterIndices[i]; + m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i]; + } } /* Compute the default threshold as in MatLab, see: @@ -386,7 +402,7 @@ void SparseQR::factorize(const MatrixType& mat) // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k. // Note: if the diagonal entry does not exist, then its contribution must be explicitly added, // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found. - for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) + for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) { Index curIdx = nonzeroCol; if(itp) curIdx = itp.row(); @@ -544,7 +560,7 @@ void SparseQR::factorize(const MatrixType& mat) if(nonzeroCol Date: Fri, 19 Sep 2014 13:25:28 +0200 Subject: bug #100: add support for explicit scalar to Array conversion (as enable implicit conversion is much more tricky) --- Eigen/src/Core/Array.h | 18 ++++++++++++++++-- Eigen/src/Core/ArrayBase.h | 6 ++++++ Eigen/src/Core/PlainObjectBase.h | 36 +++++++++++++++++++++++++++++++++++- test/array.cpp | 25 +++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/Array.h b/Eigen/src/Core/Array.h index 28d6f1443..eaee8847b 100644 --- a/Eigen/src/Core/Array.h +++ b/Eigen/src/Core/Array.h @@ -74,6 +74,21 @@ class Array { return Base::operator=(other); } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() + */ + /* This overload is needed because the usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) + { + Base::setConstant(value); + return *this; + } /** Copies the value of the expression \a other into \c *this with automatic resizing. * @@ -99,7 +114,7 @@ class Array { return Base::_set(other); } - + /** Default constructor. * * For fixed-size matrices, does nothing. @@ -144,7 +159,6 @@ class Array } #endif - #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index 4e80634b9..48a0006d5 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -122,6 +122,12 @@ template class ArrayBase { internal::call_assignment(derived(), other.derived()); } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() */ + EIGEN_DEVICE_FUNC + Derived& operator=(const Scalar &value) + { Base::setConstant(value); return derived(); } EIGEN_DEVICE_FUNC Derived& operator+=(const Scalar& scalar); diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 11aec1552..3b0e56445 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -700,9 +700,12 @@ class PlainObjectBase : public internal::dense_xpr_base::type m_storage.data()[1] = Scalar(val1); } + // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, + // then the argument is meant to be the size of the object. template EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if::value,T>::type* = 0) + EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) + && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) { // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. const bool is_integer = NumTraits::IsInteger; @@ -710,6 +713,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) resize(size); } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitely converted) template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) @@ -718,6 +723,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type m_storage.data()[0] = val0; } + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Index& val0, @@ -730,18 +736,21 @@ class PlainObjectBase : public internal::dense_xpr_base::type m_storage.data()[0] = Scalar(val0); } + // Initialize a fixed size matrix from a pointer to raw data template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Scalar* data){ this->_set_noalias(ConstMapType(data)); } + // Initialize an arbitrary matrix from a dense expression template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ this->_set_noalias(other); } + // Initialize an arbitrary matrix from a generic Eigen expression template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ @@ -762,6 +771,31 @@ class PlainObjectBase : public internal::dense_xpr_base::type { this->derived() = r; } + + // For fixed -size arrays: + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, + typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) + { + Base::setConstant(val0); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) + { + Base::setConstant(val0); + } template friend struct internal::matrix_swap_impl; diff --git a/test/array.cpp b/test/array.cpp index 010fead2d..ac9be097d 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -81,6 +81,31 @@ template void array(const ArrayType& m) VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1); m3 = m1; VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1); + + // Conversion from scalar + VERIFY_IS_APPROX((m3 = s1), ArrayType::Constant(rows,cols,s1)); + VERIFY_IS_APPROX((m3 = 1), ArrayType::Constant(rows,cols,1)); + VERIFY_IS_APPROX((m3.topLeftCorner(rows,cols) = 1), ArrayType::Constant(rows,cols,1)); + typedef Array FixedArrayType; + FixedArrayType f1(s1); + VERIFY_IS_APPROX(f1, FixedArrayType::Constant(s1)); + FixedArrayType f2(numext::real(s1)); + VERIFY_IS_APPROX(f2, FixedArrayType::Constant(numext::real(s1))); + FixedArrayType f3((int)100*numext::real(s1)); + VERIFY_IS_APPROX(f3, FixedArrayType::Constant((int)100*numext::real(s1))); + f1.setRandom(); + FixedArrayType f4(f1.data()); + VERIFY_IS_APPROX(f4, f1); + + // Check possible conflicts with 1D ctor + typedef Array OneDArrayType; + OneDArrayType o1(rows); + VERIFY(o1.size()==rows); + OneDArrayType o4((int)rows); + VERIFY(o4.size()==rows); } template void comparisons(const ArrayType& m) -- cgit v1.2.3 From 03dd4dd91a5d8963f56eebe3b9d2eb924bc06e02 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 19 Sep 2014 15:25:48 +0200 Subject: Unify unit test for BDC and Jacobi SVD. This reveals some numerical issues in BDCSVD. --- test/jacobisvd.cpp | 413 ++----------------------------------- test/svd_common.h | 454 +++++++++++++++++++++++++++++++++++++++++ unsupported/test/bdcsvd.cpp | 233 ++++++--------------- unsupported/test/jacobisvd.cpp | 198 ------------------ unsupported/test/svd_common.h | 261 ----------------------- 5 files changed, 540 insertions(+), 1019 deletions(-) create mode 100644 test/svd_common.h delete mode 100644 unsupported/test/jacobisvd.cpp delete mode 100644 unsupported/test/svd_common.h diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index cd04db5be..bfcadce95 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.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) 2008-2014 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -14,273 +14,47 @@ #include "main.h" #include -template -void jacobisvd_check_full(const MatrixType& m, const JacobiSVD& svd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix MatrixUType; - typedef Matrix MatrixVType; - - MatrixType sigma = MatrixType::Zero(rows,cols); - sigma.diagonal() = svd.singularValues().template cast(); - MatrixUType u = svd.matrixU(); - MatrixVType v = svd.matrixV(); - - VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); - VERIFY_IS_UNITARY(u); - VERIFY_IS_UNITARY(v); -} - -template -void jacobisvd_compare_to_full(const MatrixType& m, - unsigned int computationOptions, - const JacobiSVD& referenceSvd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - Index diagSize = (std::min)(rows, cols); - - JacobiSVD svd(m, computationOptions); - - VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); - if(computationOptions & ComputeFullU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); - if(computationOptions & ComputeThinU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); - if(computationOptions & ComputeFullV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV()); - if(computationOptions & ComputeThinV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); -} - -template -void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef Matrix RhsType; - typedef Matrix SolutionType; - - RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); - JacobiSVD svd(m, computationOptions); - - if(internal::is_same::value) svd.setThreshold(1e-8); - else if(internal::is_same::value) svd.setThreshold(1e-4); - - SolutionType x = svd.solve(rhs); - - RealScalar residual = (m*x-rhs).norm(); - // Check that there is no significantly better solution in the neighborhood of x - if(!test_isMuchSmallerThan(residual,rhs.norm())) - { - // If the residual is very small, then we have an exact solution, so we are already good. - for(int k=0;k::epsilon(); - RealScalar residual_y = (m*y-rhs).norm(); - VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); - - y.row(k) = x.row(k).array() - 2*NumTraits::epsilon(); - residual_y = (m*y-rhs).norm(); - VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); - } - } - - // evaluate normal equation which works also for least-squares solutions - if(internal::is_same::value) - { - // This test is not stable with single precision. - // This is probably because squaring m signicantly affects the precision. - VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); - } - - // check minimal norm solutions - { - // generate a full-rank m x n problem with m MatrixType2; - typedef Matrix RhsType2; - typedef Matrix MatrixType2T; - Index rank = RankAtCompileTime2==Dynamic ? internal::random(1,cols) : Index(RankAtCompileTime2); - MatrixType2 m2(rank,cols); - int guard = 0; - do { - m2.setRandom(); - } while(m2.jacobiSvd().setThreshold(test_precision()).rank()!=rank && (++guard)<10); - VERIFY(guard<10); - RhsType2 rhs2 = RhsType2::Random(rank); - // use QR to find a reference minimal norm solution - HouseholderQR qr(m2.adjoint()); - Matrix tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView().adjoint().solve(rhs2); - tmp.conservativeResize(cols); - tmp.tail(cols-rank).setZero(); - SolutionType x21 = qr.householderQ() * tmp; - // now check with SVD - JacobiSVD svd2(m2, computationOptions); - SolutionType x22 = svd2.solve(rhs2); - VERIFY_IS_APPROX(m2*x21, rhs2); - VERIFY_IS_APPROX(m2*x22, rhs2); - VERIFY_IS_APPROX(x21, x22); - - // Now check with a rank deficient matrix - typedef Matrix MatrixType3; - typedef Matrix RhsType3; - Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random(rank+1,2*cols) : Index(RowsAtCompileTime3); - Matrix C = Matrix::Random(rows3,rank); - MatrixType3 m3 = C * m2; - RhsType3 rhs3 = C * rhs2; - JacobiSVD svd3(m3, computationOptions); - SolutionType x3 = svd3.solve(rhs3); - VERIFY_IS_APPROX(m3*x3, rhs3); - VERIFY_IS_APPROX(m3*x21, rhs3); - VERIFY_IS_APPROX(m2*x3, rhs2); - - VERIFY_IS_APPROX(x21, x3); - } -} - -template -void jacobisvd_test_all_computation_options(const MatrixType& m) -{ - if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) - return; - JacobiSVD fullSvd(m, ComputeFullU|ComputeFullV); - CALL_SUBTEST(( jacobisvd_check_full(m, fullSvd) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeFullU | ComputeFullV) )); - - #if defined __INTEL_COMPILER - // remark #111: statement is unreachable - #pragma warning disable 111 - #endif - if(QRPreconditioner == FullPivHouseholderQRPreconditioner) - return; - - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, 0, fullSvd) )); - - if (MatrixType::ColsAtCompileTime == Dynamic) { - // thin U/V are only available with dynamic number of columns - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU , fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeFullU | ComputeThinV) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeThinU | ComputeFullV) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeThinU | ComputeThinV) )); - - // test reconstruction - typedef typename MatrixType::Index Index; - Index diagSize = (std::min)(m.rows(), m.cols()); - JacobiSVD svd(m, ComputeThinU | ComputeThinV); - VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); - } -} +#define SVD_DEFAULT(M) JacobiSVD +#define SVD_FOR_MIN_NORM(M) JacobiSVD +#include "svd_common.h" +// Check all variants of JacobiSVD template void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) { MatrixType m = a; if(pickrandom) - { - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - Index diagSize = (std::min)(a.rows(), a.cols()); - RealScalar s = std::numeric_limits::max_exponent10/4; - s = internal::random(1,s); - Matrix d = Matrix::Random(diagSize); - for(Index k=0; k(-s,s)); - m = Matrix::Random(a.rows(),diagSize) * d.asDiagonal() * Matrix::Random(diagSize,a.cols()); - // cancel some coeffs - Index n = internal::random(0,m.size()-1); - for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); - } + svd_fill_random(m); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); + CALL_SUBTEST(( svd_test_all_computation_options >(m, true) )); // check full only + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); + if(m.rows()==m.cols()) + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); } template void jacobisvd_verify_assert(const MatrixType& m) { - typedef typename MatrixType::Scalar Scalar; + svd_verify_assert >(m); typedef typename MatrixType::Index Index; Index rows = m.rows(); Index cols = m.cols(); enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime }; - typedef Matrix RhsType; - - RhsType rhs(rows); - - JacobiSVD svd; - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.singularValues()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) MatrixType a = MatrixType::Zero(rows, cols); a.setZero(); - svd.compute(a, 0); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - svd.singularValues(); - VERIFY_RAISES_ASSERT(svd.solve(rhs)) if (ColsAtCompileTime == Dynamic) { - svd.compute(a, ComputeThinU); - svd.matrixU(); - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - - svd.compute(a, ComputeThinV); - svd.matrixV(); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - JacobiSVD svd_fullqr; VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV)) VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV)) VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV)) } - else - { - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) - } } template @@ -296,165 +70,17 @@ void jacobisvd_method() VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m); } -// work around stupid msvc error when constructing at compile time an expression that involves -// a division by zero, even if the numeric type has floating point -template -EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } - -// workaround aggressive optimization in ICC -template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } - -template -void jacobisvd_inf_nan() -{ - // all this function does is verify we don't iterate infinitely on nan/inf values - - JacobiSVD svd; - typedef typename MatrixType::Scalar Scalar; - Scalar some_inf = Scalar(1) / zero(); - VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); - svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); - - Scalar nan = std::numeric_limits::quiet_NaN(); - VERIFY(nan != nan); - svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV); - - MatrixType m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = some_inf; - svd.compute(m, ComputeFullU | ComputeFullV); - - m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = nan; - svd.compute(m, ComputeFullU | ComputeFullV); - - // regression test for bug 791 - m.resize(3,3); - m << 0, 2*NumTraits::epsilon(), 0.5, - 0, -0.5, 0, - nan, 0, 0; - svd.compute(m, ComputeFullU | ComputeFullV); - - m.resize(4,4); - m << 1, 0, 0, 0, - 0, 3, 1, 2e-308, - 1, 0, 1, nan, - 0, nan, nan, 0; - svd.compute(m, ComputeFullU | ComputeFullV); -} - -// Regression test for bug 286: JacobiSVD loops indefinitely with some -// matrices containing denormal numbers. -void jacobisvd_underoverflow() -{ -#if defined __INTEL_COMPILER -// shut up warning #239: floating point underflow -#pragma warning push -#pragma warning disable 239 -#endif - Matrix2d M; - M << -7.90884e-313, -4.94e-324, - 0, 5.60844e-313; - JacobiSVD svd; - svd.compute(M,ComputeFullU|ComputeFullV); - jacobisvd_check_full(M,svd); - - VectorXd value_set(9); - value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223; - Array4i id(0,0,0,0); - int k = 0; - do - { - M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); - svd.compute(M,ComputeFullU|ComputeFullV); - jacobisvd_check_full(M,svd); - - id(k)++; - if(id(k)>=value_set.size()) - { - while(k<3 && id(k)>=value_set.size()) id(++k)++; - id.head(k).setZero(); - k=0; - } - - } while((id svd3; - svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely - jacobisvd_check_full(M3,svd3); -} - -void jacobisvd_preallocate() -{ - Vector3f v(3.f, 2.f, 1.f); - MatrixXf m = v.asDiagonal(); - - internal::set_is_malloc_allowed(false); - VERIFY_RAISES_ASSERT(VectorXf tmp(10);) - JacobiSVD svd; - internal::set_is_malloc_allowed(true); - svd.compute(m); - VERIFY_IS_APPROX(svd.singularValues(), v); - - JacobiSVD svd2(3,3); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_RAISES_ASSERT(svd2.matrixU()); - VERIFY_RAISES_ASSERT(svd2.matrixV()); - svd2.compute(m, ComputeFullU | ComputeFullV); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - - JacobiSVD svd3(3,3,ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m, ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(true); -} - void test_jacobisvd() { CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) )); CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) )); CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) )); CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) )); + + svd_all_trivial_2x2(jacobisvd); + svd_all_trivial_2x2(jacobisvd); for(int i = 0; i < g_repeat; i++) { - Matrix2cd m; - m << 0, 1, - 0, 1; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - m << 1, 0, - 1, 0; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - - Matrix2d n; - n << 0, 0, - 0, 0; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - n << 0, 0, - 0, 1; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - CALL_SUBTEST_3(( jacobisvd() )); CALL_SUBTEST_4(( jacobisvd() )); CALL_SUBTEST_5(( jacobisvd >() )); @@ -473,8 +99,8 @@ void test_jacobisvd() (void) c; // Test on inf/nan matrix - CALL_SUBTEST_7( jacobisvd_inf_nan() ); - CALL_SUBTEST_10( jacobisvd_inf_nan() ); + CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); + CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); } CALL_SUBTEST_7(( jacobisvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); @@ -488,8 +114,7 @@ void test_jacobisvd() CALL_SUBTEST_7( JacobiSVD(10,10) ); // Check that preallocation avoids subsequent mallocs - CALL_SUBTEST_9( jacobisvd_preallocate() ); + CALL_SUBTEST_9( svd_preallocate() ); - // Regression check for bug 286 - CALL_SUBTEST_2( jacobisvd_underoverflow() ); + CALL_SUBTEST_2( svd_underoverflow() ); } diff --git a/test/svd_common.h b/test/svd_common.h new file mode 100644 index 000000000..4631939e5 --- /dev/null +++ b/test/svd_common.h @@ -0,0 +1,454 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SVD_DEFAULT +#error a macro SVD_DEFAULT(MatrixType) must be defined prior to including svd_common.h +#endif + +#ifndef SVD_FOR_MIN_NORM +#error a macro SVD_FOR_MIN_NORM(MatrixType) must be defined prior to including svd_common.h +#endif + +// Check that the matrix m is properly reconstructed and that the U and V factors are unitary +// The SVD must have already been computed. +template +void svd_check_full(const MatrixType& m, const SvdType& svd) +{ + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef typename MatrixType::Scalar Scalar; + typedef Matrix MatrixUType; + typedef Matrix MatrixVType; + + MatrixType sigma = MatrixType::Zero(rows,cols); + sigma.diagonal() = svd.singularValues().template cast(); + MatrixUType u = svd.matrixU(); + MatrixVType v = svd.matrixV(); + + VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); + VERIFY_IS_UNITARY(u); + VERIFY_IS_UNITARY(v); +} + +// Compare partial SVD defined by computationOptions to a full SVD referenceSvd +template +void svd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const SvdType& referenceSvd) +{ + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + Index diagSize = (std::min)(rows, cols); + + SvdType svd(m, computationOptions); + + VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); + if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); + if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); + if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV()); + if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); +} + +// +template +void svd_least_square(const MatrixType& m, unsigned int computationOptions) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + typedef Matrix SolutionType; + + RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); + SvdType svd(m, computationOptions); + + if(internal::is_same::value) svd.setThreshold(1e-8); + else if(internal::is_same::value) svd.setThreshold(1e-4); + + SolutionType x = svd.solve(rhs); + + RealScalar residual = (m*x-rhs).norm(); + // Check that there is no significantly better solution in the neighborhood of x + if(!test_isMuchSmallerThan(residual,rhs.norm())) + { + // If the residual is very small, then we have an exact solution, so we are already good. + for(int k=0;k::epsilon(); + RealScalar residual_y = (m*y-rhs).norm(); + VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); + + y.row(k) = x.row(k).array() - 2*NumTraits::epsilon(); + residual_y = (m*y-rhs).norm(); + VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); + } + } + + // evaluate normal equation which works also for least-squares solutions + if(internal::is_same::value) + { + // This test is not stable with single precision. + // This is probably because squaring m signicantly affects the precision. + VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); + } +} + +// check minimal norm solutions, the inoput matrix m is only used to recover problem size +template +void svd_min_norm(const MatrixType& m, unsigned int computationOptions) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index cols = m.cols(); + + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix SolutionType; + + // generate a full-rank m x n problem with m MatrixType2; + typedef Matrix RhsType2; + typedef Matrix MatrixType2T; + Index rank = RankAtCompileTime2==Dynamic ? internal::random(1,cols) : Index(RankAtCompileTime2); + MatrixType2 m2(rank,cols); + int guard = 0; + do { + m2.setRandom(); + } while(SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision()).rank()!=rank && (++guard)<10); + VERIFY(guard<10); + RhsType2 rhs2 = RhsType2::Random(rank); + // use QR to find a reference minimal norm solution + HouseholderQR qr(m2.adjoint()); + Matrix tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView().adjoint().solve(rhs2); + tmp.conservativeResize(cols); + tmp.tail(cols-rank).setZero(); + SolutionType x21 = qr.householderQ() * tmp; + // now check with SVD + SVD_FOR_MIN_NORM(MatrixType2) svd2(m2, computationOptions); + SolutionType x22 = svd2.solve(rhs2); + VERIFY_IS_APPROX(m2*x21, rhs2); + VERIFY_IS_APPROX(m2*x22, rhs2); + VERIFY_IS_APPROX(x21, x22); + + // Now check with a rank deficient matrix + typedef Matrix MatrixType3; + typedef Matrix RhsType3; + Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random(rank+1,2*cols) : Index(RowsAtCompileTime3); + Matrix C = Matrix::Random(rows3,rank); + MatrixType3 m3 = C * m2; + RhsType3 rhs3 = C * rhs2; + SVD_FOR_MIN_NORM(MatrixType3) svd3(m3, computationOptions); + SolutionType x3 = svd3.solve(rhs3); + VERIFY_IS_APPROX(m3*x3, rhs3); + VERIFY_IS_APPROX(m3*x21, rhs3); + VERIFY_IS_APPROX(m2*x3, rhs2); + + VERIFY_IS_APPROX(x21, x3); +} + +// Check full, compare_to_full, least_square, and min_norm for all possible compute-options +template +void svd_test_all_computation_options(const MatrixType& m, bool full_only) +{ +// if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) +// return; + SvdType fullSvd(m, ComputeFullU|ComputeFullV); + CALL_SUBTEST(( svd_check_full(m, fullSvd) )); + CALL_SUBTEST(( svd_least_square(m, ComputeFullU | ComputeFullV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeFullV) )); + + #if defined __INTEL_COMPILER + // remark #111: statement is unreachable + #pragma warning disable 111 + #endif + if(full_only) + return; + + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, 0, fullSvd) )); + + if (MatrixType::ColsAtCompileTime == Dynamic) { + // thin U/V are only available with dynamic number of columns + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU , fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) )); + + CALL_SUBTEST(( svd_least_square(m, ComputeFullU | ComputeThinV) )); + CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeFullV) )); + CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeThinV) )); + + CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeThinV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeFullV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeThinV) )); + + // test reconstruction + typedef typename MatrixType::Index Index; + Index diagSize = (std::min)(m.rows(), m.cols()); + SvdType svd(m, ComputeThinU | ComputeThinV); + VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); + } +} + +template +void svd_fill_random(MatrixType &m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + Index diagSize = (std::min)(m.rows(), m.cols()); + RealScalar s = std::numeric_limits::max_exponent10/4; + s = internal::random(1,s); + Matrix d = Matrix::Random(diagSize); + for(Index k=0; k(-s,s)); + m = Matrix::Random(m.rows(),diagSize) * d.asDiagonal() * Matrix::Random(diagSize,m.cols()); + // cancel some coeffs + Index n = internal::random(0,m.size()-1); + for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); +} + + +// work around stupid msvc error when constructing at compile time an expression that involves +// a division by zero, even if the numeric type has floating point +template +EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } + +// workaround aggressive optimization in ICC +template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } + +// all this function does is verify we don't iterate infinitely on nan/inf values +template +void svd_inf_nan() +{ + SvdType svd; + typedef typename MatrixType::Scalar Scalar; + Scalar some_inf = Scalar(1) / zero(); + VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); + svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); + + Scalar nan = std::numeric_limits::quiet_NaN(); + VERIFY(nan != nan); + svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV); + + MatrixType m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = some_inf; + svd.compute(m, ComputeFullU | ComputeFullV); + + m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = nan; + svd.compute(m, ComputeFullU | ComputeFullV); + + // regression test for bug 791 + m.resize(3,3); + m << 0, 2*NumTraits::epsilon(), 0.5, + 0, -0.5, 0, + nan, 0, 0; + svd.compute(m, ComputeFullU | ComputeFullV); + + m.resize(4,4); + m << 1, 0, 0, 0, + 0, 3, 1, 2e-308, + 1, 0, 1, nan, + 0, nan, nan, 0; + svd.compute(m, ComputeFullU | ComputeFullV); +} + +// Regression test for bug 286: JacobiSVD loops indefinitely with some +// matrices containing denormal numbers. +void svd_underoverflow() +{ +#if defined __INTEL_COMPILER +// shut up warning #239: floating point underflow +#pragma warning push +#pragma warning disable 239 +#endif + Matrix2d M; + M << -7.90884e-313, -4.94e-324, + 0, 5.60844e-313; + SVD_DEFAULT(Matrix2d) svd; + svd.compute(M,ComputeFullU|ComputeFullV); + svd_check_full(M,svd); + + // Check all 2x2 matrices made with the following coefficients: + VectorXd value_set(9); + value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223; + Array4i id(0,0,0,0); + int k = 0; + do + { + M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); + svd.compute(M,ComputeFullU|ComputeFullV); + svd_check_full(M,svd); + + id(k)++; + if(id(k)>=value_set.size()) + { + while(k<3 && id(k)>=value_set.size()) id(++k)++; + id.head(k).setZero(); + k=0; + } + + } while((id +void svd_all_trivial_2x2( void (*cb)(const MatrixType&,bool) ) +{ + MatrixType M; + VectorXd value_set(3); + value_set << 0, 1, -1; + Array4i id(0,0,0,0); + int k = 0; + do + { + M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); + + cb(M,false); + + id(k)++; + if(id(k)>=value_set.size()) + { + while(k<3 && id(k)>=value_set.size()) id(++k)++; + id.head(k).setZero(); + k=0; + } + + } while((id +void svd_verify_assert(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + RhsType rhs(rows); + SvdType svd; + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.singularValues()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + MatrixType a = MatrixType::Zero(rows, cols); + a.setZero(); + svd.compute(a, 0); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + svd.singularValues(); + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + + if (ColsAtCompileTime == Dynamic) + { + svd.compute(a, ComputeThinU); + svd.matrixU(); + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + svd.compute(a, ComputeThinV); + svd.matrixV(); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + } + else + { + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) + } +} + +#undef SVD_DEFAULT +#undef SVD_FOR_MIN_NORM diff --git a/unsupported/test/bdcsvd.cpp b/unsupported/test/bdcsvd.cpp index 115a649b0..4ad991522 100644 --- a/unsupported/test/bdcsvd.cpp +++ b/unsupported/test/bdcsvd.cpp @@ -10,204 +10,105 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/ -#include "svd_common.h" +// discard stack allocation as that too bypasses malloc +#define EIGEN_STACK_ALLOCATION_LIMIT 0 +#define EIGEN_RUNTIME_NO_MALLOC + +#include "main.h" +#include #include #include -// check if "svd" is the good image of "m" -template -void bdcsvd_check_full(const MatrixType& m, const BDCSVD& svd) -{ - svd_check_full< MatrixType, BDCSVD< MatrixType > >(m, svd); -} - -// Compare to a reference value -template -void bdcsvd_compare_to_full(const MatrixType& m, - unsigned int computationOptions, - const BDCSVD& referenceSvd) -{ - svd_compare_to_full< MatrixType, BDCSVD< MatrixType > >(m, computationOptions, referenceSvd); -} // end bdcsvd_compare_to_full +#define SVD_DEFAULT(M) BDCSVD +// #define SVD_FOR_MIN_NORM(M) BDCSVD +#define SVD_FOR_MIN_NORM(M) JacobiSVD +#include "../../test/svd_common.h" -template -void bdcsvd_solve(const MatrixType& m, unsigned int computationOptions) -{ - svd_solve< MatrixType, BDCSVD< MatrixType > >(m, computationOptions); -} // end template bdcsvd_solve - - -// test the computations options -template -void bdcsvd_test_all_computation_options(const MatrixType& m) -{ - BDCSVD fullSvd(m, ComputeFullU|ComputeFullV); - svd_test_computation_options_1< MatrixType, BDCSVD< MatrixType > >(m, fullSvd); - svd_test_computation_options_2< MatrixType, BDCSVD< MatrixType > >(m, fullSvd); -} // end bdcsvd_test_all_computation_options - - -// Call a test with all the computations options +// Check all variants of JacobiSVD template void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) { - MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; - bdcsvd_test_all_computation_options(m); -} // end template bdcsvd - - -// verify assert -template -void bdcsvd_verify_assert(const MatrixType& m) -{ - svd_verify_assert< MatrixType, BDCSVD< MatrixType > >(m); -}// end template bdcsvd_verify_assert + MatrixType m = a; + if(pickrandom) + svd_fill_random(m); + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); +} -// test weird values -template -void bdcsvd_inf_nan() -{ - svd_inf_nan< MatrixType, BDCSVD< MatrixType > >(); -}// end template bdcsvd_inf_nan - - - -void bdcsvd_preallocate() -{ - svd_preallocate< BDCSVD< MatrixXf > >(); -} // end bdcsvd_preallocate - +// template +// void bdcsvd_method() +// { +// enum { Size = MatrixType::RowsAtCompileTime }; +// typedef typename MatrixType::RealScalar RealScalar; +// typedef Matrix RealVecType; +// MatrixType m = MatrixType::Identity(); +// VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones()); +// VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU()); +// VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV()); +// VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m); +// } // compare the Singular values returned with Jacobi and Bdc template void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0) { - std::cout << "debut compare" << std::endl; MatrixType m = MatrixType::Random(a.rows(), a.cols()); BDCSVD bdc_svd(m); JacobiSVD jacobi_svd(m); VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues()); - if(computationOptions & ComputeFullU) - VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); - if(computationOptions & ComputeThinU) - VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); - if(computationOptions & ComputeFullV) - VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); - if(computationOptions & ComputeThinV) - VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); - std::cout << "fin compare" << std::endl; -} // end template compare_bdc_jacobi - - -// call the tests + if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); + if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); +} + void test_bdcsvd() { - // test of Dynamic defined Matrix (42, 42) of float - CALL_SUBTEST_11(( bdcsvd_verify_assert > - (Matrix(42,42)) )); - CALL_SUBTEST_11(( compare_bdc_jacobi > - (Matrix(42,42), 0) )); - CALL_SUBTEST_11(( bdcsvd > - (Matrix(42,42)) )); - - // test of Dynamic defined Matrix (50, 50) of double - CALL_SUBTEST_13(( bdcsvd_verify_assert > - (Matrix(50,50)) )); - CALL_SUBTEST_13(( compare_bdc_jacobi > - (Matrix(50,50), 0) )); - CALL_SUBTEST_13(( bdcsvd > - (Matrix(50, 50)) )); - - // test of Dynamic defined Matrix (22, 22) of complex double - CALL_SUBTEST_14(( bdcsvd_verify_assert,Dynamic,Dynamic> > - (Matrix,Dynamic,Dynamic>(22,22)) )); - CALL_SUBTEST_14(( compare_bdc_jacobi,Dynamic,Dynamic> > - (Matrix, Dynamic, Dynamic> (22,22), 0) )); - CALL_SUBTEST_14(( bdcsvd,Dynamic,Dynamic> > - (Matrix,Dynamic,Dynamic>(22, 22)) )); - - // test of Dynamic defined Matrix (10, 10) of int - //CALL_SUBTEST_15(( bdcsvd_verify_assert > - // (Matrix(10,10)) )); - //CALL_SUBTEST_15(( compare_bdc_jacobi > - // (Matrix(10,10), 0) )); - //CALL_SUBTEST_15(( bdcsvd > - // (Matrix(10, 10)) )); + CALL_SUBTEST_3(( svd_verify_assert >(Matrix3f()) )); + CALL_SUBTEST_4(( svd_verify_assert >(Matrix4d()) )); + CALL_SUBTEST_7(( svd_verify_assert >(MatrixXf(10,12)) )); + CALL_SUBTEST_8(( svd_verify_assert >(MatrixXcd(7,5)) )); +// svd_all_trivial_2x2(bdcsvd); +// svd_all_trivial_2x2(bdcsvd); - // test of Dynamic defined Matrix (8, 6) of double - - CALL_SUBTEST_16(( bdcsvd_verify_assert > - (Matrix(8,6)) )); - CALL_SUBTEST_16(( compare_bdc_jacobi > - (Matrix(8, 6), 0) )); - CALL_SUBTEST_16(( bdcsvd > - (Matrix(8, 6)) )); - - - - // test of Dynamic defined Matrix (36, 12) of float - CALL_SUBTEST_17(( compare_bdc_jacobi > - (Matrix(36, 12), 0) )); - CALL_SUBTEST_17(( bdcsvd > - (Matrix(36, 12)) )); - - // test of Dynamic defined Matrix (5, 8) of double - CALL_SUBTEST_18(( compare_bdc_jacobi > - (Matrix(5, 8), 0) )); - CALL_SUBTEST_18(( bdcsvd > - (Matrix(5, 8)) )); - - - // non regression tests - CALL_SUBTEST_3(( bdcsvd_verify_assert(Matrix3f()) )); - CALL_SUBTEST_4(( bdcsvd_verify_assert(Matrix4d()) )); - CALL_SUBTEST_7(( bdcsvd_verify_assert(MatrixXf(10,12)) )); - CALL_SUBTEST_8(( bdcsvd_verify_assert(MatrixXcd(7,5)) )); - - // SUBTESTS 1 and 2 on specifics matrix for(int i = 0; i < g_repeat; i++) { - Matrix2cd m; - m << 0, 1, - 0, 1; - CALL_SUBTEST_1(( bdcsvd(m, false) )); - m << 1, 0, - 1, 0; - CALL_SUBTEST_1(( bdcsvd(m, false) )); - - Matrix2d n; - n << 0, 0, - 0, 0; - CALL_SUBTEST_2(( bdcsvd(n, false) )); - n << 0, 0, - 0, 1; - CALL_SUBTEST_2(( bdcsvd(n, false) )); +// CALL_SUBTEST_3(( bdcsvd() )); +// CALL_SUBTEST_4(( bdcsvd() )); +// CALL_SUBTEST_5(( bdcsvd >() )); + + int r = internal::random(1, EIGEN_TEST_MAX_SIZE/2), + c = internal::random(1, EIGEN_TEST_MAX_SIZE/2); - // Statics matrix don't work with BDSVD yet - // bdc algo on a random 3x3 float matrix - // CALL_SUBTEST_3(( bdcsvd() )); - // bdc algo on a random 4x4 double matrix - // CALL_SUBTEST_4(( bdcsvd() )); - // bdc algo on a random 3x5 float matrix - // CALL_SUBTEST_5(( bdcsvd >() )); - - int r = internal::random(1, 30), - c = internal::random(1, 30); - CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); - CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); + TEST_SET_BUT_UNUSED_VARIABLE(r) + TEST_SET_BUT_UNUSED_VARIABLE(c) + + CALL_SUBTEST_6(( bdcsvd(Matrix(r,2)) )); + CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); + CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) )); + CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) )); + CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) )); + CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); + CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) )); (void) r; (void) c; // Test on inf/nan matrix - CALL_SUBTEST_7( bdcsvd_inf_nan() ); + CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); + CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); } - CALL_SUBTEST_7(( bdcsvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); - CALL_SUBTEST_8(( bdcsvd(MatrixXcd(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); + // test matrixbase method +// CALL_SUBTEST_1(( bdcsvd_method() )); +// CALL_SUBTEST_3(( bdcsvd_method() )); // Test problem size constructors CALL_SUBTEST_7( BDCSVD(10,10) ); -} // end test_bdcsvd + // Check that preallocation avoids subsequent mallocs + CALL_SUBTEST_9( svd_preallocate() ); + + CALL_SUBTEST_2( svd_underoverflow() ); +} + diff --git a/unsupported/test/jacobisvd.cpp b/unsupported/test/jacobisvd.cpp deleted file mode 100644 index b4e884eee..000000000 --- a/unsupported/test/jacobisvd.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "svd_common.h" - -template -void jacobisvd_check_full(const MatrixType& m, const JacobiSVD& svd) -{ - svd_check_full >(m, svd); -} - -template -void jacobisvd_compare_to_full(const MatrixType& m, - unsigned int computationOptions, - const JacobiSVD& referenceSvd) -{ - svd_compare_to_full >(m, computationOptions, referenceSvd); -} - - -template -void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions) -{ - svd_solve< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, computationOptions); -} - - - -template -void jacobisvd_test_all_computation_options(const MatrixType& m) -{ - - if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) - return; - - JacobiSVD< MatrixType, QRPreconditioner > fullSvd(m, ComputeFullU|ComputeFullV); - svd_test_computation_options_1< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, fullSvd); - - if(QRPreconditioner == FullPivHouseholderQRPreconditioner) - return; - svd_test_computation_options_2< MatrixType, JacobiSVD< MatrixType, QRPreconditioner > >(m, fullSvd); - -} - -template -void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) -{ - MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a; - - jacobisvd_test_all_computation_options(m); - jacobisvd_test_all_computation_options(m); - jacobisvd_test_all_computation_options(m); - jacobisvd_test_all_computation_options(m); -} - - -template -void jacobisvd_verify_assert(const MatrixType& m) -{ - - svd_verify_assert >(m); - - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - MatrixType a = MatrixType::Zero(rows, cols); - a.setZero(); - - if (ColsAtCompileTime == Dynamic) - { - JacobiSVD svd_fullqr; - VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV)) - VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV)) - VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV)) - } -} - -template -void jacobisvd_method() -{ - enum { Size = MatrixType::RowsAtCompileTime }; - typedef typename MatrixType::RealScalar RealScalar; - typedef Matrix RealVecType; - MatrixType m = MatrixType::Identity(); - VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones()); - VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU()); - VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV()); - VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m); -} - - - -template -void jacobisvd_inf_nan() -{ - svd_inf_nan >(); -} - - -// Regression test for bug 286: JacobiSVD loops indefinitely with some -// matrices containing denormal numbers. -void jacobisvd_bug286() -{ -#if defined __INTEL_COMPILER -// shut up warning #239: floating point underflow -#pragma warning push -#pragma warning disable 239 -#endif - Matrix2d M; - M << -7.90884e-313, -4.94e-324, - 0, 5.60844e-313; -#if defined __INTEL_COMPILER -#pragma warning pop -#endif - JacobiSVD svd; - svd.compute(M); // just check we don't loop indefinitely -} - - -void jacobisvd_preallocate() -{ - svd_preallocate< JacobiSVD >(); -} - -void test_jacobisvd() -{ - CALL_SUBTEST_11(( jacobisvd > - (Matrix(16, 6)) )); - - CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) )); - CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) )); - CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) )); - CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) )); - - for(int i = 0; i < g_repeat; i++) { - Matrix2cd m; - m << 0, 1, - 0, 1; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - m << 1, 0, - 1, 0; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - - Matrix2d n; - n << 0, 0, - 0, 0; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - n << 0, 0, - 0, 1; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - - CALL_SUBTEST_3(( jacobisvd() )); - CALL_SUBTEST_4(( jacobisvd() )); - CALL_SUBTEST_5(( jacobisvd >() )); - CALL_SUBTEST_6(( jacobisvd >(Matrix(10,2)) )); - - int r = internal::random(1, 30), - c = internal::random(1, 30); - CALL_SUBTEST_7(( jacobisvd(MatrixXf(r,c)) )); - CALL_SUBTEST_8(( jacobisvd(MatrixXcd(r,c)) )); - (void) r; - (void) c; - - // Test on inf/nan matrix - CALL_SUBTEST_7( jacobisvd_inf_nan() ); - } - - CALL_SUBTEST_7(( jacobisvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); - CALL_SUBTEST_8(( jacobisvd(MatrixXcd(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) )); - - - // test matrixbase method - CALL_SUBTEST_1(( jacobisvd_method() )); - CALL_SUBTEST_3(( jacobisvd_method() )); - - - // Test problem size constructors - CALL_SUBTEST_7( JacobiSVD(10,10) ); - - // Check that preallocation avoids subsequent mallocs - CALL_SUBTEST_9( jacobisvd_preallocate() ); - - // Regression check for bug 286 - CALL_SUBTEST_2( jacobisvd_bug286() ); -} diff --git a/unsupported/test/svd_common.h b/unsupported/test/svd_common.h deleted file mode 100644 index 6a96e7c74..000000000 --- a/unsupported/test/svd_common.h +++ /dev/null @@ -1,261 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2009 Benoit Jacob -// -// Copyright (C) 2013 Gauthier Brun -// Copyright (C) 2013 Nicolas Carre -// Copyright (C) 2013 Jean Ceccato -// Copyright (C) 2013 Pierre Zoppitelli -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// discard stack allocation as that too bypasses malloc -#define EIGEN_STACK_ALLOCATION_LIMIT 0 -#define EIGEN_RUNTIME_NO_MALLOC - -#include "main.h" -#include -#include - - -// check if "svd" is the good image of "m" -template -void svd_check_full(const MatrixType& m, const SVD& svd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix MatrixUType; - typedef Matrix MatrixVType; - - - MatrixType sigma = MatrixType::Zero(rows, cols); - sigma.diagonal() = svd.singularValues().template cast(); - MatrixUType u = svd.matrixU(); - MatrixVType v = svd.matrixV(); - VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); - VERIFY_IS_UNITARY(u); - VERIFY_IS_UNITARY(v); -} // end svd_check_full - - - -// Compare to a reference value -template -void svd_compare_to_full(const MatrixType& m, - unsigned int computationOptions, - const SVD& referenceSvd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - Index diagSize = (std::min)(rows, cols); - - SVD svd(m, computationOptions); - - VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); - if(computationOptions & ComputeFullU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); - if(computationOptions & ComputeThinU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); - if(computationOptions & ComputeFullV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV()); - if(computationOptions & ComputeThinV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); -} // end svd_compare_to_full - - - -template -void svd_solve(const MatrixType& m, unsigned int computationOptions) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef Matrix RhsType; - typedef Matrix SolutionType; - - RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); - SVD svd(m, computationOptions); - SolutionType x = svd.solve(rhs); - // evaluate normal equation which works also for least-squares solutions - VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); -} // end svd_solve - - -// test computations options -// 2 functions because Jacobisvd can return before the second function -template -void svd_test_computation_options_1(const MatrixType& m, const SVD& fullSvd) -{ - svd_check_full< MatrixType, SVD >(m, fullSvd); - svd_solve< MatrixType, SVD >(m, ComputeFullU | ComputeFullV); -} - - -template -void svd_test_computation_options_2(const MatrixType& m, const SVD& fullSvd) -{ - svd_compare_to_full< MatrixType, SVD >(m, ComputeFullU, fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, ComputeFullV, fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, 0, fullSvd); - - if (MatrixType::ColsAtCompileTime == Dynamic) { - // thin U/V are only available with dynamic number of columns - - svd_compare_to_full< MatrixType, SVD >(m, ComputeFullU|ComputeThinV, fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, ComputeThinV, fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU|ComputeFullV, fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU , fullSvd); - svd_compare_to_full< MatrixType, SVD >(m, ComputeThinU|ComputeThinV, fullSvd); - svd_solve(m, ComputeFullU | ComputeThinV); - svd_solve(m, ComputeThinU | ComputeFullV); - svd_solve(m, ComputeThinU | ComputeThinV); - - typedef typename MatrixType::Index Index; - Index diagSize = (std::min)(m.rows(), m.cols()); - SVD svd(m, ComputeThinU | ComputeThinV); - VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); - } -} - -template -void svd_verify_assert(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef Matrix RhsType; - RhsType rhs(rows); - SVD svd; - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.singularValues()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - MatrixType a = MatrixType::Zero(rows, cols); - a.setZero(); - svd.compute(a, 0); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - svd.singularValues(); - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - - if (ColsAtCompileTime == Dynamic) - { - svd.compute(a, ComputeThinU); - svd.matrixU(); - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - svd.compute(a, ComputeThinV); - svd.matrixV(); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - } - else - { - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) - } -} - -// work around stupid msvc error when constructing at compile time an expression that involves -// a division by zero, even if the numeric type has floating point -template -EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } - -// workaround aggressive optimization in ICC -template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } - - -template -void svd_inf_nan() -{ - // all this function does is verify we don't iterate infinitely on nan/inf values - - SVD svd; - typedef typename MatrixType::Scalar Scalar; - Scalar some_inf = Scalar(1) / zero(); - VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); - svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); - - Scalar some_nan = zero () / zero (); - VERIFY(some_nan != some_nan); - svd.compute(MatrixType::Constant(10,10,some_nan), ComputeFullU | ComputeFullV); - - MatrixType m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = some_inf; - svd.compute(m, ComputeFullU | ComputeFullV); - - m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = some_nan; - svd.compute(m, ComputeFullU | ComputeFullV); -} - - -template -void svd_preallocate() -{ - Vector3f v(3.f, 2.f, 1.f); - MatrixXf m = v.asDiagonal(); - - internal::set_is_malloc_allowed(false); - VERIFY_RAISES_ASSERT(VectorXf v(10);) - SVD svd; - internal::set_is_malloc_allowed(true); - svd.compute(m); - VERIFY_IS_APPROX(svd.singularValues(), v); - - SVD svd2(3,3); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_RAISES_ASSERT(svd2.matrixU()); - VERIFY_RAISES_ASSERT(svd2.matrixV()); - svd2.compute(m, ComputeFullU | ComputeFullV); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - - SVD svd3(3,3,ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m, ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(true); -} - - - - - -- cgit v1.2.3 From 60663a510a9d1c1dfb3518e95b495170ab4d66ba Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Fri, 19 Sep 2014 21:05:01 +0000 Subject: 32-bit floats/ints, 64-bit doubles pass packetmath tests, complex 32/64-bit remaining --- Eigen/src/Core/arch/AltiVec/Complex.h | 61 ++++----- Eigen/src/Core/arch/AltiVec/PacketMath.h | 221 ++++++++++++++++++++----------- 2 files changed, 171 insertions(+), 111 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index d90cfe0de..94ecec2de 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -7,8 +7,8 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef EIGEN_COMPLEX_ALTIVEC_H -#define EIGEN_COMPLEX_ALTIVEC_H +#ifndef EIGEN_COMPLEX32_ALTIVEC_H +#define EIGEN_COMPLEX32_ALTIVEC_H namespace Eigen { @@ -21,16 +21,6 @@ static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4f_ZERO_, (Packet4ui)p4 static Packet2ul p2ul_CONJ_XOR = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui)p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; #endif -static Packet16uc p16uc_COMPLEX_RE = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_IM = vec_sld(p16uc_DUPLICATE, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; -static Packet16uc p16uc_COMPLEX_REV = vec_sld(p16uc_REVERSE, p16uc_REVERSE, 8);//{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8);//{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_HI = (Packet16uc) vec_mergeh((Packet4ui)p16uc_COMPLEX_RE, (Packet4ui)p16uc_COMPLEX_IM);//{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_PSET_LO = (Packet16uc) vec_mergel((Packet4ui)p16uc_COMPLEX_RE, (Packet4ui)p16uc_COMPLEX_IM);//{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; -static Packet16uc p16uc_COMPLEX_MASK16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8);//{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; -static Packet16uc p16uc_COMPLEX_TRANSPOSE_0 = vec_add(p16uc_PSET_HI, p16uc_COMPLEX_MASK16);//{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; -static Packet16uc p16uc_COMPLEX_TRANSPOSE_1 = vec_add(p16uc_PSET_LO, p16uc_COMPLEX_MASK16);//{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; - //---------- float ---------- struct Packet2cf { @@ -71,7 +61,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pset1(const std::complex((const float *)&from); else res.v = ploadu((const float *)&from); - res.v = vec_perm(res.v, res.v, p16uc_PSET_HI); + res.v = vec_perm(res.v, res.v, p16uc_PSET64_HI); return res; } @@ -100,17 +90,24 @@ template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, con { Packet4f v1, v2; + std::cout << "a: " << a.v << ", b: " << b.v << std::endl; // Permute and multiply the real parts of a and b - v1 = vec_perm(a.v, a.v, p16uc_COMPLEX_RE); + v1 = vec_perm(a.v, a.v, p16uc_PSET32_WODD); + std::cout << "v1 = a(re): " << v1 << std::endl; // Get the imaginary parts of a - v2 = vec_perm(a.v, a.v, p16uc_COMPLEX_IM); + v2 = vec_perm(a.v, a.v, p16uc_PSET32_WEVEN); + std::cout << "v2 = a(im): " << v2 << std::endl; // multiply a_re * b v1 = vec_madd(v1, b.v, p4f_ZERO); + std::cout << "v1+ b : " << v1 << std::endl; // multiply a_im * b and get the conjugate result v2 = vec_madd(v2, b.v, p4f_ZERO); + std::cout << "v2+ b : " << v2 << std::endl; v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); + std::cout << "~v2 : " << v2 << std::endl; // permute back to a proper order - v2 = vec_perm(v2, v2, p16uc_COMPLEX_REV); + v2 = vec_perm(v2, v2, p16uc_COMPLEX32_REV); + std::cout << "v2 : " << v2 << std::endl; return Packet2cf(vec_add(v1, v2)); } @@ -144,7 +141,7 @@ template<> EIGEN_STRONG_INLINE std::complex pfirst(const Pack template<> EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) { Packet4f rev_a; - rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX_REV2); + rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX32_REV2); return Packet2cf(rev_a); } @@ -185,7 +182,11 @@ struct palign_impl { if (Offset==1) { +#ifdef _BIG_ENDIAN first.v = vec_sld(first.v, second.v, 8); +#else + first.v = vec_sld(second.v, first.v, 8); +#endif } } }; @@ -228,18 +229,18 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, con // TODO optimize it for AltiVec Packet2cf res = conj_helper().pmul(a,b); Packet4f s = vec_madd(b.v, b.v, p4f_ZERO); - return Packet2cf(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); + return Packet2cf(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX32_REV)))); } template<> EIGEN_STRONG_INLINE Packet2cf pcplxflip(const Packet2cf& x) { - return Packet2cf(vec_perm(x.v, x.v, p16uc_COMPLEX_REV)); + return Packet2cf(vec_perm(x.v, x.v, p16uc_COMPLEX32_REV)); } EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) { - Packet4f tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_0); - kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_1); + Packet4f tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_HI); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); kernel.packet[0].v = tmp; } @@ -289,7 +290,7 @@ template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex((const double *)&from); else res.v = ploadu((const double *)&from); - res.v = vec_perm(res.v, res.v, p16uc_PSET_HI); + res.v = vec_perm(res.v, res.v, p16uc_PSET64_HI); return res; } template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, DenseIndex stride) @@ -317,9 +318,9 @@ template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, con Packet2d a_re, a_im, v1, v2; // Permute and multiply the real parts of a and b - a_re = vec_perm(a.v, a.v, p16uc_PSET_HI); + a_re = vec_perm(a.v, a.v, p16uc_PSET64_HI); // Get the imaginary parts of a - a_im = vec_perm(a.v, a.v, p16uc_PSET_HI); + a_im = vec_perm(a.v, a.v, p16uc_PSET64_HI); // multiply a_re * b v1 = vec_madd(a_re, b.v, p2d_ZERO_); // multiply a_im * b and get the conjugate result @@ -353,7 +354,7 @@ template<> EIGEN_STRONG_INLINE std::complex pfirst(const Pac template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { Packet2d rev_a; - rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX_REV2); + rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX32_REV2); return Packet1cd(rev_a); } @@ -432,18 +433,18 @@ template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, con // TODO optimize it for AltiVec Packet1cd res = conj_helper().pmul(a,b); Packet2d s = vec_madd(b.v, b.v, p2d_ZERO_); - return Packet1cd(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX_REV)))); + return Packet1cd(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX32_REV)))); } template<> EIGEN_STRONG_INLINE Packet1cd pcplxflip(const Packet1cd& x) { - return Packet1cd(vec_perm(x.v, x.v, p16uc_COMPLEX_REV)); + return Packet1cd(vec_perm(x.v, x.v, p16uc_COMPLEX32_REV)); } EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) { - Packet2d tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_0); - kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_COMPLEX_TRANSPOSE_1); + Packet2d tmp = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_HI); + kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); kernel.packet[0].v = tmp; } @@ -451,4 +452,4 @@ EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) } // end namespace Eigen -#endif // EIGEN_COMPLEX_ALTIVEC_H +#endif // EIGEN_COMPLEX32_ALTIVEC_H diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 0489ad886..aea3e79dc 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -62,21 +62,6 @@ typedef __vector unsigned char Packet16uc; #define DST_CHAN 1 #define DST_CTRL(size, count, stride) (((size) << 24) | ((count) << 16) | (stride)) -// Handle endianness properly while loading constants -// Define global static constants: -#ifdef _BIG_ENDIAN -static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; -static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; -static Packet16uc p16uc_REVERSE = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; -static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); //{ 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15} -static Packet16uc p16uc_DUPLICATE = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7}; -#else -static Packet4f p4f_COUNTDOWN = { 3.0, 2.0, 1.0, 0.0 }; -static Packet4i p4i_COUNTDOWN = { 3, 2, 1, 0 }; -static Packet16uc p16uc_REVERSE = { 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15 }; -static Packet16uc p16uc_FORWARD = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; -static Packet16uc p16uc_DUPLICATE = { 4,5,6,7, 4,5,6,7, 0,1,2,3, 0,1,2,3 }; -#endif // _BIG_ENDIAN // These constants are endian-agnostic static _EIGEN_DECLARE_CONST_FAST_Packet4f(ZERO, 0); //{ 0.0, 0.0, 0.0, 0.0} @@ -87,6 +72,40 @@ static _EIGEN_DECLARE_CONST_FAST_Packet4i(MINUS1,-1); //{ -1, -1, -1, -1} static Packet4f p4f_ONE = vec_ctf(p4i_ONE, 0); //{ 1.0, 1.0, 1.0, 1.0} static Packet4f p4f_ZERO_ = (Packet4f) vec_sl((Packet4ui)p4i_MINUS1, (Packet4ui)p4i_MINUS1); //{ 0x80000000, 0x80000000, 0x80000000, 0x80000000} +static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; +static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; + +static Packet16uc p16uc_REVERSE32 = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3 }; +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 }; + +// Handle endianness properly while loading constants +// Define global static constants: +#ifdef _BIG_ENDIAN +static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; +static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; +static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; +#else +// Mask alignment +#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 +#define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) + +static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; +static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; +static Packet16uc p16uc_PSET32_WEVEN = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; +static Packet16uc p16uc_HALF64_0_16 = vec_sld(vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 0), (Packet16uc)p4i_ZERO, 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; + +#endif // _BIG_ENDIAN + +static Packet16uc p16uc_PSET64_HI = (Packet16uc) vec_mergeh((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; +static Packet16uc p16uc_PSET64_LO = (Packet16uc) vec_mergel((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; + +static Packet16uc p16uc_COMPLEX32_REV = vec_sld(p16uc_REVERSE32, p16uc_REVERSE32, 8); //{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; +static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; + +static Packet16uc p16uc_TRANSPOSE64_HI = vec_add(p16uc_PSET64_HI, p16uc_HALF64_0_16); //{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; +static Packet16uc p16uc_TRANSPOSE64_LO = vec_add(p16uc_PSET64_LO, p16uc_HALF64_0_16); //{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; + template<> struct packet_traits : default_packet_traits { typedef Packet4f type; @@ -121,7 +140,19 @@ template<> struct packet_traits : default_packet_traits template<> struct unpacket_traits { typedef float type; enum {size=4}; typedef Packet4f half; }; template<> struct unpacket_traits { typedef int type; enum {size=4}; typedef Packet4i half; }; -/* + +inline std::ostream & operator <<(std::ostream & s, const Packet16uc & v) +{ + union { + Packet16uc v; + unsigned char n[16]; + } vt; + vt.v = v; + for (int i=0; i< 16; i++) + s << (int)vt.n[i] << ", "; + return s; +} + inline std::ostream & operator <<(std::ostream & s, const Packet4f & v) { union { @@ -154,7 +185,7 @@ inline std::ostream & operator <<(std::ostream & s, const Packet4ui & v) s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; return s; } - +/* inline std::ostream & operator <<(std::ostream & s, const Packetbi & v) { union { @@ -164,8 +195,8 @@ inline std::ostream & operator <<(std::ostream & s, const Packetbi & v) vt.v = v; s << vt.n[0] << ", " << vt.n[1] << ", " << vt.n[2] << ", " << vt.n[3]; return s; -} -*/ +}*/ + // Need to define them first or we get specialization after instantiation errors template<> EIGEN_STRONG_INLINE Packet4f pload(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD return vec_ld(0, from); } @@ -370,12 +401,12 @@ template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) template<> EIGEN_STRONG_INLINE Packet4i ploadu(const int* from) { EIGEN_DEBUG_ALIGNED_LOAD - return (Packet4i) vec_vsx_ld((long)from & 15, from); // align the data + return (Packet4i) vec_vsx_ld((long)from & 15, (const int*) _EIGEN_ALIGNED_PTR(from)); } template<> EIGEN_STRONG_INLINE Packet4f ploadu(const float* from) { EIGEN_DEBUG_ALIGNED_LOAD - return (Packet4f) vec_vsx_ld((long)from & 15, from); // align the data + return (Packet4f) vec_vsx_ld((long)from & 15, (const float*) _EIGEN_ALIGNED_PTR(from)); } #endif @@ -384,16 +415,17 @@ template<> EIGEN_STRONG_INLINE Packet4f ploaddup(const float* from) Packet4f p; if((ptrdiff_t(from) % 16) == 0) p = pload(from); else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); + return vec_perm(p, p, p16uc_DUPLICATE32_HI); } template<> EIGEN_STRONG_INLINE Packet4i ploaddup(const int* from) { Packet4i p; if((ptrdiff_t(from) % 16) == 0) p = pload(from); else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); + return vec_perm(p, p, p16uc_DUPLICATE32_HI); } +#ifdef _BIG_ENDIAN template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE @@ -430,6 +462,19 @@ template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& f vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part } +#else +// We also need ot redefine little endian loading of Packet4i/Packet4f using VSX +template<> EIGEN_STRONG_INLINE void pstoreu(int* to, const Packet4i& from) +{ + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st(from, (long)to & 15, (int*) _EIGEN_ALIGNED_PTR(to)); +} +template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& from) +{ + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st(from, (long)to & 15, (float*) _EIGEN_ALIGNED_PTR(to)); +} +#endif template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } @@ -437,8 +482,8 @@ template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dst template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } -template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { return (Packet4f)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } -template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { return (Packet4i)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } +template<> EIGEN_STRONG_INLINE Packet4f preverse(const Packet4f& a) { return (Packet4f)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE32); } +template<> EIGEN_STRONG_INLINE Packet4i preverse(const Packet4i& a) { return (Packet4i)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE32); } template<> EIGEN_STRONG_INLINE Packet4f pabs(const Packet4f& a) { return vec_abs(a); } template<> EIGEN_STRONG_INLINE Packet4i pabs(const Packet4i& a) { return vec_abs(a); } @@ -485,7 +530,11 @@ template<> EIGEN_STRONG_INLINE int predux(const Packet4i& a) { Packet4i sum; sum = vec_sums(a, p4i_ZERO); +#ifdef _BIG_ENDIAN sum = vec_sld(sum, p4i_ZERO, 12); +#else + sum = vec_sld(p4i_ZERO, sum, 4); +#endif return pfirst(sum); } @@ -572,8 +621,25 @@ struct palign_impl { static EIGEN_STRONG_INLINE void run(Packet4f& first, const Packet4f& second) { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); +#ifdef _BIG_ENDIAN + switch (Offset % 4) { + case 1: + first = vec_sld(first, second, 4); break; + case 2: + first = vec_sld(first, second, 8); break; + case 3: + first = vec_sld(first, second, 12); break; + } +#else + switch (Offset % 4) { + case 1: + first = vec_sld(second, first, 12); break; + case 2: + first = vec_sld(second, first, 8); break; + case 3: + first = vec_sld(second, first, 4); break; + } +#endif } }; @@ -582,8 +648,25 @@ struct palign_impl { static EIGEN_STRONG_INLINE void run(Packet4i& first, const Packet4i& second) { - if (Offset!=0) - first = vec_sld(first, second, Offset*4); +#ifdef _BIG_ENDIAN + switch (Offset % 4) { + case 1: + first = vec_sld(first, second, 4); break; + case 2: + first = vec_sld(first, second, 8); break; + case 3: + first = vec_sld(first, second, 12); break; + } +#else + switch (Offset % 4) { + case 1: + first = vec_sld(second, first, 12); break; + case 2: + first = vec_sld(second, first, 8); break; + case 3: + first = vec_sld(second, first, 4); break; + } +#endif } }; @@ -625,24 +708,15 @@ static Packet2d p2l_ONE = { 1, 1 }; static Packet2d p2d_ONE = { 1.0, 1.0 }; static Packet2d p2d_ZERO = { 0.0, 0.0 }; static Packet2d p2d_ZERO_ = { (double) 0x8000000000000000, (double) 0x8000000000000000 }; -static Packet2d p2d_COUNTDOWN = { 1.0, 0.0 }; - -#ifdef _BIG_ENDIAN -static Packet16uc p16uc_SPLATQ1 = { 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_SPLATQ2 = { 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; -#else -static Packet16uc p16uc_SPLATQ1 = { 4,5,6,7, 0,1,2,3, 4,5,6,7, 0,1,3,4 }; -static Packet16uc p16uc_SPLATQ2 = { 12,13,14,15, 8,9,10,11, 12,13,14,15, 8,9,10,11 }; -#endif - +static Packet2d p2d_COUNTDOWN = { 0.0, 1.0 }; static EIGEN_STRONG_INLINE Packet2d vec_splat_dbl(Packet2d& a, int index) { switch (index) { case 0: - return (Packet2d) vec_perm(a, a, p16uc_SPLATQ1); + return (Packet2d) vec_perm(a, a, p16uc_PSET64_HI); case 1: - return (Packet2d) vec_perm(a, a, p16uc_SPLATQ2); + return (Packet2d) vec_perm(a, a, p16uc_PSET64_LO); } return a; } @@ -665,17 +739,17 @@ template<> struct packet_traits : default_packet_traits template<> struct unpacket_traits { typedef double type; enum {size=2}; typedef Packet2d half; }; -/* + inline std::ostream & operator <<(std::ostream & s, const Packet2d & v) { union { - Packetdf v; + Packet2d v; double n[2]; } vt; vt.v = v; s << vt.n[0] << ", " << vt.n[1]; return s; -}*/ +} // Need to define them first or we get specialization after instantiation errors template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return (Packet2d) vec_ld(0, (const float *) from); } //FIXME @@ -698,7 +772,7 @@ pbroadcast4(const double *a, a1 = vec_splat_dbl(a1, 1); a3 = pload(a+2); a2 = vec_splat_dbl(a3, 0); - a3 = vec_splat_dbl(a1, 1); + a3 = vec_splat_dbl(a3, 1); } template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, DenseIndex stride) { @@ -755,43 +829,30 @@ template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) { return vec_and(a, vec_nor(b, b)); } - template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD - return (Packet2d) vec_vsx_ld((int)((size_t)(from) & 15), (const float *)from); // align the data + return (Packet2d) vec_vsx_ld((long)from & 15, (const float*) _EIGEN_ALIGNED_PTR(from)); } template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) { Packet2d p; if((ptrdiff_t(from) % 16) == 0) p = pload(from); else p = ploadu(from); - return vec_perm(p, p, p16uc_DUPLICATE); + return vec_perm(p, p, p16uc_PSET64_HI); } template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { - EIGEN_DEBUG_UNALIGNED_STORE - // Taken from http://developer.apple.com/hardwaredrivers/ve/alignment.html - // Warning: not thread safe! - Packet16uc MSQ, LSQ, edges; - Packet16uc edgeAlign, align; - - MSQ = vec_ld(0, (unsigned char *)to); // most significant quadword - LSQ = vec_ld(15, (unsigned char *)to); // least significant quadword - edgeAlign = vec_lvsl(0, to); // permute map to extract edges - edges=vec_perm(LSQ,MSQ,edgeAlign); // extract the edges - align = vec_lvsr( 0, to ); // permute map to misalign data - MSQ = vec_perm(edges,(Packet16uc)from,align); // misalign the data (MSQ) - LSQ = vec_perm((Packet16uc)from,edges,align); // misalign the data (LSQ) - vec_st( LSQ, 15, (unsigned char *)to ); // Store the LSQ part first - vec_st( MSQ, 0, (unsigned char *)to ); // Store the MSQ part + EIGEN_DEBUG_ALIGNED_STORE + vec_vsx_st((Packet4f)from, (long)to & 15, (float*) _EIGEN_ALIGNED_PTR(to)); } + template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { vec_dstt((const float *) addr, DST_CTRL(2,2,32), DST_CHAN); } template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { double EIGEN_ALIGN16 x[2]; pstore(x, a); return x[0]; } -template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { return (Packet2d)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE); } +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { return (Packet2d)vec_perm((Packet16uc)a,(Packet16uc)a, p16uc_REVERSE64); } template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vec_abs(a); } @@ -807,9 +868,10 @@ template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) { Packet2d v[2], sum; - v[0] = (Packet2d) vec_sld((Packet4ui) vecs[0], (Packet4ui) vecs[1], 8); - v[1] = (Packet2d) vec_sld((Packet4ui) vecs[1], (Packet4ui) vecs[0], 8); - sum = vec_add(v[0], v[1]); + v[0] = vec_add(vecs[0], (Packet2d) vec_sld((Packet4ui) vecs[0], (Packet4ui) vecs[0], 8)); + v[1] = vec_add(vecs[1], (Packet2d) vec_sld((Packet4ui) vecs[1], (Packet4ui) vecs[1], 8)); + + sum = (Packet2d) vec_sld((Packet4ui) v[1], (Packet4ui) v[0], 8); return sum; } @@ -817,26 +879,19 @@ template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) // mul template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) { - Packet2d prod; - prod = pmul(a, (Packet2d)vec_sld((Packet4ui) a, (Packet4ui)a, 8)); - return pfirst(pmul(prod, (Packet2d)vec_sld((Packet4ui) prod, (Packet4ui) prod, 4))); + return pfirst(pmul(a, (Packet2d)vec_sld((Packet4ui) a, (Packet4ui) a, 8))); } // min template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) { - Packet2d b, res; - b = vec_min(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8)); - res = vec_min(b, (Packet2d) vec_sld((Packet4ui) b, (Packet4ui) b, 4)); - return pfirst(res); + return pfirst(vec_min(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8))); } // max template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) { - Packet2d res; - res = vec_max(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8)); - return pfirst(res); + return pfirst(vec_max(a, (Packet2d) vec_sld((Packet4ui) a, (Packet4ui) a, 8))); } template @@ -844,16 +899,20 @@ struct palign_impl { static EIGEN_STRONG_INLINE void run(Packet2d& first, const Packet2d& second) { - if (Offset!=0) - first = (Packet2d) vec_sld((Packet4ui) first, (Packet4ui) second, Offset*8); + if (Offset == 1) +#ifdef _BIG_ENDIAN + first = (Packet2d) vec_sld((Packet4ui) first, (Packet4ui) second, 8); +#else + first = (Packet2d) vec_sld((Packet4ui) second, (Packet4ui) first, 8); +#endif } }; EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { Packet2d t0, t1; - t0 = (Packet2d) vec_sld((Packet4ui) kernel.packet[0], (Packet4ui) kernel.packet[1], 8); - t1 = (Packet2d) vec_sld((Packet4ui) kernel.packet[1], (Packet4ui) kernel.packet[0], 8); + t0 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_HI); + t1 = vec_perm(kernel.packet[0], kernel.packet[1], p16uc_TRANSPOSE64_LO); kernel.packet[0] = t0; kernel.packet[1] = t1; } -- cgit v1.2.3 From 80de35b6c562bca343fd5933bacc525dc1aeeb39 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Fri, 19 Sep 2014 22:05:18 +0100 Subject: Remove double return statement in PlainObjectBase::_set() --- Eigen/src/Core/PlainObjectBase.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 3b0e56445..0605e29aa 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -647,7 +647,6 @@ class PlainObjectBase : public internal::dense_xpr_base::type { internal::call_assignment(this->derived(), other.derived()); return this->derived(); - return this->derived(); } /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which -- cgit v1.2.3 From 10f8aabb611e7b727ff67141b030689c0a53ca78 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Sat, 20 Sep 2014 22:31:31 +0000 Subject: VSX port passes packetmath_[1-5] tests! --- Eigen/src/Core/arch/AltiVec/Complex.h | 80 +++++++++++--------------------- Eigen/src/Core/arch/AltiVec/PacketMath.h | 20 ++++---- 2 files changed, 37 insertions(+), 63 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 94ecec2de..58f5fbd27 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -14,11 +14,11 @@ namespace Eigen { namespace internal { -#ifdef _BIG_ENDIAN static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; +#ifdef _BIG_ENDIAN #else -static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4f_ZERO_, (Packet4ui)p4i_ZERO);//{ 0x80000000, 0x00000000, 0x80000000, 0x00000000 }; -static Packet2ul p2ul_CONJ_XOR = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui)p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_ZERO_, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; #endif //---------- float ---------- @@ -90,24 +90,17 @@ template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, con { Packet4f v1, v2; - std::cout << "a: " << a.v << ", b: " << b.v << std::endl; // Permute and multiply the real parts of a and b v1 = vec_perm(a.v, a.v, p16uc_PSET32_WODD); - std::cout << "v1 = a(re): " << v1 << std::endl; // Get the imaginary parts of a v2 = vec_perm(a.v, a.v, p16uc_PSET32_WEVEN); - std::cout << "v2 = a(im): " << v2 << std::endl; // multiply a_re * b v1 = vec_madd(v1, b.v, p4f_ZERO); - std::cout << "v1+ b : " << v1 << std::endl; // multiply a_im * b and get the conjugate result v2 = vec_madd(v2, b.v, p4f_ZERO); - std::cout << "v2+ b : " << v2 << std::endl; v2 = (Packet4f) vec_xor((Packet4ui)v2, p4ui_CONJ_XOR); - std::cout << "~v2 : " << v2 << std::endl; // permute back to a proper order v2 = vec_perm(v2, v2, p16uc_COMPLEX32_REV); - std::cout << "v2 : " << v2 << std::endl; return Packet2cf(vec_add(v1, v2)); } @@ -156,9 +149,13 @@ template<> EIGEN_STRONG_INLINE std::complex predux(const Packe template<> EIGEN_STRONG_INLINE Packet2cf preduxp(const Packet2cf* vecs) { Packet4f b1, b2; - +#ifdef _BIG_ENDIAN b1 = (Packet4f) vec_sld(vecs[0].v, vecs[1].v, 8); b2 = (Packet4f) vec_sld(vecs[1].v, vecs[0].v, 8); +#else + b1 = (Packet4f) vec_sld(vecs[1].v, vecs[0].v, 8); + b2 = (Packet4f) vec_sld(vecs[0].v, vecs[1].v, 8); +#endif b2 = (Packet4f) vec_sld(b2, b2, 8); b2 = padd(b1, b2); @@ -283,16 +280,8 @@ template<> EIGEN_STRONG_INLINE void pstore >(std::complex< template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) -{ - Packet1cd res; - /* On AltiVec we cannot load 64-bit registers, so wa have to take care of alignment */ - if((ptrdiff_t(&from) % 16) == 0) - res.v = pload((const double *)&from); - else - res.v = ploadu((const double *)&from); - res.v = vec_perm(res.v, res.v, p16uc_PSET64_HI); - return res; -} +{ /* here we really have to use unaligned loads :( */ return ploadu(&from); } + template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, DenseIndex stride) { std::complex EIGEN_ALIGN16 af[2]; @@ -311,7 +300,7 @@ template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1c template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_add(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(vec_sub(a.v,b.v)); } template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(Packet2d(a.v))); } -template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2d)a.v, (Packet2d)p2ul_CONJ_XOR)); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd((Packet2d)vec_xor((Packet2d)a.v, (Packet2d)p2ul_CONJ_XOR2)); } template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) { @@ -320,13 +309,13 @@ template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, con // Permute and multiply the real parts of a and b a_re = vec_perm(a.v, a.v, p16uc_PSET64_HI); // Get the imaginary parts of a - a_im = vec_perm(a.v, a.v, p16uc_PSET64_HI); + a_im = vec_perm(a.v, a.v, p16uc_PSET64_LO); // multiply a_re * b - v1 = vec_madd(a_re, b.v, p2d_ZERO_); + v1 = vec_madd(a_re, b.v, p2d_ZERO); // multiply a_im * b and get the conjugate result - v2 = vec_madd(a_im, b.v, p2d_ZERO_); + v2 = vec_madd(a_im, b.v, p2d_ZERO); v2 = (Packet2d) vec_sld((Packet4ui)v2, (Packet4ui)v2, 8); - v2 = (Packet2d) vec_xor((Packet2d)v2, (Packet2d) p2ul_CONJ_XOR); + v2 = (Packet2d) vec_xor((Packet2d)v2, (Packet2d) p2ul_CONJ_XOR1); return Packet1cd(vec_add(v1, v2)); } @@ -351,48 +340,31 @@ template<> EIGEN_STRONG_INLINE std::complex pfirst(const Pac return res[0]; } -template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) -{ - Packet2d rev_a; - rev_a = vec_perm(a.v, a.v, p16uc_COMPLEX32_REV2); - return Packet1cd(rev_a); -} +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; } template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) { - Packet2d b; - b = (Packet2d) vec_sld((Packet4ui) a.v, (Packet4ui) a.v, 8); - b = padd(a.v, b); - return pfirst(Packet1cd(b)); + return pfirst(a); } template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) { - Packet2d b1, b2; - - b1 = (Packet2d) vec_sld((Packet4ui) vecs[0].v, (Packet4ui) vecs[1].v, 8); - b2 = (Packet2d) vec_sld((Packet4ui) vecs[1].v, (Packet4ui) vecs[0].v, 8); - b2 = (Packet2d) vec_sld((Packet4ui) b2, (Packet4ui) b2, 8); - b2 = padd(b1, b2); - - return Packet1cd(b2); + return vecs[0]; } template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) { - Packet2d b; - Packet1cd prod; - b = (Packet2d) vec_sld((Packet4ui) a.v, (Packet4ui) a.v, 8); - prod = pmul(a, Packet1cd(b)); - - return pfirst(prod); + return pfirst(a); } template struct palign_impl { - static EIGEN_STRONG_INLINE void run(Packet1cd& first, const Packet1cd& second) - { } + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + { + // FIXME is it sure we never have to align a Packet1cd? + // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... + } }; template<> struct conj_helper @@ -436,9 +408,9 @@ template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, con return Packet1cd(pdiv(res.v, vec_add(s,vec_perm(s, s, p16uc_COMPLEX32_REV)))); } -template<> EIGEN_STRONG_INLINE Packet1cd pcplxflip(const Packet1cd& x) +EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) { - return Packet1cd(vec_perm(x.v, x.v, p16uc_COMPLEX32_REV)); + return Packet1cd(preverse(Packet2d(x.v))); } EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index aea3e79dc..f319f4266 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -94,17 +94,20 @@ static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; static Packet16uc p16uc_PSET32_WEVEN = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; static Packet16uc p16uc_HALF64_0_16 = vec_sld(vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 0), (Packet16uc)p4i_ZERO, 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; - #endif // _BIG_ENDIAN static Packet16uc p16uc_PSET64_HI = (Packet16uc) vec_mergeh((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7 }; static Packet16uc p16uc_PSET64_LO = (Packet16uc) vec_mergel((Packet4ui)p16uc_PSET32_WODD, (Packet4ui)p16uc_PSET32_WEVEN); //{ 8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15 }; +static Packet16uc p16uc_TRANSPOSE64_HI = vec_add(p16uc_PSET64_HI, p16uc_HALF64_0_16); //{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; +static Packet16uc p16uc_TRANSPOSE64_LO = vec_add(p16uc_PSET64_LO, p16uc_HALF64_0_16); //{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; static Packet16uc p16uc_COMPLEX32_REV = vec_sld(p16uc_REVERSE32, p16uc_REVERSE32, 8); //{ 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 }; -static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; -static Packet16uc p16uc_TRANSPOSE64_HI = vec_add(p16uc_PSET64_HI, p16uc_HALF64_0_16); //{ 0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; -static Packet16uc p16uc_TRANSPOSE64_LO = vec_add(p16uc_PSET64_LO, p16uc_HALF64_0_16); //{ 8,9,10,11, 12,13,14,15, 24,25,26,27, 28,29,30,31}; +#ifdef _BIG_ENDIAN +static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_FORWARD, p16uc_FORWARD, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +#else +static Packet16uc p16uc_COMPLEX32_REV2 = vec_sld(p16uc_PSET64_HI, p16uc_PSET64_LO, 8); //{ 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; +#endif // _BIG_ENDIAN template<> struct packet_traits : default_packet_traits { @@ -703,12 +706,11 @@ typedef __vector double Packet2d; typedef __vector unsigned long long Packet2ul; typedef __vector long long Packet2l; -static Packet2l p2l_ZERO = { 0x0, 0x0 }; -static Packet2d p2l_ONE = { 1, 1 }; +static Packet2l p2l_ZERO = (Packet2l) p4i_ZERO; static Packet2d p2d_ONE = { 1.0, 1.0 }; -static Packet2d p2d_ZERO = { 0.0, 0.0 }; -static Packet2d p2d_ZERO_ = { (double) 0x8000000000000000, (double) 0x8000000000000000 }; -static Packet2d p2d_COUNTDOWN = { 0.0, 1.0 }; +static Packet2d p2d_ZERO = (Packet2d) p4f_ZERO; +static Packet2d p2d_ZERO_ = { -0.0, -0.0 }; +static Packet2d p2d_COUNTDOWN = (Packet2d) vec_sld((Packet16uc) p2d_ONE, (Packet16uc) p2d_ZERO, 8); static EIGEN_STRONG_INLINE Packet2d vec_splat_dbl(Packet2d& a, int index) { -- cgit v1.2.3 From c0205ca4af402eadcf1a21bc0949afa4c9d9712a Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Sun, 21 Sep 2014 08:12:22 +0000 Subject: VSX supports vec_div, implement where appropriate (float/doubles) --- Eigen/src/Core/arch/AltiVec/PacketMath.h | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index f319f4266..3555c521d 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -336,6 +336,7 @@ template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const */ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { +#ifndef __VSX__ // VSX actually provides a div instruction Packet4f t, y_0, y_1, res; // Altivec does not offer a divide instruction, we have to do a reciprocal approximation @@ -345,8 +346,10 @@ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const t = vec_nmsub(y_0, b, p4f_ONE); y_1 = vec_madd(y_0, t, y_0); - res = vec_madd(a, y_1, p4f_ZERO); - return res; + return vec_madd(a, y_1, p4f_ZERO); +#else + return vec_div(a, b); +#endif } template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) @@ -801,20 +804,7 @@ template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return psub template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return vec_madd(a,b,p2d_ZERO); } -template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) -{ - Packet2d t, y_0, y_1, res; - - // Altivec does not offer a divide instruction, we have to do a reciprocal approximation - y_0 = vec_re(b); - - // Do one Newton-Raphson iteration to get the needed accuracy - t = vec_nmsub(y_0, b, p2d_ONE); - y_1 = vec_madd(y_0, t, y_0); - - res = vec_madd(a, y_1, p2d_ZERO); - return res; -} +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return vec_div(a,b); } // for some weird raisons, it has to be overloaded for packet of integers template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vec_madd(a, b, c); } -- cgit v1.2.3 From 974fe38ca38fb812f3ce4be105cf2ff69f40aef1 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Sun, 21 Sep 2014 11:24:30 +0000 Subject: prefetch are noops on VSX --- Eigen/src/Core/arch/AltiVec/PacketMath.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 3555c521d..1274f72dd 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -28,7 +28,7 @@ namespace internal { // NOTE Altivec has 32 registers, but Eigen only accepts a value of 8 or 16 #ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32 #endif typedef __vector float Packet4f; @@ -482,8 +482,16 @@ template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& } #endif -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { +#ifndef __VSX__ + vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); +#endif +} +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { +#ifndef __VSX__ + vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); +#endif +} template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } -- cgit v1.2.3 From 56408504e4e3fa5f9c59d9edac14ca1ba1255e5a Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Sun, 21 Sep 2014 13:59:30 +0300 Subject: fix compile error on big endian altivec --- Eigen/src/Core/arch/AltiVec/Complex.h | 3 ++- Eigen/src/Core/arch/AltiVec/PacketMath.h | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 58f5fbd27..30e2088ef 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -242,6 +242,7 @@ EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) } //---------- double ---------- +#ifdef __VSX__ struct Packet1cd { EIGEN_STRONG_INLINE Packet1cd() {} @@ -419,7 +420,7 @@ EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) kernel.packet[1].v = vec_perm(kernel.packet[0].v, kernel.packet[1].v, p16uc_TRANSPOSE64_LO); kernel.packet[0].v = tmp; } - +#endif // __VSX__ } // end namespace internal } // end namespace Eigen diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 1274f72dd..728f8b4d6 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -76,12 +76,12 @@ static Packet4f p4f_COUNTDOWN = { 0.0, 1.0, 2.0, 3.0 }; static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; static Packet16uc p16uc_REVERSE32 = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3 }; -static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 }; // Handle endianness properly while loading constants // Define global static constants: #ifdef _BIG_ENDIAN +static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; @@ -91,6 +91,7 @@ static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((P #define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; static Packet16uc p16uc_PSET32_WEVEN = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; static Packet16uc p16uc_HALF64_0_16 = vec_sld(vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 0), (Packet16uc)p4i_ZERO, 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; @@ -337,7 +338,7 @@ template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { #ifndef __VSX__ // VSX actually provides a div instruction - Packet4f t, y_0, y_1, res; + Packet4f t, y_0, y_1; // Altivec does not offer a divide instruction, we have to do a reciprocal approximation y_0 = vec_re(b); -- cgit v1.2.3 From de38ff24993af77f188ab97d458d2884eeffd1ba Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Sun, 21 Sep 2014 11:56:07 +0000 Subject: prefetch are noops on VSX, actually disable the prefetch trait --- Eigen/src/Core/arch/AltiVec/PacketMath.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 728f8b4d6..1b86e1227 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -483,16 +483,10 @@ template<> EIGEN_STRONG_INLINE void pstoreu(float* to, const Packet4f& } #endif -template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { #ifndef __VSX__ - vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); +template<> EIGEN_STRONG_INLINE void prefetch(const float* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } +template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); } #endif -} -template<> EIGEN_STRONG_INLINE void prefetch(const int* addr) { -#ifndef __VSX__ - vec_dstt(addr, DST_CTRL(2,2,32), DST_CHAN); -#endif -} template<> EIGEN_STRONG_INLINE float pfirst(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } template<> EIGEN_STRONG_INLINE int pfirst(const Packet4i& a) { int EIGEN_ALIGN16 x[4]; vec_st(a, 0, x); return x[0]; } -- cgit v1.2.3 From 5fa69422a2d0f2d508c52e1b0eb39ed7e0d63726 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sun, 21 Sep 2014 14:19:23 +0100 Subject: Fix copy-and-paste typo in SolveWithGuess assignment This fixes compilation of code snippets in BiCGSTAB docs. --- Eigen/src/IterativeLinearSolvers/SolveWithGuess.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h index 46dd5babe..6cd4872dc 100644 --- a/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +++ b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h @@ -93,12 +93,12 @@ protected: PlainObject m_result; }; -// Specialization for "dst = dec.solve(rhs)" +// Specialization for "dst = dec.solveWithGuess(rhs)" // NOTE we need to specialize it for Dense2Dense to avoid ambiguous specialization error and a Sparse2Sparse specialization must exist somewhere template struct Assignment, internal::assign_op, Dense2Dense, Scalar> { - typedef Solve SrcXprType; + typedef SolveWithGuess SrcXprType; static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { // FIXME shall we resize dst here? -- cgit v1.2.3 From 333905b0c2e2e377744c7ed326ead34625510530 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sun, 21 Sep 2014 14:20:08 +0100 Subject: Fix typos in docs for IterativeLinearSolvers module --- Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 2 +- Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index 051940dc7..42da7d14b 100644 --- a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -143,7 +143,7 @@ struct traits > * step execution example starting with a random guess and printing the evolution * of the estimated error: * \include BiCGSTAB_step_by_step.cpp - * Note that such a step by step excution is slightly slower. + * Note that such a step by step execution is slightly slower. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index fd9285087..1ca7e0561 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -60,10 +60,10 @@ public: ~IterativeSolverBase() {} - /** Initializes the iterative solver for the sparcity pattern of the matrix \a A for further solving \c Ax=b problems. + /** Initializes the iterative solver for the sparsity pattern of the matrix \a A for further solving \c Ax=b problems. * - * Currently, this function mostly call analyzePattern on the preconditioner. In the future - * we might, for instance, implement column reodering for faster matrix vector products. + * Currently, this function mostly calls analyzePattern on the preconditioner. In the future + * we might, for instance, implement column reordering for faster matrix vector products. */ Derived& analyzePattern(const MatrixType& A) { @@ -76,7 +76,7 @@ public: /** Initializes the iterative solver with the numerical values of the matrix \a A for further solving \c Ax=b problems. * - * Currently, this function mostly call factorize on the preconditioner. + * Currently, this function mostly calls factorize on the preconditioner. * * \warning this class stores a reference to the matrix A as well as some * precomputed values that depend on it. Therefore, if \a A is changed @@ -95,8 +95,8 @@ public: /** Initializes the iterative solver with the matrix \a A for further solving \c Ax=b problems. * - * Currently, this function mostly initialized/compute the preconditioner. In the future - * we might, for instance, implement column reodering for faster matrix vector products. + * Currently, this function mostly initializes/computes the preconditioner. In the future + * we might, for instance, implement column reordering for faster matrix vector products. * * \warning this class stores a reference to the matrix A as well as some * precomputed values that depend on it. Therefore, if \a A is changed -- cgit v1.2.3 From abba11bdcf3e9f98a616e59570086edbf0d762b5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 22 Sep 2014 15:22:52 +0200 Subject: Many improvements in Divide&Conquer SVD: - Fix many numerical issues, in particular regarding deflation. - Add heavy debugging output to help track numerical issues (there are still fews) - Make use of Eiegn's apply-inplane-rotation feature. --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 516 +++++++++++++++++++++++----------- 1 file changed, 354 insertions(+), 162 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index 0167872af..b13ee415e 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -11,6 +11,7 @@ // Copyright (C) 2013 Jean Ceccato // Copyright (C) 2013 Pierre Zoppitelli // Copyright (C) 2013 Jitse Niesen +// Copyright (C) 2014 Gael Guennebaud // // Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,7 +19,8 @@ #ifndef EIGEN_BDCSVD_H #define EIGEN_BDCSVD_H - +// #define EIGEN_BDCSVD_DEBUG_VERBOSE +// #define EIGEN_BDCSVD_SANITY_CHECKS namespace Eigen { template class BDCSVD; @@ -165,6 +167,7 @@ private: template void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); static void structured_update(Block A, const MatrixXr &B, Index n1); + static RealScalar secularEq(RealScalar x, const ArrayXr& col0, const ArrayXr& diag, const ArrayXr& diagShifted, RealScalar shift, Index n); protected: MatrixXr m_naiveU, m_naiveV; @@ -189,11 +192,12 @@ public: }; //end class BDCSVD -// Methode to allocate ans initialize matrix and attributs +// Methode to allocate ans initialize matrix and attributes template void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) { m_isTranspose = (cols > rows); + if (Base::allocate(rows, cols, computationOptions)) return; @@ -233,7 +237,7 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign allocate(matrix.rows(), matrix.cols(), computationOptions); using std::abs; - //**** step 1 Bidiagonalization m_isTranspose = (matrix.cols()>matrix.rows()) ; + //**** step 1 Bidiagonalization MatrixType copy; if (m_isTranspose) copy = matrix.adjoint(); else copy = matrix; @@ -264,8 +268,11 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign break; } } +// std::cout << "m_naiveU\n" << m_naiveU << "\n\n"; +// std::cout << "m_naiveV\n" << m_naiveV << "\n\n"; if(m_isTranspose) copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU); else copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV); +// std::cout << "DONE\n"; m_isInitialized = true; return *this; }// end compute @@ -278,18 +285,16 @@ void BDCSVD::copyUV(const HouseholderU &householderU, const Househol // Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa if (computeU()) { - Index Ucols = m_computeThinU ? m_nonzeroSingularValues : householderU.cols(); + Index Ucols = m_computeThinU ? m_diagSize : householderU.cols(); m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); - Index blockCols = m_computeThinU ? m_nonzeroSingularValues : m_diagSize; - m_matrixU.topLeftCorner(m_diagSize, blockCols) = naiveV.template cast().topLeftCorner(m_diagSize, blockCols); + m_matrixU.topLeftCorner(m_diagSize, m_diagSize) = naiveV.template cast().topLeftCorner(m_diagSize, m_diagSize); householderU.applyThisOnTheLeft(m_matrixU); } if (computeV()) { - Index Vcols = m_computeThinV ? m_nonzeroSingularValues : householderV.cols(); + Index Vcols = m_computeThinV ? m_diagSize : householderV.cols(); m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); - Index blockCols = m_computeThinV ? m_nonzeroSingularValues : m_diagSize; - m_matrixV.topLeftCorner(m_diagSize, blockCols) = naiveU.template cast().topLeftCorner(m_diagSize, blockCols); + m_matrixV.topLeftCorner(m_diagSize, m_diagSize) = naiveU.template cast().topLeftCorner(m_diagSize, m_diagSize); householderV.applyThisOnTheLeft(m_matrixV); } } @@ -308,7 +313,7 @@ void BDCSVD::structured_update(Block A, co Index n = A.rows(); if(n>100) { - // If the matrices are large enough, let's exploit the sparse strucure of A by + // If the matrices are large enough, let's exploit the sparse structure of A by // splitting it in half (wrt n1), and packing the non-zero columns. DenseIndex n2 = n - n1; MatrixXr A1(n1,n), A2(n2,n), B1(n,n), B2(n,n); @@ -385,6 +390,7 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, // right submatrix before the left one. divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift); divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1); + if (m_compU) { lambda = m_naiveU(firstCol + k, firstCol + k); @@ -417,6 +423,13 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, c0 = alphaK * lambda / r0; s0 = betaK * phi / r0; } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + if (m_compU) { MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1)); @@ -449,6 +462,13 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, m_naiveU.row(1).segment(firstCol + 1, k).setZero(); m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero(); } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + m_computed(firstCol + shift, firstCol + shift) = r0; m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); @@ -461,11 +481,22 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, VectorType singVals; computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(UofSVD.allFinite()); + assert(VofSVD.allFinite()); +#endif + if (m_compU) structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2); else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n+1)/2); +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; }// end divide @@ -491,18 +522,78 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec U.resize(n+1, n+1); if (m_compV) V.resize(n, n); - if (col0.hasNaN() || diag.hasNaN()) return; + if (col0.hasNaN() || diag.hasNaN()) { std::cout << "\n\nHAS NAN\n\n"; return; } + ArrayXr shifts(n), mus(n), zhat(n); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "computeSVDofM using:\n"; + std::cout << " z: " << col0.transpose() << "\n"; + std::cout << " d: " << diag.transpose() << "\n"; +#endif + // Compute singVals, shifts, and mus computeSingVals(col0, diag, singVals, shifts, mus); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << " sing-val: " << singVals.transpose() << "\n"; + std::cout << " mu: " << mus.transpose() << "\n"; + std::cout << " shift: " << shifts.transpose() << "\n"; +#endif + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(singVals.allFinite()); + assert(mus.allFinite()); + assert(shifts.allFinite()); +#endif + + // Compute zhat perturbCol0(col0, diag, singVals, shifts, mus, zhat); - computeSingVecs(zhat, diag, singVals, shifts, mus, U, V); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << " zhat: " << zhat.transpose() << "\n"; + { + Index actual_n = n; + while(actual_n>1 && col0(actual_n-1)==0) --actual_n; + std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n"; + std::cout << " check1: " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check2: " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check3: " << ((diag.segment(1,actual_n-1)-singVals.head(actual_n-1).array()) / singVals.head(actual_n-1).array()).transpose() << "\n\n\n"; + } +#endif +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(zhat.allFinite()); +#endif + + computeSingVecs(zhat, diag, singVals, shifts, mus, U, V); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "U^T U: " << (U.transpose() * U - MatrixType(MatrixType::Identity(U.cols(),U.cols()))).norm() << "\n"; + std::cout << "V^T V: " << (V.transpose() * V - MatrixType(MatrixType::Identity(V.cols(),V.cols()))).norm() << "\n"; +#endif + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert((U.transpose() * U - MatrixType(MatrixType::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); + assert((V.transpose() * V - MatrixType(MatrixType::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + // Reverse order so that singular values in increased order - singVals.reverseInPlace(); - U.leftCols(n) = U.leftCols(n).rowwise().reverse().eval(); // FIXME this requires a temporary - if (m_compV) V = V.rowwise().reverse().eval(); // FIXME this requires a temporary + // Because of deflation, the zeros singular-values are already at the end + Index actual_n = n; + while(actual_n>1 && singVals(actual_n-1)==0) --actual_n; + singVals.head(actual_n).reverseInPlace(); + U.leftCols(actual_n) = U.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary + if (m_compV) V.leftCols(actual_n) = V.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary +} + +template +typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXr& diagShifted, RealScalar shift, Index n) +{ + return 1 + (col0.square() / ((diagShifted - mu) )/( (diag + shift + mu))).head(n).sum(); } template @@ -514,6 +605,19 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia using std::max; Index n = col0.size(); + Index actual_n = n; + while(actual_n>1 && col0(actual_n-1)==0) --actual_n; + Index m = 0; + Array perm(actual_n); + { + for(Index k=0;k::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // otherwise, use secular equation to find singular value RealScalar left = diag(k); - RealScalar right = (k != n-1) ? diag(k+1) : (diag(n-1) + col0.matrix().norm()); + RealScalar right = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm()); // first decide whether it's closer to the left end or the right end RealScalar mid = left + (right-left) / 2; - RealScalar fMid = 1 + (col0.square() / ((diag + mid) * (diag - mid))).sum(); + RealScalar fMid = 1 + (col0.square() / ((diag + mid) * (diag - mid))).head(actual_n).sum(); - RealScalar shift = (k == n-1 || fMid > 0) ? left : right; + RealScalar shift = (k == actual_n-1 || fMid > 0) ? left : right; // measure everything relative to shift ArrayXr diagShifted = diag - shift; @@ -543,7 +647,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia if (shift == left) { muPrev = (right - left) * 0.1; - if (k == n-1) muCur = right - left; + if (k == actual_n-1) muCur = right - left; else muCur = (right - left) * 0.5; } else @@ -552,8 +656,8 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia muCur = -(right - left) * 0.5; } - RealScalar fPrev = 1 + (col0.square() / ((diagShifted - muPrev) * (diag + shift + muPrev))).sum(); - RealScalar fCur = 1 + (col0.square() / ((diagShifted - muCur) * (diag + shift + muCur))).sum(); + RealScalar fPrev = secularEq(muPrev, col0, diag, diagShifted, shift, actual_n); + RealScalar fCur = secularEq(muCur, col0, diag, diagShifted, shift, actual_n); if (abs(fPrev) < abs(fCur)) { swap(fPrev, fCur); @@ -563,7 +667,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // rational interpolation: fit a function of the form a / mu + b through the two previous // iterates and use its zero to compute the next iterate bool useBisection = false; - while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && fCur != fPrev && !useBisection) + while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) { ++m_numIters; @@ -573,7 +677,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia muPrev = muCur; fPrev = fCur; muCur = -a / b; - fCur = 1 + (col0.square() / ((diagShifted - muCur) * (diag + shift + muCur))).sum(); + fCur = secularEq(muCur, col0, diag, diagShifted, shift, actual_n); if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true; @@ -595,14 +699,19 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia rightShifted = -1e-30; } - RealScalar fLeft = 1 + (col0.square() / ((diagShifted - leftShifted) * (diag + shift + leftShifted))).sum(); - RealScalar fRight = 1 + (col0.square() / ((diagShifted - rightShifted) * (diag + shift + rightShifted))).sum(); - assert(fLeft * fRight < 0); + RealScalar fLeft = secularEq(leftShifted, col0, diag, diagShifted, shift, actual_n); + RealScalar fRight = secularEq(rightShifted, col0, diag, diagShifted, shift, actual_n); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + if(fLeft * fRight>0) + std::cout << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; +#endif + eigen_internal_assert(fLeft * fRight < 0); while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (max)(abs(leftShifted), abs(rightShifted))) { RealScalar midShifted = (leftShifted + rightShifted) / 2; - RealScalar fMid = 1 + (col0.square() / ((diagShifted - midShifted) * (diag + shift + midShifted))).sum(); + RealScalar fMid = secularEq(midShifted, col0, diag, diagShifted, shift, actual_n); if (fLeft * fMid < 0) { rightShifted = midShifted; @@ -638,27 +747,53 @@ void BDCSVD::perturbCol0 { using std::sqrt; Index n = col0.size(); + + // Ignore trailing zeros: + Index actual_n = n; + while(actual_n>1 && col0(actual_n-1)==0) --actual_n; + // Deflated non-zero singular values are kept in-place, + // we thus compute an indirection array to properly ignore all deflated entries. + // TODO compute it once! + Index m = 0; // size of the deflated problem + Array perm(actual_n); + { + for(Index k=0;k 0) zhat(k) = tmp; - else zhat(k) = -tmp; + RealScalar dk = diag(k); + RealScalar prod = (singVals(actual_n-1) + dk) * (mus(actual_n-1) + (shifts(actual_n-1) - dk)); + + for(Index l = 0; l 0.9 ) + std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk)) << ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n"; +#endif + } + } +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(actual_n-1) + dk) << " * " << mus(actual_n-1) + shifts(actual_n-1) << " - " << dk << "\n"; +#endif + RealScalar tmp = sqrt(prod); + zhat(k) = col0(k) > 0 ? tmp : -tmp; } } } @@ -670,6 +805,23 @@ void BDCSVD::computeSingVecs const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V) { Index n = zhat.size(); + + // Deflated non-zero singular values are kept in-place, + // we thus compute an indirection array to properly ignore all deflated entries. + // TODO compute it once! + Index actual_n = n; + while(actual_n>1 && zhat(actual_n-1)==0) --actual_n; + Index m = 0; + Array perm(actual_n); + { + for(Index k=0;k::computeSingVecs } else { - U.col(k).head(n) = zhat / (((diag - shifts(k)) - mus(k)) * (diag + singVals[k])); - U(n,k) = 0; + U.col(k).setZero(); + for(Index l=0;l::deflation43(Index firstCol, Index shift, Index i, Index using std::abs; using std::sqrt; using std::pow; - RealScalar c = m_computed(firstCol + shift, firstCol + shift); - RealScalar s = m_computed(i, firstCol + shift); - RealScalar r = sqrt(pow(abs(c), 2) + pow(abs(s), 2)); + Index start = firstCol + shift; + RealScalar c = m_computed(start, start); + RealScalar s = m_computed(start+i, start); + RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); if (r == 0) { - m_computed(i, i) = 0; + m_computed(start+i, start+i) = 0; return; } - c/=r; - s/=r; - m_computed(firstCol + shift, firstCol + shift) = r; - m_computed(i, firstCol + shift) = 0; - m_computed(i, i) = 0; - if (m_compU) - { - m_naiveU.col(firstCol).segment(firstCol,size) = - c * m_naiveU.col(firstCol).segment(firstCol, size) - - s * m_naiveU.col(i).segment(firstCol, size) ; - - m_naiveU.col(i).segment(firstCol, size) = - (c + s*s/c) * m_naiveU.col(i).segment(firstCol, size) + - (s/c) * m_naiveU.col(firstCol).segment(firstCol,size); - } + m_computed(start,start) = r; + m_computed(start+i, start) = 0; + m_computed(start+i, start+i) = 0; + + JacobiRotation J(c/r,-s/r); + if (m_compU) m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J); + else m_naiveU.applyOnTheRight(firstCol, firstCol+i, J); }// end deflation 43 // page 13 // i,j >= 1, i != j and |di - dj| < epsilon * norm2(M) // We apply two rotations to have zj = 0; +// TODO deflation44 is still broken and not properly tested template void BDCSVD::deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size) { @@ -740,9 +898,20 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi using std::sqrt; using std::conj; using std::pow; - RealScalar c = m_computed(firstColm, firstColm + j - 1); - RealScalar s = m_computed(firstColm, firstColm + i - 1); - RealScalar r = sqrt(pow(abs(c), 2) + pow(abs(s), 2)); + RealScalar c = m_computed(firstColm+i, firstColm); + RealScalar s = m_computed(firstColm+j, firstColm); + RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; " + << m_computed(firstColm + i-1, firstColm) << " " + << m_computed(firstColm + i, firstColm) << " " + << m_computed(firstColm + i+1, firstColm) << " " + << m_computed(firstColm + i+2, firstColm) << "\n"; + std::cout << m_computed(firstColm + i-1, firstColm + i-1) << " " + << m_computed(firstColm + i, firstColm+i) << " " + << m_computed(firstColm + i+1, firstColm+i+1) << " " + << m_computed(firstColm + i+2, firstColm+i+2) << "\n"; +#endif if (r==0) { m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); @@ -753,25 +922,15 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi m_computed(firstColm + i, firstColm) = r; m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); m_computed(firstColm + j, firstColm) = 0; + + JacobiRotation J(c,s); if (m_compU) { - m_naiveU.col(firstColu + i).segment(firstColu, size) = - c * m_naiveU.col(firstColu + i).segment(firstColu, size) - - s * m_naiveU.col(firstColu + j).segment(firstColu, size) ; - - m_naiveU.col(firstColu + j).segment(firstColu, size) = - (c + s*s/c) * m_naiveU.col(firstColu + j).segment(firstColu, size) + - (s/c) * m_naiveU.col(firstColu + i).segment(firstColu, size); + m_naiveU.middleRows(firstColu, size).applyOnTheRight(firstColu + i, firstColu + j, J); } if (m_compV) { - m_naiveV.col(firstColW + i).segment(firstRowW, size - 1) = - c * m_naiveV.col(firstColW + i).segment(firstRowW, size - 1) + - s * m_naiveV.col(firstColW + j).segment(firstRowW, size - 1) ; - - m_naiveV.col(firstColW + j).segment(firstRowW, size - 1) = - (c + s*s/c) * m_naiveV.col(firstColW + j).segment(firstRowW, size - 1) - - (s/c) * m_naiveV.col(firstColW + i).segment(firstRowW, size - 1); + m_naiveU.middleRows(firstRowW, size-1).applyOnTheRight(firstColW + i, firstColW + j, J.transpose()); } }// end deflation 44 @@ -780,104 +939,137 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi template void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift) { - //condition 4.1 using std::sqrt; using std::abs; + using std::max; const Index length = lastCol + 1 - firstCol; - RealScalar norm1 = m_computed.block(firstCol+shift, firstCol+shift, length, 1).squaredNorm(); - RealScalar norm2 = m_computed.block(firstCol+shift, firstCol+shift, length, length).diagonal().squaredNorm(); - RealScalar epsilon = 10 * NumTraits::epsilon() * sqrt(norm1 + norm2); - if (m_computed(firstCol + shift, firstCol + shift) < epsilon) - m_computed(firstCol + shift, firstCol + shift) = epsilon; + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + + Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); + Diagonal fulldiag(m_computed); + VectorBlock,Dynamic> diag(fulldiag, firstCol+shift, length); + + RealScalar epsilon = 8 * NumTraits::epsilon() * (max)(col0.cwiseAbs().maxCoeff(), diag.cwiseAbs().maxCoeff()); + + //condition 4.1 + if (diag(0) < epsilon) + { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon << "\n"; +#endif + diag(0) = epsilon; + } //condition 4.2 - for (Index i=firstCol + shift + 1;i<=lastCol + shift;i++) - if (abs(m_computed(i, firstCol + shift)) < epsilon) - m_computed(i, firstCol + shift) = 0; + for (Index i=1;i firstCol + shift + k) permutation[p] = j++; - else if (j> lastCol + shift) permutation[p] = i++; - else if (m_computed(i, i) < m_computed(j, j)) permutation[p] = j++; - else permutation[p] = i++; - } - //we do the permutation - RealScalar aux; - //we stock the current index of each col - //and the column of each index - Index *realInd = new Index[length]; // FIXME avoid repeated dynamic memory allocation - Index *realCol = new Index[length]; // FIXME avoid repeated dynamic memory allocation - for (int pos = 0; pos< length; pos++) - { - realCol[pos] = pos + firstCol + shift; - realInd[pos] = pos; - } - const Index Zero = firstCol + shift; - VectorType temp; - for (int i = 1; i < length - 1; i++) + } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + { - const Index I = i + Zero; - const Index realI = realInd[i]; - const Index j = permutation[length - i] - Zero; - const Index J = realCol[j]; + // Sort the diagonal entries, since diag(1:k-1) and diag(k:length) are already sorted, let's do a sorted merge. + // First, compute the respective permutation. + Index *permutation = new Index[length]; // FIXME avoid repeated dynamic memory allocation + { + permutation[0] = 0; + Index p = 1; + for(Index i=1; i k) permutation[p] = j++; + else if (j >= length) permutation[p] = i++; + else if (diag(i) < diag(j)) permutation[p] = j++; + else permutation[p] = i++; + } + } - //diag displace - aux = m_computed(I, I); - m_computed(I, I) = m_computed(J, J); - m_computed(J, J) = aux; + // Current index of each col, and current column of each index + Index *realInd = new Index[length]; // FIXME avoid repeated dynamic memory allocation + Index *realCol = new Index[length]; // FIXME avoid repeated dynamic memory allocation - //firstrow displace - aux = m_computed(I, Zero); - m_computed(I, Zero) = m_computed(J, Zero); - m_computed(J, Zero) = aux; - - // change columns - if (m_compU) - { - temp = m_naiveU.col(I - shift).segment(firstCol, length + 1); - m_naiveU.col(I - shift).segment(firstCol, length + 1) = m_naiveU.col(J - shift).segment(firstCol, length + 1); - m_naiveU.col(J - shift).segment(firstCol, length + 1) = temp; - } - else + for(int pos = 0; pos< length; pos++) { - temp = m_naiveU.col(I - shift).segment(0, 2); - m_naiveU.col(I - shift).template head<2>() = m_naiveU.col(J - shift).segment(0, 2); - m_naiveU.col(J - shift).template head<2>() = temp; + realCol[pos] = pos; + realInd[pos] = pos; } - if (m_compV) + + for(Index i = 1; i < length - 1; i++) { - const Index CWI = I + firstColW - Zero; - const Index CWJ = J + firstColW - Zero; - temp = m_naiveV.col(CWI).segment(firstRowW, length); - m_naiveV.col(CWI).segment(firstRowW, length) = m_naiveV.col(CWJ).segment(firstRowW, length); - m_naiveV.col(CWJ).segment(firstRowW, length) = temp; + const Index pi = permutation[length - i]; + const Index J = realCol[pi]; + + using std::swap; + // swap diaognal and first column entries: + swap(diag(i), diag(J)); + swap(col0(i), col0(J)); + + // change columns + if (m_compU) m_naiveU.col(firstCol+i).segment(firstCol, length + 1).swap(m_naiveU.col(firstCol+J).segment(firstCol, length + 1)); + else m_naiveU.col(firstCol+i).segment(0, 2) .swap(m_naiveU.col(firstCol+J).segment(0, 2)); + if (m_compV) m_naiveV.col(firstColW + i).segment(firstRowW, length).swap(m_naiveV.col(firstColW + J).segment(firstRowW, length)); + + //update real pos + const Index realI = realInd[i]; + realCol[realI] = J; + realCol[pi] = i; + realInd[J] = realI; + realInd[i] = pi; } - - //update real pos - realCol[realI] = J; - realCol[j] = I; - realInd[J - Zero] = realI; - realInd[I - Zero] = j; + delete[] permutation; + delete[] realInd; + delete[] realCol; } - for (Index i = firstCol + shift + 1; i::epsilon()*diag(i+1)) +// if ((diag(i+1) - diag(i)) < epsilon) + { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i+1) - diag(i)) << " < " << epsilon << "\n"; +#endif + deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i, i + 1, length); + } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif }//end deflation -- cgit v1.2.3 From f9d6d3780f1709cc8e3722b55963dc2359cf414f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 22 Sep 2014 17:34:17 +0200 Subject: bug #879: fix compilation of tri1=mat*tri2 by copying tri2 into a full temporary. --- Eigen/src/Core/TriangularMatrix.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 0d315dd50..36f04a5e8 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -207,7 +207,8 @@ template class TriangularView TransposeMode = (Mode & Upper ? Lower : 0) | (Mode & Lower ? Upper : 0) | (Mode & (UnitDiag)) - | (Mode & (ZeroDiag)) + | (Mode & (ZeroDiag)), + IsVectorAtCompileTime = false }; EIGEN_DEVICE_FUNC -- cgit v1.2.3 From ae514ddfe561ef220bc9bbf8c0b7b5005b60d9c8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 22 Sep 2014 22:49:20 +0200 Subject: bug #880: manually edit the DartConfiguration.tcl file to get it working with cmake 3.0.x --- cmake/EigenConfigureTesting.cmake | 45 ++++++--------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/cmake/EigenConfigureTesting.cmake b/cmake/EigenConfigureTesting.cmake index 0b5de95bb..190509958 100644 --- a/cmake/EigenConfigureTesting.cmake +++ b/cmake/EigenConfigureTesting.cmake @@ -14,49 +14,18 @@ add_dependencies(check buildtests) # check whether /bin/bash exists find_file(EIGEN_BIN_BASH_EXISTS "/bin/bash" PATHS "/" NO_DEFAULT_PATH) -# CMake/Ctest does not allow us to change the build command, -# so we have to workaround by directly editing the generated DartConfiguration.tcl file -# save CMAKE_MAKE_PROGRAM -set(CMAKE_MAKE_PROGRAM_SAVE ${CMAKE_MAKE_PROGRAM}) -# and set a fake one -set(CMAKE_MAKE_PROGRAM "@EIGEN_MAKECOMMAND_PLACEHOLDER@") - # This call activates testing and generates the DartConfiguration.tcl include(CTest) set(EIGEN_TEST_BUILD_FLAGS "" CACHE STRING "Options passed to the build command of unit tests") -# overwrite default DartConfiguration.tcl -# The worarounds are different for each version of the MSVC IDE -set(EIGEN_TEST_TARGET buildtests) -if(MSVC_IDE) - if(CMAKE_MAKE_PROGRAM_SAVE MATCHES "devenv") # devenv - set(EIGEN_BUILD_COMMAND "${CMAKE_MAKE_PROGRAM_SAVE} Eigen.sln /build Release /project ${EIGEN_TEST_TARGET}") - else() # msbuild - set(EIGEN_BUILD_COMMAND "${CMAKE_MAKE_PROGRAM_SAVE} ${EIGEN_TEST_TARGET}.vcxproj /p:Configuration=\${CTEST_CONFIGURATION_TYPE}") - endif() - - # append the build flags if provided - if(NOT "${EIGEN_TEST_BUILD_FLAGS}" MATCHES "^[ \t]*$") - set(EIGEN_BUILD_COMMAND "${EIGEN_BUILD_COMMAND} ${EIGEN_TEST_BUILD_FLAGS}") - endif() - - # apply the dartconfig hack ... - set(EIGEN_MAKECOMMAND_PLACEHOLDER "${EIGEN_BUILD_COMMAND}\n#") -else() - # for make and nmake - set(EIGEN_BUILD_COMMAND "${CMAKE_MAKE_PROGRAM_SAVE} ${EIGEN_TEST_TARGET} ${EIGEN_TEST_BUILD_FLAGS}") - set(EIGEN_MAKECOMMAND_PLACEHOLDER "${EIGEN_BUILD_COMMAND}") -endif() - -configure_file(${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl ${CMAKE_BINARY_DIR}/DartConfiguration.tcl) - -# restore default CMAKE_MAKE_PROGRAM -set(CMAKE_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM_SAVE}) - -# un-set temporary variables so that it is like they never existed -unset(CMAKE_MAKE_PROGRAM_SAVE) -unset(EIGEN_MAKECOMMAND_PLACEHOLDER) +# Overwrite default DartConfiguration.tcl such that ctest can build our unit tests. +# Recall that our unit tests are not in the "all" target, so we have to explicitely ask ctest to build our custom 'buildtests' target. +# At this stage, we can also add custom flags to the build tool through the user defined EIGEN_TEST_BUILD_FLAGS variable. +file(READ "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" EIGEN_DART_CONFIG_FILE) +string(REGEX REPLACE "MakeCommand:.*DefaultCTestConfigurationType" "MakeCommand: ${CMAKE_COMMAND} --build . --target buildtests --config '' -- -i ${EIGEN_TEST_BUILD_FLAGS}\nDefaultCTestConfigurationType" + EIGEN_DART_CONFIG_FILE2 ${EIGEN_DART_CONFIG_FILE}) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" ${EIGEN_DART_CONFIG_FILE2}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_BINARY_DIR}/CTestCustom.cmake) -- cgit v1.2.3 From ff46ec0f240ef84e2293b33b265c703e9b765c2e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 22 Sep 2014 23:33:28 +0200 Subject: bug #881: make SparseMatrixBase::isApprox(SparseMatrixBase) exploits sparse computations instead of converting the operands to dense matrices. --- Eigen/src/SparseCore/SparseFuzzy.h | 30 +++++++++++++++++------------- Eigen/src/SparseCore/SparseMatrixBase.h | 3 +-- test/sparse_basic.cpp | 4 ++++ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Eigen/src/SparseCore/SparseFuzzy.h b/Eigen/src/SparseCore/SparseFuzzy.h index 45f36e9eb..3e67cbf5f 100644 --- a/Eigen/src/SparseCore/SparseFuzzy.h +++ b/Eigen/src/SparseCore/SparseFuzzy.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -10,17 +10,21 @@ #ifndef EIGEN_SPARSE_FUZZY_H #define EIGEN_SPARSE_FUZZY_H -// template -// template -// bool SparseMatrixBase::isApprox( -// const OtherDerived& other, -// typename NumTraits::Real prec -// ) const -// { -// const typename internal::nested::type nested(derived()); -// const typename internal::nested::type otherNested(other.derived()); -// return (nested - otherNested).cwise().abs2().sum() -// <= prec * prec * (std::min)(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum()); -// } +namespace Eigen { + +template +template +bool SparseMatrixBase::isApprox(const SparseMatrixBase& other, const RealScalar &prec) const +{ + using std::min; + const typename internal::nested_eval::type actualA(derived()); + typename internal::conditional::type, + const PlainObject>::type actualB(other.derived()); + + return (actualA - actualB).squaredNorm() <= prec * prec * (min)(actualA.squaredNorm(), actualB.squaredNorm()); +} + +} // end namespace Eigen #endif // EIGEN_SPARSE_FUZZY_H diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index b5c50d93a..a438c6487 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -324,8 +324,7 @@ template class SparseMatrixBase : public EigenBase template bool isApprox(const SparseMatrixBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const - { return toDense().isApprox(other.toDense(),prec); } + const RealScalar& prec = NumTraits::dummy_precision()) const; template bool isApprox(const MatrixBase& other, diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index c86534bad..e5b6d5a0a 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -304,6 +304,10 @@ template void sparse_basic(const SparseMatrixType& re VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose()); VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint()); + + // check isApprox handles opposite storage order + typename Transpose::PlainObject m3(m2); + VERIFY(m2.isApprox(m3)); } -- cgit v1.2.3 From 3878e6f1703c22782ef9897fe46c7f1fc6a47ae5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 23 Sep 2014 10:25:12 +0200 Subject: Add a true ctest unit test for failtests --- test/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 530e9e4e1..4132e6481 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -324,3 +324,6 @@ endif(CUDA_FOUND) endif(EIGEN_TEST_NVCC) + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests) +add_test(NAME failtests WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests COMMAND ${CMAKE_COMMAND} ${Eigen_SOURCE_DIR} -G "${CMAKE_GENERATOR}" -DEIGEN_FAILTEST=ON) -- cgit v1.2.3 From 72569f17ecbc37309291aa7f333c8236aba8ee3f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 23 Sep 2014 10:26:02 +0200 Subject: bug #882: add const-correctness failtests for CwiseUnaryView, TriangularView, and SelfAdjointView. --- failtest/CMakeLists.txt | 6 ++++++ failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp | 15 +++++++++++++++ failtest/cwiseunaryview_on_const_type_actually_const.cpp | 16 ++++++++++++++++ failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp | 15 +++++++++++++++ .../selfadjointview_on_const_type_actually_const.cpp | 16 ++++++++++++++++ failtest/triangularview_nonconst_ctor_on_const_xpr.cpp | 15 +++++++++++++++ failtest/triangularview_on_const_type_actually_const.cpp | 16 ++++++++++++++++ 7 files changed, 99 insertions(+) create mode 100644 failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp create mode 100644 failtest/cwiseunaryview_on_const_type_actually_const.cpp create mode 100644 failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp create mode 100644 failtest/selfadjointview_on_const_type_actually_const.cpp create mode 100644 failtest/triangularview_nonconst_ctor_on_const_xpr.cpp create mode 100644 failtest/triangularview_on_const_type_actually_const.cpp diff --git a/failtest/CMakeLists.txt b/failtest/CMakeLists.txt index 5afa2ac82..83b6c81a9 100644 --- a/failtest/CMakeLists.txt +++ b/failtest/CMakeLists.txt @@ -7,6 +7,9 @@ ei_add_failtest("block_nonconst_ctor_on_const_xpr_1") ei_add_failtest("block_nonconst_ctor_on_const_xpr_2") ei_add_failtest("transpose_nonconst_ctor_on_const_xpr") ei_add_failtest("diagonal_nonconst_ctor_on_const_xpr") +ei_add_failtest("cwiseunaryview_nonconst_ctor_on_const_xpr") +ei_add_failtest("triangularview_nonconst_ctor_on_const_xpr") +ei_add_failtest("selfadjointview_nonconst_ctor_on_const_xpr") ei_add_failtest("const_qualified_block_method_retval_0") ei_add_failtest("const_qualified_block_method_retval_1") @@ -25,6 +28,9 @@ ei_add_failtest("block_on_const_type_actually_const_0") ei_add_failtest("block_on_const_type_actually_const_1") ei_add_failtest("transpose_on_const_type_actually_const") ei_add_failtest("diagonal_on_const_type_actually_const") +ei_add_failtest("cwiseunaryview_on_const_type_actually_const") +ei_add_failtest("triangularview_on_const_type_actually_const") +ei_add_failtest("selfadjointview_on_const_type_actually_const") if (EIGEN_FAILTEST_FAILURE_COUNT) message(FATAL_ERROR diff --git a/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp b/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 000000000..e23cf8fd8 --- /dev/null +++ b/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + CwiseUnaryView,Matrix3d> t(m); +} + +int main() {} diff --git a/failtest/cwiseunaryview_on_const_type_actually_const.cpp b/failtest/cwiseunaryview_on_const_type_actually_const.cpp new file mode 100644 index 000000000..fcd41dfdb --- /dev/null +++ b/failtest/cwiseunaryview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + CwiseUnaryView,CV_QUALIFIER MatrixXf>(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} diff --git a/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp b/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 000000000..a240f8184 --- /dev/null +++ b/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + SelfAdjointView t(m); +} + +int main() {} diff --git a/failtest/selfadjointview_on_const_type_actually_const.cpp b/failtest/selfadjointview_on_const_type_actually_const.cpp new file mode 100644 index 000000000..19aaad6d0 --- /dev/null +++ b/failtest/selfadjointview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + SelfAdjointView(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} diff --git a/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp b/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 000000000..807447e4b --- /dev/null +++ b/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + TriangularView t(m); +} + +int main() {} diff --git a/failtest/triangularview_on_const_type_actually_const.cpp b/failtest/triangularview_on_const_type_actually_const.cpp new file mode 100644 index 000000000..0a381a612 --- /dev/null +++ b/failtest/triangularview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + TriangularView(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} -- cgit v1.2.3 From de0d8a010e8cee66901786e0e2819beeaa5cb253 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 23 Sep 2014 12:58:14 +0200 Subject: Suppress stupid gcc-4.4 warning --- Eigen/src/SparseCore/SparseFuzzy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseFuzzy.h b/Eigen/src/SparseCore/SparseFuzzy.h index 3e67cbf5f..a76c1a5e0 100644 --- a/Eigen/src/SparseCore/SparseFuzzy.h +++ b/Eigen/src/SparseCore/SparseFuzzy.h @@ -18,7 +18,7 @@ bool SparseMatrixBase::isApprox(const SparseMatrixBase& o { using std::min; const typename internal::nested_eval::type actualA(derived()); - typename internal::conditional::type, const PlainObject>::type actualB(other.derived()); -- cgit v1.2.3 From 36448c9e287935b8c408791bf88b2907292d6c80 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 23 Sep 2014 14:28:23 +0200 Subject: Make constructors explicit if they could lead to unintended implicit conversion --- Eigen/src/Cholesky/LDLT.h | 12 +-- Eigen/src/Cholesky/LLT.h | 12 +-- Eigen/src/CholmodSupport/CholmodSupport.h | 2 +- Eigen/src/Core/ArrayBase.h | 4 +- Eigen/src/Core/ArrayWrapper.h | 4 +- Eigen/src/Core/BandMatrix.h | 6 +- Eigen/src/Core/CoreEvaluators.h | 57 +++++++------- Eigen/src/Core/CwiseUnaryOp.h | 2 +- Eigen/src/Core/CwiseUnaryView.h | 2 +- Eigen/src/Core/DenseBase.h | 4 +- Eigen/src/Core/DenseStorage.h | 16 ++-- Eigen/src/Core/Diagonal.h | 16 ++-- Eigen/src/Core/DiagonalMatrix.h | 20 ++--- Eigen/src/Core/Flagged.h | 4 +- Eigen/src/Core/ForceAlignedAccess.h | 6 +- Eigen/src/Core/GlobalFunctions.h | 4 +- Eigen/src/Core/Inverse.h | 2 +- Eigen/src/Core/Map.h | 2 +- Eigen/src/Core/MapBase.h | 2 +- Eigen/src/Core/Matrix.h | 2 +- Eigen/src/Core/MatrixBase.h | 6 +- Eigen/src/Core/NestByValue.h | 2 +- Eigen/src/Core/NoAlias.h | 4 +- Eigen/src/Core/PermutationMatrix.h | 11 +-- Eigen/src/Core/PlainObjectBase.h | 2 +- Eigen/src/Core/ProductEvaluators.h | 18 ++--- Eigen/src/Core/Redux.h | 2 +- Eigen/src/Core/ReturnByValue.h | 2 +- Eigen/src/Core/Reverse.h | 6 +- Eigen/src/Core/SelfAdjointView.h | 6 +- Eigen/src/Core/Solve.h | 2 +- Eigen/src/Core/Stride.h | 4 +- Eigen/src/Core/Transpose.h | 7 +- Eigen/src/Core/Transpositions.h | 6 +- Eigen/src/Core/TriangularMatrix.h | 33 ++++---- Eigen/src/Core/VectorwiseOp.h | 88 +++++++++++++--------- Eigen/src/Core/Visitor.h | 2 +- Eigen/src/Core/products/SelfadjointRank2Update.h | 8 +- Eigen/src/Core/util/BlasUtil.h | 2 +- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 4 +- Eigen/src/Eigenvalues/ComplexSchur.h | 4 +- Eigen/src/Eigenvalues/EigenSolver.h | 4 +- Eigen/src/Eigenvalues/GeneralizedEigenSolver.h | 4 +- .../GeneralizedSelfAdjointEigenSolver.h | 2 +- Eigen/src/Eigenvalues/HessenbergDecomposition.h | 4 +- Eigen/src/Eigenvalues/RealQZ.h | 4 +- Eigen/src/Eigenvalues/RealSchur.h | 4 +- Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 4 +- Eigen/src/Eigenvalues/Tridiagonalization.h | 4 +- Eigen/src/Geometry/Homogeneous.h | 8 +- Eigen/src/Geometry/Quaternion.h | 6 +- Eigen/src/Geometry/Rotation2D.h | 2 +- .../IterativeLinearSolvers/BasicPreconditioners.h | 4 +- Eigen/src/IterativeLinearSolvers/BiCGSTAB.h | 2 +- .../src/IterativeLinearSolvers/ConjugateGradient.h | 2 +- Eigen/src/IterativeLinearSolvers/IncompleteLUT.h | 2 +- .../IterativeLinearSolvers/IterativeSolverBase.h | 2 +- Eigen/src/LU/FullPivLU.h | 2 +- Eigen/src/LU/PartialPivLU.h | 4 +- Eigen/src/PaStiXSupport/PaStiXSupport.h | 6 +- Eigen/src/PardisoSupport/PardisoSupport.h | 6 +- Eigen/src/QR/ColPivHouseholderQR.h | 2 +- Eigen/src/QR/FullPivHouseholderQR.h | 2 +- Eigen/src/QR/HouseholderQR.h | 2 +- Eigen/src/SPQRSupport/SuiteSparseQRSupport.h | 10 +-- Eigen/src/SVD/JacobiSVD.h | 4 +- Eigen/src/SVD/UpperBidiagonalization.h | 4 +- Eigen/src/SparseCholesky/SimplicialCholesky.h | 16 ++-- Eigen/src/SparseCore/AmbiVector.h | 4 +- Eigen/src/SparseCore/CompressedStorage.h | 2 +- Eigen/src/SparseCore/MappedSparseMatrix.h | 2 +- Eigen/src/SparseCore/SparseBlock.h | 4 +- Eigen/src/SparseCore/SparseCwiseBinaryOp.h | 8 +- Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 4 +- Eigen/src/SparseCore/SparseDenseProduct.h | 9 ++- Eigen/src/SparseCore/SparseDiagonalProduct.h | 4 +- Eigen/src/SparseCore/SparseMatrix.h | 6 +- Eigen/src/SparseCore/SparseMatrixBase.h | 15 ++-- Eigen/src/SparseCore/SparsePermutation.h | 4 +- Eigen/src/SparseCore/SparseProduct.h | 2 +- Eigen/src/SparseCore/SparseSelfAdjointView.h | 6 +- Eigen/src/SparseCore/SparseTranspose.h | 2 +- Eigen/src/SparseCore/SparseTriangularView.h | 4 +- Eigen/src/SparseCore/SparseVector.h | 12 +-- Eigen/src/SparseCore/SparseView.h | 6 +- Eigen/src/SparseLU/SparseLU.h | 6 +- Eigen/src/SparseQR/SparseQR.h | 6 +- Eigen/src/SuperLUSupport/SuperLUSupport.h | 2 +- Eigen/src/UmfPackSupport/UmfPackSupport.h | 2 +- Eigen/src/misc/Kernel.h | 2 +- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 80 ++++++++++++-------- Eigen/src/plugins/CommonCwiseUnaryOps.h | 37 +++++---- Eigen/src/plugins/MatrixCwiseUnaryOps.h | 26 ++++--- 93 files changed, 415 insertions(+), 354 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 32c770654..b4016cd6c 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -85,7 +85,7 @@ template class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) + explicit LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), @@ -98,7 +98,7 @@ template class LDLT * This calculates the decomposition for the input \a matrix. * \sa LDLT(Index size) */ - LDLT(const MatrixType& matrix) + explicit LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), @@ -406,16 +406,16 @@ template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } }; } // end namespace internal diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index cb9e0eb7b..90194e64d 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -83,10 +83,10 @@ template class LLT * according to the specified problem \a size. * \sa LLT() */ - LLT(Index size) : m_matrix(size, size), + explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} - LLT(const MatrixType& matrix) + explicit LLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { @@ -351,8 +351,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -361,8 +361,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index 3524ffb2d..0c3b86dd2 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -180,7 +180,7 @@ class CholmodBase : public SparseSolverBase cholmod_start(&m_cholmod); } - CholmodBase(const MatrixType& matrix) + explicit CholmodBase(const MatrixType& matrix) : m_cholmodFactor(0), m_info(Success) { m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index 48a0006d5..b37b49ac4 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -158,9 +158,9 @@ template class ArrayBase /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ EIGEN_DEVICE_FUNC - MatrixWrapper matrix() { return derived(); } + MatrixWrapper matrix() { return MatrixWrapper(derived()); } EIGEN_DEVICE_FUNC - const MatrixWrapper matrix() const { return derived(); } + const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } diff --git a/Eigen/src/Core/ArrayWrapper.h b/Eigen/src/Core/ArrayWrapper.h index ed5210272..0b89c58cb 100644 --- a/Eigen/src/Core/ArrayWrapper.h +++ b/Eigen/src/Core/ArrayWrapper.h @@ -55,7 +55,7 @@ class ArrayWrapper : public ArrayBase > typedef typename internal::nested::type NestedExpressionType; EIGEN_DEVICE_FUNC - EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } @@ -198,7 +198,7 @@ class MatrixWrapper : public MatrixBase > typedef typename internal::nested::type NestedExpressionType; EIGEN_DEVICE_FUNC - inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} + explicit inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index b0ebe1160..e59ee3da9 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -204,7 +204,7 @@ class BandMatrix : public BandMatrixBase::Index Index; typedef typename internal::traits::CoefficientsType CoefficientsType; - inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -266,7 +266,7 @@ class BandMatrixWrapper : public BandMatrixBase::CoefficientsType CoefficientsType; typedef typename internal::traits::Index Index; - inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -314,7 +314,7 @@ class TridiagonalMatrix : public BandMatrix Base; typedef typename Base::Index Index; public: - TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 09a83a382..ab4320c2a 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -34,6 +34,11 @@ template struct storage_kind_to_shape; template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; + +// FIXME Is this necessary? And why was it not before refactoring??? +template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; + + // Evaluators have to be specialized with respect to various criteria such as: // - storage/structure/shape // - scalar type @@ -87,7 +92,7 @@ template struct evaluator : public unary_evaluator { typedef unary_evaluator Base; - evaluator(const T& xpr) : Base(xpr) {} + explicit evaluator(const T& xpr) : Base(xpr) {} }; @@ -150,7 +155,7 @@ struct evaluator > : RowsAtCompileTime) {} - evaluator(const PlainObjectType& m) + explicit evaluator(const PlainObjectType& m) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { } @@ -242,7 +247,7 @@ struct evaluator > evaluator() {} - evaluator(const XprType& m) + explicit evaluator(const XprType& m) : evaluator >(m) { } }; @@ -260,7 +265,7 @@ struct unary_evaluator, IndexBased> Flags = evaluator::Flags ^ RowMajorBit }; - unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -337,7 +342,7 @@ struct evaluator > | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) // FIXME EvalBeforeNestingBit should be needed anymore }; - evaluator(const XprType& n) + explicit evaluator(const XprType& n) : m_functor(n.functor()) { } @@ -387,7 +392,7 @@ struct unary_evaluator, IndexBased > | (functor_traits::PacketAccess ? PacketAccessBit : 0)) }; - unary_evaluator(const XprType& op) + explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -433,7 +438,7 @@ struct evaluator > typedef CwiseBinaryOp XprType; typedef binary_evaluator > Base; - evaluator(const XprType& xpr) : Base(xpr) {} + explicit evaluator(const XprType& xpr) : Base(xpr) {} }; template @@ -461,7 +466,7 @@ struct binary_evaluator, IndexBased, IndexBase Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) }; - binary_evaluator(const XprType& xpr) + explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -515,7 +520,7 @@ struct unary_evaluator, IndexBased> Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)) }; - unary_evaluator(const XprType& op) + explicit unary_evaluator(const XprType& op) : m_unaryOp(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -573,7 +578,7 @@ struct mapbase_evaluator : evaluator_base CoeffReadCost = NumTraits::ReadCost }; - mapbase_evaluator(const XprType& map) + explicit mapbase_evaluator(const XprType& map) : m_data(const_cast(map.data())), m_xpr(map) { @@ -663,7 +668,7 @@ struct evaluator > Flags = KeepsPacketAccess ? int(Flags2) : (int(Flags2) & ~PacketAccessBit) }; - evaluator(const XprType& map) + explicit evaluator(const XprType& map) : mapbase_evaluator(map) { } }; @@ -680,7 +685,7 @@ struct evaluator > Flags = evaluator >::Flags }; - evaluator(const XprType& ref) + explicit evaluator(const XprType& ref) : mapbase_evaluator(ref) { } }; @@ -731,7 +736,7 @@ struct evaluator > Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit }; typedef block_evaluator block_evaluator_type; - evaluator(const XprType& block) : block_evaluator_type(block) {} + explicit evaluator(const XprType& block) : block_evaluator_type(block) {} }; // no direct-access => dispatch to a unary evaluator @@ -741,7 +746,7 @@ struct block_evaluator XprType; - block_evaluator(const XprType& block) + explicit block_evaluator(const XprType& block) : unary_evaluator(block) {} }; @@ -752,7 +757,7 @@ struct unary_evaluator, IndexBa { typedef Block XprType; - unary_evaluator(const XprType& block) + explicit unary_evaluator(const XprType& block) : m_argImpl(block.nestedExpression()), m_startRow(block.startRow()), m_startCol(block.startCol()) @@ -831,7 +836,7 @@ struct block_evaluator XprType; - block_evaluator(const XprType& block) + explicit block_evaluator(const XprType& block) : mapbase_evaluator(block) { // FIXME this should be an internal assertion @@ -857,7 +862,7 @@ struct evaluator > Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits }; - evaluator(const XprType& select) + explicit evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), m_thenImpl(select.thenMatrix()), m_elseImpl(select.elseMatrix()) @@ -911,7 +916,7 @@ struct unary_evaluator > Flags = (evaluator::Flags & HereditaryBits & ~RowMajorBit) | (traits::Flags & RowMajorBit) }; - unary_evaluator(const XprType& replicate) + explicit unary_evaluator(const XprType& replicate) : m_arg(replicate.nestedExpression()), m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), @@ -975,7 +980,7 @@ struct evaluator > Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&HereditaryBits) }; - evaluator(const XprType expr) + explicit evaluator(const XprType expr) : m_expr(expr) {} @@ -1012,7 +1017,7 @@ struct evaluator_wrapper_base Flags = evaluator::Flags }; - evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} typedef typename ArgType::Index Index; typedef typename ArgType::Scalar Scalar; @@ -1074,7 +1079,7 @@ struct unary_evaluator > { typedef MatrixWrapper XprType; - unary_evaluator(const XprType& wrapper) + explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -1085,7 +1090,7 @@ struct unary_evaluator > { typedef ArrayWrapper XprType; - unary_evaluator(const XprType& wrapper) + explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -1131,7 +1136,7 @@ struct unary_evaluator > }; typedef internal::reverse_packet_cond reverse_packet; - unary_evaluator(const XprType& reverse) + explicit unary_evaluator(const XprType& reverse) : m_argImpl(reverse.nestedExpression()), m_rows(ReverseRow ? reverse.nestedExpression().rows() : 0), m_cols(ReverseCol ? reverse.nestedExpression().cols() : 0) @@ -1212,7 +1217,7 @@ struct evaluator > Flags = (unsigned int)evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit) & ~RowMajorBit }; - evaluator(const XprType& diagonal) + explicit evaluator(const XprType& diagonal) : m_argImpl(diagonal.nestedExpression()), m_index(diagonal.index()) { } @@ -1275,7 +1280,7 @@ class EvalToTemp typedef typename dense_xpr_base::type Base; EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) - EvalToTemp(const ArgType& arg) + explicit EvalToTemp(const ArgType& arg) : m_arg(arg) { } @@ -1309,7 +1314,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) + explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index 79a872934..708e3e818 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -63,7 +63,7 @@ class CwiseUnaryOp : internal::no_assignment_operator, typedef typename internal::remove_all::type NestedExpression; EIGEN_DEVICE_FUNC - inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + explicit inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 71249a39c..61fd8ee35 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -63,7 +63,7 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::type NestedExpression; - inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + explicit inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 6078af553..101ef6f20 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -275,6 +275,7 @@ template class DenseBase // TODO flagged is temporarly disabled. It seems useless now template + EIGEN_DEPRECATED const Derived& flagged() const { return derived(); } @@ -282,8 +283,9 @@ template class DenseBase EIGEN_DEVICE_FUNC CommaInitializer operator<< (const DenseBase& other); + typedef Transpose TransposeReturnType; EIGEN_DEVICE_FUNC - Eigen::Transpose transpose(); + TransposeReturnType transpose(); typedef typename internal::add_const >::type ConstTransposeReturnType; EIGEN_DEVICE_FUNC ConstTransposeReturnType transpose() const; diff --git a/Eigen/src/Core/DenseStorage.h b/Eigen/src/Core/DenseStorage.h index 59f515495..852648639 100644 --- a/Eigen/src/Core/DenseStorage.h +++ b/Eigen/src/Core/DenseStorage.h @@ -130,7 +130,7 @@ template class DenseSt public: EIGEN_DEVICE_FUNC DenseStorage() {} EIGEN_DEVICE_FUNC - DenseStorage(internal::constructor_without_unaligned_array_assert) + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} @@ -155,7 +155,7 @@ template class DenseStorage class DenseStorage class DenseStorage class DenseStorage class DenseStorage(size)), m_rows(nbRows), m_cols(nbCols) @@ -350,7 +350,7 @@ template class DenseStorage(size)), m_cols(nbCols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } DenseStorage(const DenseStorage& other) @@ -416,7 +416,7 @@ template class DenseStorage(size)), m_rows(nbRows) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } DenseStorage(const DenseStorage& other) diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 1ffcd97f9..ba7ddbb14 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -70,7 +70,7 @@ template class Diagonal EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) EIGEN_DEVICE_FUNC - inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) @@ -189,7 +189,7 @@ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { - return derived(); + return DiagonalReturnType(derived()); } /** This is the const version of diagonal(). */ @@ -238,20 +238,20 @@ MatrixBase::diagonal(Index index) const * * \sa MatrixBase::diagonal(), class Diagonal */ template -template -inline typename MatrixBase::template DiagonalIndexReturnType::Type +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { - return derived(); + return typename DiagonalIndexReturnType::Type(derived()); } /** This is the const version of diagonal(). */ template -template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { - return derived(); + return typename ConstDiagonalIndexReturnType::Type(derived()); } } // end namespace Eigen diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 44c249aa6..e3dc71336 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -63,24 +63,26 @@ class DiagonalBase : public EigenBase return Product(derived(),matrix.derived()); } + typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; EIGEN_DEVICE_FUNC - inline const DiagonalWrapper, const DiagonalVectorType> > + inline const InverseReturnType inverse() const { - return diagonal().cwiseInverse(); + return InverseReturnType(diagonal().cwiseInverse()); } + typedef DiagonalWrapper, const DiagonalVectorType> > ScalarMultipleReturnType; EIGEN_DEVICE_FUNC - inline const DiagonalWrapper, const DiagonalVectorType> > + inline const ScalarMultipleReturnType operator*(const Scalar& scalar) const { - return diagonal() * scalar; + return ScalarMultipleReturnType(diagonal() * scalar); } EIGEN_DEVICE_FUNC - friend inline const DiagonalWrapper, const DiagonalVectorType> > + friend inline const ScalarMultipleReturnType operator*(const Scalar& scalar, const DiagonalBase& other) { - return other.diagonal() * scalar; + return ScalarMultipleReturnType(other.diagonal() * scalar); } }; @@ -144,7 +146,7 @@ class DiagonalMatrix /** Constructs a diagonal matrix with given dimension */ EIGEN_DEVICE_FUNC - inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ EIGEN_DEVICE_FUNC @@ -253,7 +255,7 @@ class DiagonalWrapper /** Constructor from expression of diagonal coefficients to wrap. */ EIGEN_DEVICE_FUNC - inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ EIGEN_DEVICE_FUNC @@ -276,7 +278,7 @@ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { - return derived(); + return DiagonalWrapper(derived()); } /** \returns true if *this is approximately equal to a diagonal matrix, diff --git a/Eigen/src/Core/Flagged.h b/Eigen/src/Core/Flagged.h index 1f2955fc1..6ce11edf3 100644 --- a/Eigen/src/Core/Flagged.h +++ b/Eigen/src/Core/Flagged.h @@ -48,7 +48,7 @@ template clas ExpressionType, const ExpressionType&>::type ExpressionTypeNested; typedef typename ExpressionType::InnerIterator InnerIterator; - inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} + explicit inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } @@ -132,7 +132,7 @@ template inline const Flagged DenseBase::flagged() const { - return derived(); + return Flagged(derived()); } } // end namespace Eigen diff --git a/Eigen/src/Core/ForceAlignedAccess.h b/Eigen/src/Core/ForceAlignedAccess.h index 807c7a293..065acfa64 100644 --- a/Eigen/src/Core/ForceAlignedAccess.h +++ b/Eigen/src/Core/ForceAlignedAccess.h @@ -39,7 +39,7 @@ template class ForceAlignedAccess typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } @@ -127,7 +127,7 @@ template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } /** \returns an expression of *this with forced aligned access if \a Enable is true. @@ -138,7 +138,7 @@ template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } } // end namespace Eigen diff --git a/Eigen/src/Core/GlobalFunctions.h b/Eigen/src/Core/GlobalFunctions.h index 2067a2a6e..ee67b7d3c 100644 --- a/Eigen/src/Core/GlobalFunctions.h +++ b/Eigen/src/Core/GlobalFunctions.h @@ -15,7 +15,7 @@ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ NAME(const Eigen::ArrayBase& x) { \ - return x.derived(); \ + return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ } #define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ @@ -30,7 +30,7 @@ { \ static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ { \ - return x.derived(); \ + return typename NAME##_retval >::type(x.derived()); \ } \ }; diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 5cfa7e50c..706796b78 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -51,7 +51,7 @@ public: typedef typename internal::nested::type XprTypeNested; typedef typename internal::remove_all::type XprTypeNestedCleaned; - Inverse(const XprType &xpr) + explicit Inverse(const XprType &xpr) : m_xpr(xpr) {} diff --git a/Eigen/src/Core/Map.h b/Eigen/src/Core/Map.h index 87c1787bf..098f1c096 100644 --- a/Eigen/src/Core/Map.h +++ b/Eigen/src/Core/Map.h @@ -122,7 +122,7 @@ template class Ma * \param a_stride optional Stride object, passing the strides. */ EIGEN_DEVICE_FUNC - inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) + explicit inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) { PlainObjectType::Base::_check_template_params(); diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 6d3b344e8..3e68b1e91 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -128,7 +128,7 @@ template class MapBase } EIGEN_DEVICE_FUNC - inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) checkSanity(); diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 8a5821548..bb6c75387 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -214,7 +214,7 @@ class Matrix // FIXME is it still needed EIGEN_DEVICE_FUNC - Matrix(internal::constructor_without_unaligned_array_assert) + explicit Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 9dbbd6fb5..048060e6b 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -327,7 +327,7 @@ template class MatrixBase NoAlias noalias(); - // TODO forceAlignedAccess is temporarly disabled + // TODO forceAlignedAccess is temporarily disabled // Need to find a nicer workaround. inline const Derived& forceAlignedAccess() const { return derived(); } inline Derived& forceAlignedAccess() { return derived(); } @@ -343,10 +343,10 @@ template class MatrixBase /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } /////////// LU module /////////// diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h index a893b1761..248dd8eb0 100644 --- a/Eigen/src/Core/NestByValue.h +++ b/Eigen/src/Core/NestByValue.h @@ -40,7 +40,7 @@ template class NestByValue typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} inline Index rows() const { return m_expression.rows(); } inline Index cols() const { return m_expression.cols(); } diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 097c9c062..0ade75255 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -33,7 +33,7 @@ class NoAlias public: typedef typename ExpressionType::Scalar Scalar; - NoAlias(ExpressionType& expression) : m_expression(expression) {} + explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} template EIGEN_DEVICE_FUNC @@ -100,7 +100,7 @@ class NoAlias template NoAlias MatrixBase::noalias() { - return derived(); + return NoAlias(derived()); } } // end namespace Eigen diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 200518173..98c83047a 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -73,6 +73,7 @@ class PermutationBase : public EigenBase typedef PermutationMatrix PlainPermutationType; using Base::derived; + typedef Transpose TransposeReturnType; #endif /** Copies the other permutation into *this */ @@ -198,14 +199,14 @@ class PermutationBase : public EigenBase * * \note \note_try_to_help_rvo */ - inline Transpose inverse() const - { return derived(); } + inline TransposeReturnType inverse() const + { return TransposeReturnType(derived()); } /** \returns the tranpose permutation matrix. * * \note \note_try_to_help_rvo */ - inline Transpose transpose() const - { return derived(); } + inline TransposeReturnType transpose() const + { return TransposeReturnType(derived()); } /**** multiplication helpers to hopefully get RVO ****/ @@ -301,7 +302,7 @@ class PermutationMatrix : public PermutationBase::type // FIXME is it still needed ? /** \internal */ EIGEN_DEVICE_FUNC - PlainObjectBase(internal::constructor_without_unaligned_array_assert) + explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index f880e7696..69e569908 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -35,7 +35,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) : Base(xpr) {} + explicit evaluator(const XprType& xpr) : Base(xpr) {} }; // Catch scalar * ( A * B ) and transform it to (A*scalar) * B @@ -50,7 +50,7 @@ struct evaluator, const Produ typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) + explicit evaluator(const XprType& xpr) : Base(xpr.functor().m_other * xpr.nestedExpression().lhs() * xpr.nestedExpression().rhs()) {} }; @@ -66,7 +66,7 @@ struct evaluator, DiagIndex> > typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) + explicit evaluator(const XprType& xpr) : Base(Diagonal, DiagIndex>( Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), xpr.index() )) @@ -103,7 +103,7 @@ struct product_evaluator, ProductTag, LhsShape typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -242,7 +242,7 @@ struct generic_product_impl struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; struct adds { Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} + explicit adds(const Scalar& s) : m_scale(s) {} template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += m_scale * src; } @@ -377,7 +377,7 @@ struct product_evaluator, ProductTag, DenseShape, typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : m_lhs(xpr.lhs()), m_rhs(xpr.rhs()), m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! @@ -508,7 +508,7 @@ struct product_evaluator, LazyCoeffBasedProduc typedef Product XprType; typedef Product BaseProduct; typedef product_evaluator Base; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : Base(BaseProduct(xpr.lhs(),xpr.rhs())) {} }; @@ -739,7 +739,7 @@ struct product_evaluator, ProductTag, DiagonalSha StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) { } @@ -783,7 +783,7 @@ struct product_evaluator, ProductTag, DenseShape, enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) { } diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index c6c355d43..14a2671e9 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -340,7 +340,7 @@ class redux_evaluator { public: typedef _XprType XprType; - redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index f4e12a93b..5fcd9e3fc 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -103,7 +103,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) + explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index 01de90800..9ba6ea2e6 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -89,7 +89,7 @@ template class Reverse typedef internal::reverse_packet_cond reverse_packet; public: - inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) @@ -184,7 +184,7 @@ template inline typename DenseBase::ReverseReturnType DenseBase::reverse() { - return derived(); + return ReverseReturnType(derived()); } /** This is the const version of reverse(). */ @@ -192,7 +192,7 @@ template inline const typename DenseBase::ConstReverseReturnType DenseBase::reverse() const { - return derived(); + return ConstReverseReturnType(derived()); } /** This is the "in place" version of reverse: it reverses \c *this. diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 19cb232c9..f5fbd7215 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -67,7 +67,7 @@ template class SelfAdjointView typedef typename MatrixType::PlainObject PlainObject; EIGEN_DEVICE_FUNC - inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) + explicit inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix) {} EIGEN_DEVICE_FUNC @@ -258,7 +258,7 @@ template typename MatrixBase::template ConstSelfAdjointViewReturnType::Type MatrixBase::selfadjointView() const { - return derived(); + return typename ConstSelfAdjointViewReturnType::Type(derived()); } template @@ -266,7 +266,7 @@ template typename MatrixBase::template SelfAdjointViewReturnType::Type MatrixBase::selfadjointView() { - return derived(); + return typename SelfAdjointViewReturnType::Type(derived()); } } // end namespace Eigen diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index 7b12be1e6..641ffa218 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -121,7 +121,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - evaluator(const SolveType& solve) + explicit evaluator(const SolveType& solve) : m_result(solve.rows(), solve.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/Stride.h b/Eigen/src/Core/Stride.h index 187774978..e46faad34 100644 --- a/Eigen/src/Core/Stride.h +++ b/Eigen/src/Core/Stride.h @@ -93,7 +93,7 @@ class InnerStride : public Stride<0, Value> public: typedef DenseIndex Index; EIGEN_DEVICE_FUNC InnerStride() : Base() {} - EIGEN_DEVICE_FUNC InnerStride(Index v) : Base(0, v) {} + EIGEN_DEVICE_FUNC InnerStride(Index v) : Base(0, v) {} // FIXME making this explicit could break valid code }; /** \brief Convenience specialization of Stride to specify only an outer stride @@ -105,7 +105,7 @@ class OuterStride : public Stride public: typedef DenseIndex Index; EIGEN_DEVICE_FUNC OuterStride() : Base() {} - EIGEN_DEVICE_FUNC OuterStride(Index v) : Base(v,0) {} + EIGEN_DEVICE_FUNC OuterStride(Index v) : Base(v,0) {} // FIXME making this explicit could break valid code }; } // end namespace Eigen diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 144bb2c01..57d6fd2fe 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -64,7 +64,7 @@ template class Transpose typedef typename internal::remove_all::type NestedExpression; EIGEN_DEVICE_FUNC - inline Transpose(MatrixType& a_matrix) : m_matrix(a_matrix) {} + explicit inline Transpose(MatrixType& a_matrix) : m_matrix(a_matrix) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Transpose) @@ -169,7 +169,7 @@ template inline Transpose DenseBase::transpose() { - return derived(); + return TransposeReturnType(derived()); } /** This is the const version of transpose(). @@ -207,8 +207,7 @@ template inline const typename MatrixBase::AdjointReturnType MatrixBase::adjoint() const { - return this->transpose(); // in the complex case, the .conjugate() is be implicit here - // due to implicit conversion to return type + return AdjointReturnType(this->transpose()); } /*************************************************************************** diff --git a/Eigen/src/Core/Transpositions.h b/Eigen/src/Core/Transpositions.h index 92261118f..77e7d6f45 100644 --- a/Eigen/src/Core/Transpositions.h +++ b/Eigen/src/Core/Transpositions.h @@ -240,7 +240,7 @@ class Map > typedef typename TranspositionType::IndicesType IndicesType; public: - Transpose(const TranspositionType& t) : m_transpositions(t) {} + explicit Transpose(const TranspositionType& t) : m_transpositions(t) {} inline int size() const { return m_transpositions.size(); } diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 36f04a5e8..36bbd46e1 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -211,8 +211,9 @@ template class TriangularView IsVectorAtCompileTime = false }; + // FIXME This, combined with const_cast_derived in transpose() leads to a const-correctness loophole EIGEN_DEVICE_FUNC - inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) + explicit inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) {} using Base::operator=; @@ -229,32 +230,36 @@ template class TriangularView EIGEN_DEVICE_FUNC NestedExpression& nestedExpression() { return *const_cast(&m_matrix); } + typedef TriangularView ConjugateReturnType; /** \sa MatrixBase::conjugate() */ EIGEN_DEVICE_FUNC - inline TriangularView conjugate() - { return m_matrix.conjugate(); } + inline ConjugateReturnType conjugate() + { return ConjugateReturnType(m_matrix.conjugate()); } /** \sa MatrixBase::conjugate() const */ + EIGEN_DEVICE_FUNC - inline const TriangularView conjugate() const - { return m_matrix.conjugate(); } + inline const ConjugateReturnType conjugate() const + { return ConjugateReturnType(m_matrix.conjugate()); } + typedef TriangularView AdjointReturnType; /** \sa MatrixBase::adjoint() const */ EIGEN_DEVICE_FUNC - inline const TriangularView adjoint() const - { return m_matrix.adjoint(); } + inline const AdjointReturnType adjoint() const + { return AdjointReturnType(m_matrix.adjoint()); } - /** \sa MatrixBase::transpose() */ + typedef TriangularView,TransposeMode> TransposeReturnType; + /** \sa MatrixBase::transpose() */ EIGEN_DEVICE_FUNC - inline TriangularView,TransposeMode> transpose() + inline TransposeReturnType transpose() { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().transpose(); + return TransposeReturnType(m_matrix.const_cast_derived().transpose()); } /** \sa MatrixBase::transpose() const */ EIGEN_DEVICE_FUNC - inline const TriangularView,TransposeMode> transpose() const + inline const TransposeReturnType transpose() const { - return m_matrix.transpose(); + return TransposeReturnType(m_matrix.transpose()); } template @@ -556,7 +561,7 @@ template typename MatrixBase::template TriangularViewReturnType::Type MatrixBase::triangularView() { - return derived(); + return typename TriangularViewReturnType::Type(derived()); } /** This is the const version of MatrixBase::triangularView() */ @@ -565,7 +570,7 @@ template typename MatrixBase::template ConstTriangularViewReturnType::Type MatrixBase::triangularView() const { - return derived(); + return typename ConstTriangularViewReturnType::Type(derived()); } /** \returns true if *this is approximately equal to an upper triangular matrix, diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index a8130e902..e340c1433 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -65,7 +65,7 @@ class PartialReduxExpr : internal::no_assignment_operator, typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - PartialReduxExpr(const MatrixType& mat, const MemberOp& func = MemberOp()) + explicit PartialReduxExpr(const MatrixType& mat, const MemberOp& func = MemberOp()) : m_matrix(mat), m_functor(func) {} Index rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); } @@ -128,7 +128,7 @@ struct member_redux { >::type result_type; template struct Cost { enum { value = (Size-1) * functor_traits::Cost }; }; - member_redux(const BinaryOp func) : m_functor(func) {} + member_redux(const BinaryOp func) : m_functor(func) {} // FIXME this should actually be explicit, but lets not exaggerate template inline result_type operator()(const DenseBase& mat) const { return mat.redux(m_functor); } @@ -249,7 +249,7 @@ template class VectorwiseOp public: - inline VectorwiseOp(ExpressionType& matrix) : m_matrix(matrix) {} + explicit inline VectorwiseOp(ExpressionType& matrix) : m_matrix(matrix) {} /** \internal */ inline const ExpressionType& _expression() const { return m_matrix; } @@ -266,6 +266,21 @@ template class VectorwiseOp redux(const BinaryOp& func = BinaryOp()) const { return typename ReduxReturnType::Type(_expression(), func); } + typedef typename ReturnType::Type MinCoeffReturnType; + typedef typename ReturnType::Type MaxCoeffReturnType; + typedef typename ReturnType::Type SquareNormReturnType; + typedef typename ReturnType::Type NormReturnType; + typedef typename ReturnType::Type BlueNormReturnType; + typedef typename ReturnType::Type StableNormReturnType; + typedef typename ReturnType::Type HypotNormReturnType; + typedef typename ReturnType::Type SumReturnType; + typedef typename ReturnType::Type MeanReturnType; + typedef typename ReturnType::Type AllReturnType; + typedef typename ReturnType::Type AnyReturnType; + typedef PartialReduxExpr, Direction> CountReturnType; + typedef typename ReturnType::Type ProdReturnType; + typedef Reverse ReverseReturnType; + /** \returns a row (or column) vector expression of the smallest coefficient * of each column (or row) of the referenced expression. * @@ -275,8 +290,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_minCoeff.out * * \sa DenseBase::minCoeff() */ - const typename ReturnType::Type minCoeff() const - { return _expression(); } + const MinCoeffReturnType minCoeff() const + { return MinCoeffReturnType(_expression()); } /** \returns a row (or column) vector expression of the largest coefficient * of each column (or row) of the referenced expression. @@ -287,8 +302,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_maxCoeff.out * * \sa DenseBase::maxCoeff() */ - const typename ReturnType::Type maxCoeff() const - { return _expression(); } + const MaxCoeffReturnType maxCoeff() const + { return MaxCoeffReturnType(_expression()); } /** \returns a row (or column) vector expression of the squared norm * of each column (or row) of the referenced expression. @@ -298,8 +313,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_squaredNorm.out * * \sa DenseBase::squaredNorm() */ - const typename ReturnType::Type squaredNorm() const - { return _expression(); } + const SquareNormReturnType squaredNorm() const + { return SquareNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression. @@ -309,8 +324,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_norm.out * * \sa DenseBase::norm() */ - const typename ReturnType::Type norm() const - { return _expression(); } + const NormReturnType norm() const + { return NormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm @@ -319,8 +334,8 @@ template class VectorwiseOp * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::blueNorm() */ - const typename ReturnType::Type blueNorm() const - { return _expression(); } + const BlueNormReturnType blueNorm() const + { return BlueNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm @@ -329,8 +344,8 @@ template class VectorwiseOp * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::stableNorm() */ - const typename ReturnType::Type stableNorm() const - { return _expression(); } + const StableNormReturnType stableNorm() const + { return StableNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm @@ -339,8 +354,8 @@ template class VectorwiseOp * This is a vector with real entries, even if the original matrix has complex entries. * * \sa DenseBase::hypotNorm() */ - const typename ReturnType::Type hypotNorm() const - { return _expression(); } + const HypotNormReturnType hypotNorm() const + { return HypotNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the sum * of each column (or row) of the referenced expression. @@ -349,31 +364,31 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_sum.out * * \sa DenseBase::sum() */ - const typename ReturnType::Type sum() const - { return _expression(); } + const SumReturnType sum() const + { return SumReturnType(_expression()); } /** \returns a row (or column) vector expression of the mean * of each column (or row) of the referenced expression. * * \sa DenseBase::mean() */ - const typename ReturnType::Type mean() const - { return _expression(); } + const MeanReturnType mean() const + { return MeanReturnType(_expression()); } /** \returns a row (or column) vector expression representing * whether \b all coefficients of each respective column (or row) are \c true. * This expression can be assigned to a vector with entries of type \c bool. * * \sa DenseBase::all() */ - const typename ReturnType::Type all() const - { return _expression(); } + const AllReturnType all() const + { return AllReturnType(_expression()); } /** \returns a row (or column) vector expression representing * whether \b at \b least one coefficient of each respective column (or row) is \c true. * This expression can be assigned to a vector with entries of type \c bool. * * \sa DenseBase::any() */ - const typename ReturnType::Type any() const - { return _expression(); } + const AnyReturnType any() const + { return Any(_expression()); } /** \returns a row (or column) vector expression representing * the number of \c true coefficients of each respective column (or row). @@ -384,8 +399,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_count.out * * \sa DenseBase::count() */ - const PartialReduxExpr, Direction> count() const - { return _expression(); } + const CountReturnType count() const + { return CountReturnType(_expression()); } /** \returns a row (or column) vector expression of the product * of each column (or row) of the referenced expression. @@ -394,8 +409,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_prod.out * * \sa DenseBase::prod() */ - const typename ReturnType::Type prod() const - { return _expression(); } + const ProdReturnType prod() const + { return ProdReturnType(_expression()); } /** \returns a matrix expression @@ -405,8 +420,8 @@ template class VectorwiseOp * Output: \verbinclude Vectorwise_reverse.out * * \sa DenseBase::reverse() */ - const Reverse reverse() const - { return Reverse( _expression() ); } + const ReverseReturnType reverse() const + { return ReverseReturnType( _expression() ); } typedef Replicate ReplicateReturnType; const ReplicateReturnType replicate(Index factor) const; @@ -550,7 +565,8 @@ template class VectorwiseOp /////////// Geometry module /////////// - Homogeneous homogeneous() const; + typedef Homogeneous HomogeneousReturnType; + HomogeneousReturnType homogeneous() const; typedef typename ExpressionType::PlainObject CrossReturnType; template @@ -595,7 +611,7 @@ template inline const typename DenseBase::ConstColwiseReturnType DenseBase::colwise() const { - return derived(); + return ConstColwiseReturnType(derived()); } /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations @@ -606,7 +622,7 @@ template inline typename DenseBase::ColwiseReturnType DenseBase::colwise() { - return derived(); + return ColwiseReturnType(derived()); } /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations @@ -620,7 +636,7 @@ template inline const typename DenseBase::ConstRowwiseReturnType DenseBase::rowwise() const { - return derived(); + return ConstRowwiseReturnType(derived()); } /** \returns a writable VectorwiseOp wrapper of *this providing additional partial reduction operations @@ -631,7 +647,7 @@ template inline typename DenseBase::RowwiseReturnType DenseBase::rowwise() { - return derived(); + return RowwiseReturnType(derived()); } } // end namespace Eigen diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h index 810ec28e7..02bd4eff3 100644 --- a/Eigen/src/Core/Visitor.h +++ b/Eigen/src/Core/Visitor.h @@ -58,7 +58,7 @@ template class visitor_evaluator { public: - visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; diff --git a/Eigen/src/Core/products/SelfadjointRank2Update.h b/Eigen/src/Core/products/SelfadjointRank2Update.h index 8594a97ce..2ae364111 100644 --- a/Eigen/src/Core/products/SelfadjointRank2Update.h +++ b/Eigen/src/Core/products/SelfadjointRank2Update.h @@ -79,11 +79,11 @@ SelfAdjointView& SelfAdjointView if (IsRowMajor) actualAlpha = numext::conj(actualAlpha); - internal::selfadjoint_rank2_update_selector::type>::type, - typename internal::remove_all::type>::type, + typedef typename internal::remove_all::type>::type UType; + typedef typename internal::remove_all::type>::type VType; + internal::selfadjoint_rank2_update_selector - ::run(_expression().const_cast_derived().data(),_expression().outerStride(),actualU,actualV,actualAlpha); + ::run(_expression().const_cast_derived().data(),_expression().outerStride(),UType(actualU),VType(actualV),actualAlpha); return *this; } diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h index 0d8e2705a..9f9115c2a 100644 --- a/Eigen/src/Core/util/BlasUtil.h +++ b/Eigen/src/Core/util/BlasUtil.h @@ -231,7 +231,7 @@ struct blas_traits > enum { IsTransposed = Base::IsTransposed ? 0 : 1 }; - static inline ExtractType extract(const XprType& x) { return Base::extract(x.nestedExpression()); } + static inline ExtractType extract(const XprType& x) { return ExtractType(Base::extract(x.nestedExpression())); } static inline Scalar extractScalarFactor(const XprType& x) { return Base::extractScalarFactor(x.nestedExpression()); } }; diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index af434bc9b..25082546e 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -104,7 +104,7 @@ template class ComplexEigenSolver * according to the specified problem \a size. * \sa ComplexEigenSolver() */ - ComplexEigenSolver(Index size) + explicit ComplexEigenSolver(Index size) : m_eivec(size, size), m_eivalues(size), m_schur(size), @@ -122,7 +122,7 @@ template class ComplexEigenSolver * * This constructor calls compute() to compute the eigendecomposition. */ - ComplexEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) + explicit ComplexEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(),matrix.cols()), m_eivalues(matrix.cols()), m_schur(matrix.rows()), diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 89e6cade3..a3a5a4649 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -91,7 +91,7 @@ template class ComplexSchur * * \sa compute() for an example. */ - ComplexSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) + explicit ComplexSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) : m_matT(size,size), m_matU(size,size), m_hess(size), @@ -109,7 +109,7 @@ template class ComplexSchur * * \sa matrixT() and matrixU() for examples. */ - ComplexSchur(const MatrixType& matrix, bool computeU = true) + explicit ComplexSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_hess(matrix.rows()), diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index d2563d470..8a83b85bb 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -118,7 +118,7 @@ template class EigenSolver * according to the specified problem \a size. * \sa EigenSolver() */ - EigenSolver(Index size) + explicit EigenSolver(Index size) : m_eivec(size, size), m_eivalues(size), m_isInitialized(false), @@ -143,7 +143,7 @@ template class EigenSolver * * \sa compute() */ - EigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) + explicit EigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), m_isInitialized(false), diff --git a/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h index dc240e13e..c20ea03e6 100644 --- a/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +++ b/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h @@ -122,7 +122,7 @@ template class GeneralizedEigenSolver * according to the specified problem \a size. * \sa GeneralizedEigenSolver() */ - GeneralizedEigenSolver(Index size) + explicit GeneralizedEigenSolver(Index size) : m_eivec(size, size), m_alphas(size), m_betas(size), @@ -145,7 +145,7 @@ template class GeneralizedEigenSolver * * \sa compute() */ - GeneralizedEigenSolver(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true) + explicit GeneralizedEigenSolver(const MatrixType& A, const MatrixType& B, bool computeEigenvectors = true) : m_eivec(A.rows(), A.cols()), m_alphas(A.cols()), m_betas(A.cols()), diff --git a/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h index 07bf1ea09..1ce1f5f58 100644 --- a/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h @@ -74,7 +74,7 @@ class GeneralizedSelfAdjointEigenSolver : public SelfAdjointEigenSolver<_MatrixT * * \sa compute() for an example */ - GeneralizedSelfAdjointEigenSolver(Index size) + explicit GeneralizedSelfAdjointEigenSolver(Index size) : Base(size) {} diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index 3db0c0106..2615a9f23 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -97,7 +97,7 @@ template class HessenbergDecomposition * * \sa compute() for an example. */ - HessenbergDecomposition(Index size = Size==Dynamic ? 2 : Size) + explicit HessenbergDecomposition(Index size = Size==Dynamic ? 2 : Size) : m_matrix(size,size), m_temp(size), m_isInitialized(false) @@ -115,7 +115,7 @@ template class HessenbergDecomposition * * \sa matrixH() for an example. */ - HessenbergDecomposition(const MatrixType& matrix) + explicit HessenbergDecomposition(const MatrixType& matrix) : m_matrix(matrix), m_temp(matrix.rows()), m_isInitialized(false) diff --git a/Eigen/src/Eigenvalues/RealQZ.h b/Eigen/src/Eigenvalues/RealQZ.h index 5706eeebe..ae10ff91e 100644 --- a/Eigen/src/Eigenvalues/RealQZ.h +++ b/Eigen/src/Eigenvalues/RealQZ.h @@ -83,7 +83,7 @@ namespace Eigen { * * \sa compute() for an example. */ - RealQZ(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) : + explicit RealQZ(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) : m_S(size, size), m_T(size, size), m_Q(size, size), @@ -101,7 +101,7 @@ namespace Eigen { * * This constructor calls compute() to compute the QZ decomposition. */ - RealQZ(const MatrixType& A, const MatrixType& B, bool computeQZ = true) : + explicit RealQZ(const MatrixType& A, const MatrixType& B, bool computeQZ = true) : m_S(A.rows(),A.cols()), m_T(A.rows(),A.cols()), m_Q(A.rows(),A.cols()), diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index 64d136341..10f5fb174 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -80,7 +80,7 @@ template class RealSchur * * \sa compute() for an example. */ - RealSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) + explicit RealSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime) : m_matT(size, size), m_matU(size, size), m_workspaceVector(size), @@ -100,7 +100,7 @@ template class RealSchur * Example: \include RealSchur_RealSchur_MatrixType.cpp * Output: \verbinclude RealSchur_RealSchur_MatrixType.out */ - RealSchur(const MatrixType& matrix, bool computeU = true) + explicit RealSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_workspaceVector(matrix.rows()), diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index a6bbdac6b..1dd2ab45b 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -133,7 +133,7 @@ template class SelfAdjointEigenSolver * \sa compute() for an example */ EIGEN_DEVICE_FUNC - SelfAdjointEigenSolver(Index size) + explicit SelfAdjointEigenSolver(Index size) : m_eivec(size, size), m_eivalues(size), m_subdiag(size > 1 ? size - 1 : 1), @@ -156,7 +156,7 @@ template class SelfAdjointEigenSolver * \sa compute(const MatrixType&, int) */ EIGEN_DEVICE_FUNC - SelfAdjointEigenSolver(const MatrixType& matrix, int options = ComputeEigenvectors) + explicit SelfAdjointEigenSolver(const MatrixType& matrix, int options = ComputeEigenvectors) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1), diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index e3a27f275..f20528f86 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -112,7 +112,7 @@ template class Tridiagonalization * * \sa compute() for an example. */ - Tridiagonalization(Index size = Size==Dynamic ? 2 : Size) + explicit Tridiagonalization(Index size = Size==Dynamic ? 2 : Size) : m_matrix(size,size), m_hCoeffs(size > 1 ? size-1 : 1), m_isInitialized(false) @@ -128,7 +128,7 @@ template class Tridiagonalization * Example: \include Tridiagonalization_Tridiagonalization_MatrixType.cpp * Output: \verbinclude Tridiagonalization_Tridiagonalization_MatrixType.out */ - Tridiagonalization(const MatrixType& matrix) + explicit Tridiagonalization(const MatrixType& matrix) : m_matrix(matrix), m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1), m_isInitialized(false) diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index d1881d84d..ede203ef9 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -68,7 +68,7 @@ template class Homogeneous typedef MatrixBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Homogeneous) - inline Homogeneous(const MatrixType& matrix) + explicit inline Homogeneous(const MatrixType& matrix) : m_matrix(matrix) {} @@ -128,7 +128,7 @@ inline typename MatrixBase::HomogeneousReturnType MatrixBase::homogeneous() const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); - return derived(); + return HomogeneousReturnType(derived()); } /** \geometry_module @@ -143,7 +143,7 @@ template inline Homogeneous VectorwiseOp::homogeneous() const { - return _expression(); + return HomogeneousReturnType(_expression()); } /** \geometry_module @@ -323,7 +323,7 @@ struct unary_evaluator, IndexBased> typedef evaluator type; typedef evaluator nestedType; - unary_evaluator(const XprType& op) + explicit unary_evaluator(const XprType& op) : Base(), m_temp(op) { ::new (static_cast(this)) Base(m_temp); diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 3f0067286..216e5b12f 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -251,7 +251,7 @@ public: inline Quaternion(const Scalar& w, const Scalar& x, const Scalar& y, const Scalar& z) : m_coeffs(x, y, z, w){} /** Constructs and initialize a quaternion from the array data */ - inline Quaternion(const Scalar* data) : m_coeffs(data) {} + explicit inline Quaternion(const Scalar* data) : m_coeffs(data) {} /** Copy constructor */ template EIGEN_STRONG_INLINE Quaternion(const QuaternionBase& other) { this->Base::operator=(other); } @@ -351,7 +351,7 @@ class Map, _Options > * \code *coeffs == {x, y, z, w} \endcode * * If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */ - EIGEN_STRONG_INLINE Map(const Scalar* coeffs) : m_coeffs(coeffs) {} + explicit EIGEN_STRONG_INLINE Map(const Scalar* coeffs) : m_coeffs(coeffs) {} inline const Coefficients& coeffs() const { return m_coeffs;} @@ -388,7 +388,7 @@ class Map, _Options > * \code *coeffs == {x, y, z, w} \endcode * * If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */ - EIGEN_STRONG_INLINE Map(Scalar* coeffs) : m_coeffs(coeffs) {} + explicit EIGEN_STRONG_INLINE Map(Scalar* coeffs) : m_coeffs(coeffs) {} inline Coefficients& coeffs() { return m_coeffs; } inline const Coefficients& coeffs() const { return m_coeffs; } diff --git a/Eigen/src/Geometry/Rotation2D.h b/Eigen/src/Geometry/Rotation2D.h index 1cac343a5..c82762acd 100644 --- a/Eigen/src/Geometry/Rotation2D.h +++ b/Eigen/src/Geometry/Rotation2D.h @@ -59,7 +59,7 @@ protected: public: /** Construct a 2D counter clock wise rotation from the angle \a a in radian. */ - inline Rotation2D(const Scalar& a) : m_angle(a) {} + explicit inline Rotation2D(const Scalar& a) : m_angle(a) {} /** \returns the rotation angle */ inline Scalar angle() const { return m_angle; } diff --git a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h index 98b169868..3991afa8f 100644 --- a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +++ b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h @@ -43,7 +43,7 @@ class DiagonalPreconditioner DiagonalPreconditioner() : m_isInitialized(false) {} template - DiagonalPreconditioner(const MatType& mat) : m_invdiag(mat.cols()) + explicit DiagonalPreconditioner(const MatType& mat) : m_invdiag(mat.cols()) { compute(mat); } @@ -114,7 +114,7 @@ class IdentityPreconditioner IdentityPreconditioner() {} template - IdentityPreconditioner(const MatrixType& ) {} + explicit IdentityPreconditioner(const MatrixType& ) {} template IdentityPreconditioner& analyzePattern(const MatrixType& ) { return *this; } diff --git a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index 42da7d14b..224fe913f 100644 --- a/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -178,7 +178,7 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - BiCGSTAB(const MatrixType& A) : Base(A) {} + explicit BiCGSTAB(const MatrixType& A) : Base(A) {} ~BiCGSTAB() {} diff --git a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index f72cf86a5..b5ef6d60f 100644 --- a/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -189,7 +189,7 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - ConjugateGradient(const MatrixType& A) : Base(A) {} + explicit ConjugateGradient(const MatrixType& A) : Base(A) {} ~ConjugateGradient() {} diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index 7adbbc489..8ed9bdecc 100644 --- a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -116,7 +116,7 @@ class IncompleteLUT : public SparseSolverBase > {} template - IncompleteLUT(const MatrixType& mat, const RealScalar& droptol=NumTraits::dummy_precision(), int fillfactor = 10) + explicit IncompleteLUT(const MatrixType& mat, const RealScalar& droptol=NumTraits::dummy_precision(), int fillfactor = 10) : m_droptol(droptol),m_fillfactor(fillfactor), m_analysisIsOk(false),m_factorizationIsOk(false) { diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 1ca7e0561..f33c868bb 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -52,7 +52,7 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - IterativeSolverBase(const MatrixType& A) + explicit IterativeSolverBase(const MatrixType& A) { init(); compute(A); diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index fdf2e0642..96f2cebee 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -94,7 +94,7 @@ template class FullPivLU * \param matrix the matrix of which to compute the LU decomposition. * It is required to be nonzero. */ - FullPivLU(const MatrixType& matrix); + explicit FullPivLU(const MatrixType& matrix); /** Computes the LU decomposition of the given matrix. * diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index a4d22ce5f..d04e4191b 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -92,7 +92,7 @@ template class PartialPivLU * according to the specified problem \a size. * \sa PartialPivLU() */ - PartialPivLU(Index size); + explicit PartialPivLU(Index size); /** Constructor. * @@ -101,7 +101,7 @@ template class PartialPivLU * \warning The matrix should have full rank (e.g. if it's square, it should be invertible). * If you need to deal with non-full rank, use class FullPivLU instead. */ - PartialPivLU(const MatrixType& matrix); + explicit PartialPivLU(const MatrixType& matrix); PartialPivLU& compute(const MatrixType& matrix); diff --git a/Eigen/src/PaStiXSupport/PaStiXSupport.h b/Eigen/src/PaStiXSupport/PaStiXSupport.h index bb8e0d1a8..a96c27695 100644 --- a/Eigen/src/PaStiXSupport/PaStiXSupport.h +++ b/Eigen/src/PaStiXSupport/PaStiXSupport.h @@ -417,7 +417,7 @@ class PastixLU : public PastixBase< PastixLU<_MatrixType> > init(); } - PastixLU(const MatrixType& matrix):Base() + explicit PastixLU(const MatrixType& matrix):Base() { init(); compute(matrix); @@ -527,7 +527,7 @@ class PastixLLT : public PastixBase< PastixLLT<_MatrixType, _UpLo> > init(); } - PastixLLT(const MatrixType& matrix):Base() + explicit PastixLLT(const MatrixType& matrix):Base() { init(); compute(matrix); @@ -608,7 +608,7 @@ class PastixLDLT : public PastixBase< PastixLDLT<_MatrixType, _UpLo> > init(); } - PastixLDLT(const MatrixType& matrix):Base() + explicit PastixLDLT(const MatrixType& matrix):Base() { init(); compute(matrix); diff --git a/Eigen/src/PardisoSupport/PardisoSupport.h b/Eigen/src/PardisoSupport/PardisoSupport.h index e1b0e1818..054af6635 100644 --- a/Eigen/src/PardisoSupport/PardisoSupport.h +++ b/Eigen/src/PardisoSupport/PardisoSupport.h @@ -391,7 +391,7 @@ class PardisoLU : public PardisoImpl< PardisoLU > pardisoInit(Base::ScalarIsComplex ? 13 : 11); } - PardisoLU(const MatrixType& matrix) + explicit PardisoLU(const MatrixType& matrix) : Base() { pardisoInit(Base::ScalarIsComplex ? 13 : 11); @@ -442,7 +442,7 @@ class PardisoLLT : public PardisoImpl< PardisoLLT > pardisoInit(Base::ScalarIsComplex ? 4 : 2); } - PardisoLLT(const MatrixType& matrix) + explicit PardisoLLT(const MatrixType& matrix) : Base() { pardisoInit(Base::ScalarIsComplex ? 4 : 2); @@ -500,7 +500,7 @@ class PardisoLDLT : public PardisoImpl< PardisoLDLT > pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2); } - PardisoLDLT(const MatrixType& matrix) + explicit PardisoLDLT(const MatrixType& matrix) : Base() { pardisoInit(Base::ScalarIsComplex ? ( bool(Options&Symmetric) ? 6 : -4 ) : -2); diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index adf737276..de77e8411 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -117,7 +117,7 @@ template class ColPivHouseholderQR * * \sa compute() */ - ColPivHouseholderQR(const MatrixType& matrix) + explicit ColPivHouseholderQR(const MatrixType& matrix) : m_qr(matrix.rows(), matrix.cols()), m_hCoeffs((std::min)(matrix.rows(),matrix.cols())), m_colsPermutation(PermIndexType(matrix.cols())), diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 710c64a45..5712d175c 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -120,7 +120,7 @@ template class FullPivHouseholderQR * * \sa compute() */ - FullPivHouseholderQR(const MatrixType& matrix) + explicit FullPivHouseholderQR(const MatrixType& matrix) : m_qr(matrix.rows(), matrix.cols()), m_hCoeffs((std::min)(matrix.rows(), matrix.cols())), m_rows_transpositions((std::min)(matrix.rows(), matrix.cols())), diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 0b0c9d1bd..f22008494 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -91,7 +91,7 @@ template class HouseholderQR * * \sa compute() */ - HouseholderQR(const MatrixType& matrix) + explicit HouseholderQR(const MatrixType& matrix) : m_qr(matrix.rows(), matrix.cols()), m_hCoeffs((std::min)(matrix.rows(),matrix.cols())), m_temp(matrix.cols()), diff --git a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h index bcdc981d7..44f6a1acb 100644 --- a/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +++ b/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h @@ -65,7 +65,7 @@ class SPQR : public SparseSolverBase > typedef typename _MatrixType::RealScalar RealScalar; typedef UF_long Index ; typedef SparseMatrix MatrixType; - typedef PermutationMatrix PermutationType; + typedef Map > PermutationType; public: SPQR() : m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()) @@ -73,7 +73,7 @@ class SPQR : public SparseSolverBase > cholmod_l_start(&m_cc); } - SPQR(const _MatrixType& matrix) + explicit SPQR(const _MatrixType& matrix) : m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits::epsilon()) { cholmod_l_start(&m_cc); @@ -164,11 +164,7 @@ class SPQR : public SparseSolverBase > PermutationType colsPermutation() const { eigen_assert(m_isInitialized && "Decomposition is not initialized."); - Index n = m_cR->ncol; - PermutationType colsPerm(n); - for(Index j = 0; j ncol); } /** * Gets the rank of the matrix. diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index f2a72faa3..59f88a15a 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -550,7 +550,7 @@ template class JacobiSVD * according to the specified problem size. * \sa JacobiSVD() */ - JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) + explicit JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) { allocate(rows, cols, computationOptions); } @@ -565,7 +565,7 @@ template class JacobiSVD * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not * available with the (non-default) FullPivHouseholderQR preconditioner. */ - JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) + explicit JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) { compute(matrix, computationOptions); } diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h index 40b1237a0..eaa6bb86e 100644 --- a/Eigen/src/SVD/UpperBidiagonalization.h +++ b/Eigen/src/SVD/UpperBidiagonalization.h @@ -37,7 +37,7 @@ template class UpperBidiagonalization typedef Matrix SuperDiagVectorType; typedef HouseholderSequence< const MatrixType, - CwiseUnaryOp, const Diagonal > + const typename internal::remove_all::ConjugateReturnType>::type > HouseholderUSequenceType; typedef HouseholderSequence< const typename internal::remove_all::type, @@ -53,7 +53,7 @@ template class UpperBidiagonalization */ UpperBidiagonalization() : m_householder(), m_bidiagonal(), m_isInitialized(false) {} - UpperBidiagonalization(const MatrixType& matrix) + explicit UpperBidiagonalization(const MatrixType& matrix) : m_householder(matrix.rows(), matrix.cols()), m_bidiagonal(matrix.cols(), matrix.cols()), m_isInitialized(false) diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index 3c8cef5db..0e8fa6628 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -57,7 +57,7 @@ class SimplicialCholeskyBase : public SparseSolverBase : m_info(Success), m_shiftOffset(0), m_shiftScale(1) {} - SimplicialCholeskyBase(const MatrixType& matrix) + explicit SimplicialCholeskyBase(const MatrixType& matrix) : m_info(Success), m_shiftOffset(0), m_shiftScale(1) { derived().compute(matrix); @@ -239,8 +239,8 @@ template struct traits CholMatrixType; typedef TriangularView MatrixL; typedef TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct traits > @@ -253,8 +253,8 @@ template struct traits CholMatrixType; typedef TriangularView MatrixL; typedef TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct traits > @@ -303,7 +303,7 @@ public: /** Default constructor */ SimplicialLLT() : Base() {} /** Constructs and performs the LLT factorization of \a matrix */ - SimplicialLLT(const MatrixType& matrix) + explicit SimplicialLLT(const MatrixType& matrix) : Base(matrix) {} /** \returns an expression of the factor L */ @@ -393,7 +393,7 @@ public: SimplicialLDLT() : Base() {} /** Constructs and performs the LLT factorization of \a matrix */ - SimplicialLDLT(const MatrixType& matrix) + explicit SimplicialLDLT(const MatrixType& matrix) : Base(matrix) {} /** \returns a vector expression of the diagonal D */ @@ -473,7 +473,7 @@ public: public: SimplicialCholesky() : Base(), m_LDLT(true) {} - SimplicialCholesky(const MatrixType& matrix) + explicit SimplicialCholesky(const MatrixType& matrix) : Base(), m_LDLT(true) { compute(matrix); diff --git a/Eigen/src/SparseCore/AmbiVector.h b/Eigen/src/SparseCore/AmbiVector.h index 17fff96a7..5c9c3101e 100644 --- a/Eigen/src/SparseCore/AmbiVector.h +++ b/Eigen/src/SparseCore/AmbiVector.h @@ -27,7 +27,7 @@ class AmbiVector typedef _Index Index; typedef typename NumTraits::Real RealScalar; - AmbiVector(Index size) + explicit AmbiVector(Index size) : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) { resize(size); @@ -288,7 +288,7 @@ class AmbiVector<_Scalar,_Index>::Iterator * In practice, all coefficients having a magnitude smaller than \a epsilon * are skipped. */ - Iterator(const AmbiVector& vec, const RealScalar& epsilon = 0) + explicit Iterator(const AmbiVector& vec, const RealScalar& epsilon = 0) : m_vector(vec) { using std::abs; diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h index a667cb56e..a93550340 100644 --- a/Eigen/src/SparseCore/CompressedStorage.h +++ b/Eigen/src/SparseCore/CompressedStorage.h @@ -36,7 +36,7 @@ class CompressedStorage : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) {} - CompressedStorage(size_t size) + explicit CompressedStorage(size_t size) : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) { resize(size); diff --git a/Eigen/src/SparseCore/MappedSparseMatrix.h b/Eigen/src/SparseCore/MappedSparseMatrix.h index d9aabd049..2852c669a 100644 --- a/Eigen/src/SparseCore/MappedSparseMatrix.h +++ b/Eigen/src/SparseCore/MappedSparseMatrix.h @@ -192,7 +192,7 @@ struct evaluator > }; evaluator() : m_matrix(0) {} - evaluator(const MappedSparseMatrixType &mat) : m_matrix(&mat) {} + explicit evaluator(const MappedSparseMatrixType &mat) : m_matrix(&mat) {} operator MappedSparseMatrixType&() { return m_matrix->const_cast_derived(); } operator const MappedSparseMatrixType&() const { return *m_matrix; } diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h index 635d58d86..f8b9d5ad6 100644 --- a/Eigen/src/SparseCore/SparseBlock.h +++ b/Eigen/src/SparseCore/SparseBlock.h @@ -443,7 +443,7 @@ namespace internal { Index m_end; public: - EIGEN_STRONG_INLINE GenericSparseBlockInnerIteratorImpl(const BlockType& block, Index outer = 0) + explicit EIGEN_STRONG_INLINE GenericSparseBlockInnerIteratorImpl(const BlockType& block, Index outer = 0) : m_block(block), m_outerPos( (IsRowMajor ? block.m_startCol.value() : block.m_startRow.value()) - 1), // -1 so that operator++ finds the first non-zero entry @@ -512,7 +512,7 @@ struct unary_evaluator, IteratorBa typedef typename internal::conditional::type InnerIterator; - unary_evaluator(const XprType& op) + explicit unary_evaluator(const XprType& op) : m_argImpl(op.nestedExpression()), m_block(op) {} diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index 5993c1caf..94ca9b1a4 100644 --- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -117,7 +117,7 @@ public: Flags = XprType::Flags }; - binary_evaluator(const XprType& xpr) + explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -195,7 +195,7 @@ public: Flags = XprType::Flags }; - binary_evaluator(const XprType& xpr) + explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -260,7 +260,7 @@ public: Flags = XprType::Flags }; - binary_evaluator(const XprType& xpr) + explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -326,7 +326,7 @@ public: Flags = XprType::Flags }; - binary_evaluator(const XprType& xpr) + explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) diff --git a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h index 6036fd0a7..32b7bc949 100644 --- a/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +++ b/Eigen/src/SparseCore/SparseCwiseUnaryOp.h @@ -29,7 +29,7 @@ struct unary_evaluator, IteratorBased> Flags = XprType::Flags }; - unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} + explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} protected: typedef typename evaluator::InnerIterator EvalIterator; @@ -104,7 +104,7 @@ struct unary_evaluator, IteratorBased> Flags = XprType::Flags }; - unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} + explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) {} protected: typedef typename evaluator::InnerIterator EvalIterator; diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 04c838a71..7af6a12a9 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -173,7 +173,8 @@ protected: typedef Product ProdXprType; // if the actual left-hand side is a dense vector, - // then build a sparse-view so that we can seamlessly iterator over it. + // then build a sparse-view so that we can seamlessly iterate over it. + // FIXME ActualLhs does not seem to be necessary typedef typename conditional::StorageKind,Sparse>::value, Lhs1, SparseView >::type ActualLhs; typedef typename conditional::StorageKind,Sparse>::value, @@ -228,7 +229,7 @@ public: Scalar m_factor; }; - sparse_dense_outer_product_evaluator(const ActualLhs &lhs, const ActualRhs &rhs) + sparse_dense_outer_product_evaluator(const Lhs1 &lhs, const ActualRhs &rhs) : m_lhs(lhs), m_lhsXprImpl(m_lhs), m_rhsXprImpl(rhs) {} @@ -253,7 +254,7 @@ struct product_evaluator, OuterProduct, Sparse typedef Product XprType; typedef typename XprType::PlainObject PlainObject; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs()) {} @@ -268,7 +269,7 @@ struct product_evaluator, OuterProduct, DenseS typedef Product XprType; typedef typename XprType::PlainObject PlainObject; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs()) {} diff --git a/Eigen/src/SparseCore/SparseDiagonalProduct.h b/Eigen/src/SparseCore/SparseDiagonalProduct.h index 0cb2bd572..be935e9f3 100644 --- a/Eigen/src/SparseCore/SparseDiagonalProduct.h +++ b/Eigen/src/SparseCore/SparseDiagonalProduct.h @@ -44,7 +44,7 @@ struct product_evaluator, ProductTag, Diagonal enum { CoeffReadCost = Dynamic, Flags = Rhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags typedef sparse_diagonal_product_evaluator Base; - product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} + explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {} }; template @@ -57,7 +57,7 @@ struct product_evaluator, ProductTag, SparseSh enum { CoeffReadCost = Dynamic, Flags = Lhs::Flags&RowMajorBit }; // FIXME CoeffReadCost & Flags typedef sparse_diagonal_product_evaluator, Lhs::Flags&RowMajorBit?SDP_AsCwiseProduct:SDP_AsScalarProduct> Base; - product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) {} + explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal().transpose()) {} }; template diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h index 9e7124ff2..7ccdd12a5 100644 --- a/Eigen/src/SparseCore/SparseMatrix.h +++ b/Eigen/src/SparseCore/SparseMatrix.h @@ -89,6 +89,8 @@ class SparseMatrix EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) typedef MappedSparseMatrix Map; + typedef Diagonal DiagonalReturnType; + using Base::IsRowMajor; typedef internal::CompressedStorage Storage; enum { @@ -621,7 +623,7 @@ class SparseMatrix } /** \returns a const expression of the diagonal coefficients */ - const Diagonal diagonal() const { return *this; } + const DiagonalReturnType diagonal() const { return DiagonalReturnType(*this); } /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ inline SparseMatrix() @@ -1272,7 +1274,7 @@ struct evaluator > }; evaluator() : m_matrix(0) {} - evaluator(const SparseMatrixType &mat) : m_matrix(&mat) {} + explicit evaluator(const SparseMatrixType &mat) : m_matrix(&mat) {} operator SparseMatrixType&() { return m_matrix->const_cast_derived(); } operator const SparseMatrixType&() const { return *m_matrix; } diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index a438c6487..f96042f27 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -94,6 +94,9 @@ template class SparseMatrixBase : public EigenBase CwiseUnaryOp, Eigen::Transpose >, Transpose >::type AdjointReturnType; + typedef Transpose TransposeReturnType; + template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; + typedef typename internal::add_const >::type ConstTransposeReturnType; // FIXME storage order do not match evaluator storage order typedef SparseMatrix PlainObject; @@ -114,6 +117,8 @@ template class SparseMatrixBase : public EigenBase /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,Matrix > ConstantReturnType; + /** type of the equivalent dense matrix */ + typedef Matrix DenseMatrixType; /** type of the equivalent square matrix */ typedef Matrix SquareMatrixType; @@ -303,9 +308,9 @@ template class SparseMatrixBase : public EigenBase RealScalar norm() const; RealScalar blueNorm() const; - Transpose transpose() { return derived(); } - const Transpose transpose() const { return derived(); } - const AdjointReturnType adjoint() const { return transpose(); } + TransposeReturnType transpose() { return TransposeReturnType(derived()); } + const ConstTransposeReturnType transpose() const { return ConstTransposeReturnType(derived()); } + const AdjointReturnType adjoint() const { return AdjointReturnType(transpose()); } // inner-vector typedef Block InnerVectorReturnType; @@ -317,9 +322,9 @@ template class SparseMatrixBase : public EigenBase Block innerVectors(Index outerStart, Index outerSize); const Block innerVectors(Index outerStart, Index outerSize) const; - Matrix toDense() const + DenseMatrixType toDense() const { - return derived(); + return DenseMatrixType(derived()); } template diff --git a/Eigen/src/SparseCore/SparsePermutation.h b/Eigen/src/SparseCore/SparsePermutation.h index 228796bf8..3bfa2ae1b 100644 --- a/Eigen/src/SparseCore/SparsePermutation.h +++ b/Eigen/src/SparseCore/SparsePermutation.h @@ -166,7 +166,7 @@ struct product_evaluator, ProductTag, Permutat typedef typename traits >::ReturnType PlainObject; typedef typename evaluator::type Base; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -185,7 +185,7 @@ struct product_evaluator, ProductTag, SparseSh typedef typename traits >::ReturnType PlainObject; typedef typename evaluator::type Base; - product_evaluator(const XprType& xpr) + explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index b68fe986a..ae707376a 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -59,7 +59,7 @@ struct evaluator > > typedef evaluator type; typedef evaluator nestedType; - evaluator(const XprType& xpr) + explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { using std::abs; diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 69ac1a398..247d4e6d3 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -53,7 +53,7 @@ template class SparseSelfAdjointView typedef typename MatrixType::Nested MatrixTypeNested; typedef typename internal::remove_all::type _MatrixTypeNested; - inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) + explicit inline SparseSelfAdjointView(const MatrixType& matrix) : m_matrix(matrix) { eigen_assert(rows()==cols() && "SelfAdjointView is only for squared matrices"); } @@ -172,14 +172,14 @@ template template const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const { - return derived(); + return SparseSelfAdjointView(derived()); } template template SparseSelfAdjointView SparseMatrixBase::selfadjointView() { - return derived(); + return SparseSelfAdjointView(derived()); } /*************************************************************************** diff --git a/Eigen/src/SparseCore/SparseTranspose.h b/Eigen/src/SparseCore/SparseTranspose.h index fae7cae97..c3d2d1a16 100644 --- a/Eigen/src/SparseCore/SparseTranspose.h +++ b/Eigen/src/SparseCore/SparseTranspose.h @@ -62,7 +62,7 @@ struct unary_evaluator, IteratorBased> Flags = XprType::Flags }; - unary_evaluator(const XprType& op) :m_argImpl(op.nestedExpression()) {} + explicit unary_evaluator(const XprType& op) :m_argImpl(op.nestedExpression()) {} protected: typename evaluator::nestedType m_argImpl; diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 744c3d730..e200bc815 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -185,7 +185,7 @@ public: Flags = XprType::Flags }; - unary_evaluator(const XprType &xpr) : m_argImpl(xpr.nestedExpression()) {} + explicit unary_evaluator(const XprType &xpr) : m_argImpl(xpr.nestedExpression()) {} class InnerIterator : public EvalIterator { @@ -269,7 +269,7 @@ template inline const TriangularView SparseMatrixBase::triangularView() const { - return derived(); + return TriangularView(derived()); } } // end namespace Eigen diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index c9f9d61e9..dfbb2be2e 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.h @@ -221,7 +221,7 @@ class SparseVector inline SparseVector() : m_size(0) { check_template_parameters(); resize(0); } - inline SparseVector(Index size) : m_size(0) { check_template_parameters(); resize(size); } + explicit inline SparseVector(Index size) : m_size(0) { check_template_parameters(); resize(size); } inline SparseVector(Index rows, Index cols) : m_size(0) { check_template_parameters(); resize(rows,cols); } @@ -360,14 +360,14 @@ template class SparseVector::InnerIterator { public: - InnerIterator(const SparseVector& vec, Index outer=0) + explicit InnerIterator(const SparseVector& vec, Index outer=0) : m_data(vec.m_data), m_id(0), m_end(static_cast(m_data.size())) { EIGEN_UNUSED_VARIABLE(outer); eigen_assert(outer==0); } - InnerIterator(const internal::CompressedStorage& data) + explicit InnerIterator(const internal::CompressedStorage& data) : m_data(data), m_id(0), m_end(static_cast(m_data.size())) {} @@ -392,14 +392,14 @@ template class SparseVector::ReverseInnerIterator { public: - ReverseInnerIterator(const SparseVector& vec, Index outer=0) + explicit ReverseInnerIterator(const SparseVector& vec, Index outer=0) : m_data(vec.m_data), m_id(static_cast(m_data.size())), m_start(0) { EIGEN_UNUSED_VARIABLE(outer); eigen_assert(outer==0); } - ReverseInnerIterator(const internal::CompressedStorage& data) + explicit ReverseInnerIterator(const internal::CompressedStorage& data) : m_data(data), m_id(static_cast(m_data.size())), m_start(0) {} @@ -435,7 +435,7 @@ struct evaluator > Flags = SparseVectorType::Flags }; - evaluator(const SparseVectorType &mat) : m_matrix(mat) {} + explicit evaluator(const SparseVectorType &mat) : m_matrix(mat) {} operator SparseVectorType&() { return m_matrix.const_cast_derived(); } operator const SparseVectorType&() const { return m_matrix; } diff --git a/Eigen/src/SparseCore/SparseView.h b/Eigen/src/SparseCore/SparseView.h index d10cc5a35..40a3019fa 100644 --- a/Eigen/src/SparseCore/SparseView.h +++ b/Eigen/src/SparseCore/SparseView.h @@ -36,7 +36,7 @@ public: EIGEN_SPARSE_PUBLIC_INTERFACE(SparseView) typedef typename internal::remove_all::type NestedExpression; - SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), + explicit SparseView(const MatrixType& mat, const Scalar& m_reference = Scalar(0), RealScalar m_epsilon = NumTraits::dummy_precision()) : m_matrix(mat), m_reference(m_reference), m_epsilon(m_epsilon) {} @@ -111,7 +111,7 @@ struct unary_evaluator, IteratorBased> Flags = XprType::Flags }; - unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} protected: typename evaluator::nestedType m_argImpl; @@ -180,7 +180,7 @@ struct unary_evaluator, IndexBased> Flags = XprType::Flags }; - unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} + explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_view(xpr) {} protected: typename evaluator::nestedType m_argImpl; diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index 14d7e713e..cd4ea5b13 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -95,7 +95,7 @@ class SparseLU : public SparseSolverBase >, { initperfvalues(); } - SparseLU(const MatrixType& matrix):m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) + explicit SparseLU(const MatrixType& matrix):m_lastError(""),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0),m_detPermR(1) { initperfvalues(); compute(matrix); @@ -650,7 +650,7 @@ struct SparseLUMatrixLReturnType : internal::no_assignment_operator { typedef typename MappedSupernodalType::Index Index; typedef typename MappedSupernodalType::Scalar Scalar; - SparseLUMatrixLReturnType(const MappedSupernodalType& mapL) : m_mapL(mapL) + explicit SparseLUMatrixLReturnType(const MappedSupernodalType& mapL) : m_mapL(mapL) { } Index rows() { return m_mapL.rows(); } Index cols() { return m_mapL.cols(); } @@ -667,7 +667,7 @@ struct SparseLUMatrixUReturnType : internal::no_assignment_operator { typedef typename MatrixLType::Index Index; typedef typename MatrixLType::Scalar Scalar; - SparseLUMatrixUReturnType(const MatrixLType& mapL, const MatrixUType& mapU) + explicit SparseLUMatrixUReturnType(const MatrixLType& mapL, const MatrixUType& mapU) : m_mapL(mapL),m_mapU(mapU) { } Index rows() { return m_mapL.rows(); } diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 6d85ea9be..f6a9af672 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -88,7 +88,7 @@ class SparseQR : public SparseSolverBase > * * \sa compute() */ - SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) + explicit SparseQR(const MatrixType& mat) : m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) { compute(mat); } @@ -636,7 +636,7 @@ struct SparseQRMatrixQReturnType : public EigenBase DenseMatrix; - SparseQRMatrixQReturnType(const SparseQRType& qr) : m_qr(qr) {} + explicit SparseQRMatrixQReturnType(const SparseQRType& qr) : m_qr(qr) {} template SparseQR_QProduct operator*(const MatrixBase& other) { @@ -672,7 +672,7 @@ struct SparseQRMatrixQReturnType : public EigenBase struct SparseQRMatrixQTransposeReturnType { - SparseQRMatrixQTransposeReturnType(const SparseQRType& qr) : m_qr(qr) {} + explicit SparseQRMatrixQTransposeReturnType(const SparseQRType& qr) : m_qr(qr) {} template SparseQR_QProduct operator*(const MatrixBase& other) { diff --git a/Eigen/src/SuperLUSupport/SuperLUSupport.h b/Eigen/src/SuperLUSupport/SuperLUSupport.h index 0137585ca..ef73587a7 100644 --- a/Eigen/src/SuperLUSupport/SuperLUSupport.h +++ b/Eigen/src/SuperLUSupport/SuperLUSupport.h @@ -469,7 +469,7 @@ class SuperLU : public SuperLUBase<_MatrixType,SuperLU<_MatrixType> > SuperLU() : Base() { init(); } - SuperLU(const MatrixType& matrix) : Base() + explicit SuperLU(const MatrixType& matrix) : Base() { init(); Base::compute(matrix); diff --git a/Eigen/src/UmfPackSupport/UmfPackSupport.h b/Eigen/src/UmfPackSupport/UmfPackSupport.h index 7fada5567..1c5800ffa 100644 --- a/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -142,7 +142,7 @@ class UmfPackLU : public SparseSolverBase > UmfPackLU() { init(); } - UmfPackLU(const MatrixType& matrix) + explicit UmfPackLU(const MatrixType& matrix) { init(); compute(matrix); diff --git a/Eigen/src/misc/Kernel.h b/Eigen/src/misc/Kernel.h index b9e1518fd..4b03e44c1 100644 --- a/Eigen/src/misc/Kernel.h +++ b/Eigen/src/misc/Kernel.h @@ -41,7 +41,7 @@ template struct kernel_retval_base typedef ReturnByValue Base; typedef typename Base::Index Index; - kernel_retval_base(const DecompositionType& dec) + explicit kernel_retval_base(const DecompositionType& dec) : m_dec(dec), m_rank(dec.rank()), m_cols(m_rank==dec.cols() ? 1 : dec.cols() - m_rank) diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index f6d7d8944..4e64826da 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -1,5 +1,24 @@ +// These are already defined in MatrixCwiseUnaryOps.h +//typedef CwiseUnaryOp, const Derived> AbsReturnType; +//typedef CwiseUnaryOp, const Derived> Abs2ReturnType; +//typedef CwiseUnaryOp, const Derived> SqrtReturnType; +//typedef CwiseUnaryOp, const Derived> CwiseInverseReturnType; +//typedef CwiseUnaryOp >, const Derived> CwiseScalarEqualReturnType; + +typedef CwiseUnaryOp, const Derived> ExpReturnType; +typedef CwiseUnaryOp, const Derived> LogReturnType; +typedef CwiseUnaryOp, const Derived> CosReturnType; +typedef CwiseUnaryOp, const Derived> SinReturnType; +typedef CwiseUnaryOp, const Derived> AcosReturnType; +typedef CwiseUnaryOp, const Derived> AsinReturnType; +typedef CwiseUnaryOp, const Derived> TanReturnType; +typedef CwiseUnaryOp, const Derived> AtanReturnType; +typedef CwiseUnaryOp, const Derived> PowReturnType; +typedef CwiseUnaryOp, const Derived> SquareReturnType; +typedef CwiseUnaryOp, const Derived> CubeReturnType; + /** \returns an expression of the coefficient-wise absolute value of \c *this * * Example: \include Cwise_abs.cpp @@ -8,10 +27,10 @@ * \sa abs2() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> +EIGEN_STRONG_INLINE const AbsReturnType abs() const { - return derived(); + return AbsReturnType(derived()); } /** \returns an expression of the coefficient-wise squared absolute value of \c *this @@ -22,10 +41,10 @@ abs() const * \sa abs(), square() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> +EIGEN_STRONG_INLINE const Abs2ReturnType abs2() const { - return derived(); + return Abs2ReturnType(derived()); } /** \returns an expression of the coefficient-wise exponential of *this. @@ -39,10 +58,10 @@ abs2() const * \sa pow(), log(), sin(), cos() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const ExpReturnType exp() const { - return derived(); + return ExpReturnType(derived()); } /** \returns an expression of the coefficient-wise logarithm of *this. @@ -56,10 +75,10 @@ exp() const * \sa exp() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const LogReturnType log() const { - return derived(); + return LogReturnType(derived()); } /** \returns an expression of the coefficient-wise square root of *this. @@ -73,10 +92,10 @@ log() const * \sa pow(), square() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const SqrtReturnType sqrt() const { - return derived(); + return SqrtReturnType(derived()); } /** \returns an expression of the coefficient-wise cosine of *this. @@ -90,10 +109,10 @@ sqrt() const * \sa sin(), acos() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const CosReturnType cos() const { - return derived(); + return CosReturnType(derived()); } @@ -108,10 +127,10 @@ cos() const * \sa cos(), asin() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const SinReturnType sin() const { - return derived(); + return SinReturnType(derived()); } /** \returns an expression of the coefficient-wise arc cosine of *this. @@ -122,10 +141,10 @@ sin() const * \sa cos(), asin() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const AcosReturnType acos() const { - return derived(); + return AcosReturnType(derived()); } /** \returns an expression of the coefficient-wise arc sine of *this. @@ -136,10 +155,10 @@ acos() const * \sa sin(), acos() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const AsinReturnType asin() const { - return derived(); + return AsinReturnType(derived()); } /** \returns an expression of the coefficient-wise tan of *this. @@ -150,10 +169,10 @@ asin() const * \sa cos(), sin() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, Derived> +inline const TanReturnType tan() const { - return derived(); + return TanReturnType(derived()); } /** \returns an expression of the coefficient-wise arc tan of *this. @@ -163,10 +182,10 @@ tan() const * * \sa cos(), sin(), tan() */ -inline const CwiseUnaryOp, Derived> +inline const AtanReturnType atan() const { - return derived(); + return AtanReturnType(derived()); } /** \returns an expression of the coefficient-wise power of *this to the given exponent. @@ -180,11 +199,10 @@ atan() const * \sa exp(), log() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const PowReturnType pow(const Scalar& exponent) const { - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_pow_op(exponent)); + return PowReturnType(derived(), internal::scalar_pow_op(exponent)); } @@ -196,10 +214,10 @@ pow(const Scalar& exponent) const * \sa operator/(), operator*() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const CwiseInverseReturnType inverse() const { - return derived(); + return CwiseInverseReturnType(derived()); } /** \returns an expression of the coefficient-wise square of *this. @@ -210,10 +228,10 @@ inverse() const * \sa operator/(), operator*(), abs2() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const SquareReturnType square() const { - return derived(); + return SquareReturnType(derived()); } /** \returns an expression of the coefficient-wise cube of *this. @@ -224,10 +242,10 @@ square() const * \sa square(), pow() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> +inline const CubeReturnType cube() const { - return derived(); + return CubeReturnType(derived()); } #define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \ diff --git a/Eigen/src/plugins/CommonCwiseUnaryOps.h b/Eigen/src/plugins/CommonCwiseUnaryOps.h index a17153e64..050bce03c 100644 --- a/Eigen/src/plugins/CommonCwiseUnaryOps.h +++ b/Eigen/src/plugins/CommonCwiseUnaryOps.h @@ -14,6 +14,8 @@ /** \internal Represents a scalar multiple of an expression */ typedef CwiseUnaryOp, const Derived> ScalarMultipleReturnType; +typedef CwiseUnaryOp >, const Derived> ScalarComplexMultipleReturnType; + /** \internal Represents a quotient of an expression by a scalar*/ typedef CwiseUnaryOp, const Derived> ScalarQuotient1ReturnType; /** \internal the return type of conjugate() */ @@ -36,13 +38,16 @@ typedef CwiseUnaryOp, const Derived> ImagReturn /** \internal the return type of imag() */ typedef CwiseUnaryView, Derived> NonConstImagReturnType; +typedef CwiseUnaryOp, const Derived> NegativeReturnType; +//typedef CwiseUnaryOp, const Derived> + #endif // not EIGEN_PARSED_BY_DOXYGEN /** \returns an expression of the opposite of \c *this */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp::Scalar>, const Derived> -operator-() const { return derived(); } +inline const NegativeReturnType +operator-() const { return NegativeReturnType(derived()); } /** \returns an expression of \c *this scaled by the scalar factor \a scalar */ @@ -50,8 +55,7 @@ EIGEN_DEVICE_FUNC inline const ScalarMultipleReturnType operator*(const Scalar& scalar) const { - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_multiple_op(scalar)); + return ScalarMultipleReturnType(derived(), internal::scalar_multiple_op(scalar)); } #ifdef EIGEN_PARSED_BY_DOXYGEN @@ -60,20 +64,18 @@ const ScalarMultipleReturnType operator*(const RealScalar& scalar) const; /** \returns an expression of \c *this divided by the scalar value \a scalar */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp::Scalar>, const Derived> +inline const ScalarQuotient1ReturnType operator/(const Scalar& scalar) const { - return CwiseUnaryOp, const Derived> - (derived(), internal::scalar_quotient1_op(scalar)); + return ScalarQuotient1ReturnType(derived(), internal::scalar_quotient1_op(scalar)); } /** Overloaded for efficient real matrix times complex scalar value */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp >, const Derived> +inline const ScalarComplexMultipleReturnType operator*(const std::complex& scalar) const { - return CwiseUnaryOp >, const Derived> - (*static_cast(this), internal::scalar_multiple2_op >(scalar)); + return ScalarComplexMultipleReturnType(derived(), internal::scalar_multiple2_op >(scalar)); } EIGEN_DEVICE_FUNC @@ -86,6 +88,9 @@ inline friend const CwiseUnaryOp& scalar, const StorageBaseType& matrix) { return matrix*scalar; } + +template struct CastXpr { typedef typename internal::cast_return_type, const Derived> >::type Type; }; + /** \returns an expression of *this with the \a Scalar type casted to * \a NewScalar. * @@ -95,10 +100,10 @@ operator*(const std::complex& scalar, const StorageBaseType& matrix) */ template EIGEN_DEVICE_FUNC -typename internal::cast_return_type::Scalar, NewType>, const Derived> >::type +typename CastXpr::Type cast() const { - return derived(); + return typename CastXpr::Type(derived()); } /** \returns an expression of the complex conjugate of \c *this. @@ -116,14 +121,14 @@ conjugate() const * \sa imag() */ EIGEN_DEVICE_FUNC inline RealReturnType -real() const { return derived(); } +real() const { return RealReturnType(derived()); } /** \returns an read-only expression of the imaginary part of \c *this. * * \sa real() */ EIGEN_DEVICE_FUNC inline const ImagReturnType -imag() const { return derived(); } +imag() const { return ImagReturnType(derived()); } /** \brief Apply a unary operator coefficient-wise * \param[in] func Functor implementing the unary operator @@ -176,11 +181,11 @@ unaryViewExpr(const CustomViewOp& func = CustomViewOp()) const * \sa imag() */ EIGEN_DEVICE_FUNC inline NonConstRealReturnType -real() { return derived(); } +real() { return NonConstRealReturnType(derived()); } /** \returns a non const expression of the imaginary part of \c *this. * * \sa real() */ EIGEN_DEVICE_FUNC inline NonConstImagReturnType -imag() { return derived(); } +imag() { return NonConstImagReturnType(derived()); } diff --git a/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/Eigen/src/plugins/MatrixCwiseUnaryOps.h index 1bb15f862..045a2ebb2 100644 --- a/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -10,6 +10,11 @@ // This file is a base class plugin containing matrix specifics coefficient wise functions. +typedef CwiseUnaryOp, const Derived> AbsReturnType; +typedef CwiseUnaryOp, const Derived> Abs2ReturnType; +typedef CwiseUnaryOp, const Derived> SqrtReturnType; +typedef CwiseUnaryOp, const Derived> CwiseInverseReturnType; +typedef CwiseUnaryOp >, const Derived> CwiseScalarEqualReturnType; /** \returns an expression of the coefficient-wise absolute value of \c *this * * Example: \include MatrixBase_cwiseAbs.cpp @@ -18,8 +23,8 @@ * \sa cwiseAbs2() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs() const { return derived(); } +EIGEN_STRONG_INLINE const AbsReturnType +cwiseAbs() const { return AbsReturnType(derived()); } /** \returns an expression of the coefficient-wise squared absolute value of \c *this * @@ -29,8 +34,8 @@ cwiseAbs() const { return derived(); } * \sa cwiseAbs() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const CwiseUnaryOp, const Derived> -cwiseAbs2() const { return derived(); } +EIGEN_STRONG_INLINE const Abs2ReturnType +cwiseAbs2() const { return Abs2ReturnType(derived()); } /** \returns an expression of the coefficient-wise square root of *this. * @@ -40,8 +45,8 @@ cwiseAbs2() const { return derived(); } * \sa cwisePow(), cwiseSquare() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> -cwiseSqrt() const { return derived(); } +inline const SqrtReturnType +cwiseSqrt() const { return SqrtReturnType(derived()); } /** \returns an expression of the coefficient-wise inverse of *this. * @@ -51,8 +56,8 @@ cwiseSqrt() const { return derived(); } * \sa cwiseProduct() */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp, const Derived> -cwiseInverse() const { return derived(); } +inline const CwiseInverseReturnType +cwiseInverse() const { return CwiseInverseReturnType(derived()); } /** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s * @@ -64,9 +69,8 @@ cwiseInverse() const { return derived(); } * \sa cwiseEqual(const MatrixBase &) const */ EIGEN_DEVICE_FUNC -inline const CwiseUnaryOp >, const Derived> +inline const CwiseScalarEqualReturnType cwiseEqual(const Scalar& s) const { - return CwiseUnaryOp >,const Derived> - (derived(), std::bind1st(std::equal_to(), s)); + return CwiseScalarEqualReturnType(derived(), std::bind1st(std::equal_to(), s)); } -- cgit v1.2.3 From eb13ada3aa4e8514bc297e99badcc87c5f71533d Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 23 Sep 2014 17:21:27 +0200 Subject: Renamed CwiseInverseReturnType to InverseReturnType for ArrayBase::inverse() --- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index 4e64826da..bb1f96bdc 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -4,7 +4,7 @@ //typedef CwiseUnaryOp, const Derived> AbsReturnType; //typedef CwiseUnaryOp, const Derived> Abs2ReturnType; //typedef CwiseUnaryOp, const Derived> SqrtReturnType; -//typedef CwiseUnaryOp, const Derived> CwiseInverseReturnType; +typedef CwiseUnaryOp, const Derived> InverseReturnType; //typedef CwiseUnaryOp >, const Derived> CwiseScalarEqualReturnType; typedef CwiseUnaryOp, const Derived> ExpReturnType; @@ -214,10 +214,10 @@ pow(const Scalar& exponent) const * \sa operator/(), operator*() */ EIGEN_DEVICE_FUNC -inline const CwiseInverseReturnType +inline const InverseReturnType inverse() const { - return CwiseInverseReturnType(derived()); + return InverseReturnType(derived()); } /** \returns an expression of the coefficient-wise square of *this. -- cgit v1.2.3 From 7817bc19a40caa1d7d5d56e995cc887af58b42a2 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 23 Sep 2014 17:23:34 +0200 Subject: Removed FIXME, as it is actually necessary. --- Eigen/src/SparseCore/SparseDenseProduct.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index 7af6a12a9..ed3cb1990 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -174,7 +174,6 @@ protected: // if the actual left-hand side is a dense vector, // then build a sparse-view so that we can seamlessly iterate over it. - // FIXME ActualLhs does not seem to be necessary typedef typename conditional::StorageKind,Sparse>::value, Lhs1, SparseView >::type ActualLhs; typedef typename conditional::StorageKind,Sparse>::value, -- cgit v1.2.3 From 421feea3b2ca7d1b4c8af567c282519f293ce38f Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 23 Sep 2014 18:55:42 +0200 Subject: member_redux constructor is explicit too. Renamed some typedefs for more consistency. --- Eigen/src/Core/VectorwiseOp.h | 16 ++++++++-------- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 8 +++----- Eigen/src/plugins/MatrixCwiseUnaryOps.h | 18 +++++++++--------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index e340c1433..2815a16c9 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h @@ -128,7 +128,7 @@ struct member_redux { >::type result_type; template struct Cost { enum { value = (Size-1) * functor_traits::Cost }; }; - member_redux(const BinaryOp func) : m_functor(func) {} // FIXME this should actually be explicit, but lets not exaggerate + explicit member_redux(const BinaryOp func) : m_functor(func) {} template inline result_type operator()(const DenseBase& mat) const { return mat.redux(m_functor); } @@ -165,10 +165,10 @@ template class VectorwiseOp typedef typename internal::remove_all::type ExpressionTypeNestedCleaned; template class Functor, - typename Scalar=typename internal::traits::Scalar> struct ReturnType + typename Scalar_=Scalar> struct ReturnType { typedef PartialReduxExpr, + Functor, Direction > Type; }; @@ -176,7 +176,7 @@ template class VectorwiseOp template struct ReduxReturnType { typedef PartialReduxExpr::Scalar>, + internal::member_redux, Direction > Type; }; @@ -264,11 +264,11 @@ template class VectorwiseOp template const typename ReduxReturnType::Type redux(const BinaryOp& func = BinaryOp()) const - { return typename ReduxReturnType::Type(_expression(), func); } + { return typename ReduxReturnType::Type(_expression(), internal::member_redux(func)); } typedef typename ReturnType::Type MinCoeffReturnType; typedef typename ReturnType::Type MaxCoeffReturnType; - typedef typename ReturnType::Type SquareNormReturnType; + typedef typename ReturnType::Type SquaredNormReturnType; typedef typename ReturnType::Type NormReturnType; typedef typename ReturnType::Type BlueNormReturnType; typedef typename ReturnType::Type StableNormReturnType; @@ -313,8 +313,8 @@ template class VectorwiseOp * Output: \verbinclude PartialRedux_squaredNorm.out * * \sa DenseBase::squaredNorm() */ - const SquareNormReturnType squaredNorm() const - { return SquareNormReturnType(_expression()); } + const SquaredNormReturnType squaredNorm() const + { return SquaredNormReturnType(_expression()); } /** \returns a row (or column) vector expression of the norm * of each column (or row) of the referenced expression. diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index bb1f96bdc..f6f526d2b 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -1,11 +1,9 @@ -// These are already defined in MatrixCwiseUnaryOps.h -//typedef CwiseUnaryOp, const Derived> AbsReturnType; -//typedef CwiseUnaryOp, const Derived> Abs2ReturnType; -//typedef CwiseUnaryOp, const Derived> SqrtReturnType; +typedef CwiseUnaryOp, const Derived> AbsReturnType; +typedef CwiseUnaryOp, const Derived> Abs2ReturnType; +typedef CwiseUnaryOp, const Derived> SqrtReturnType; typedef CwiseUnaryOp, const Derived> InverseReturnType; -//typedef CwiseUnaryOp >, const Derived> CwiseScalarEqualReturnType; typedef CwiseUnaryOp, const Derived> ExpReturnType; typedef CwiseUnaryOp, const Derived> LogReturnType; diff --git a/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/Eigen/src/plugins/MatrixCwiseUnaryOps.h index 045a2ebb2..c99ee94ec 100644 --- a/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -10,9 +10,9 @@ // This file is a base class plugin containing matrix specifics coefficient wise functions. -typedef CwiseUnaryOp, const Derived> AbsReturnType; -typedef CwiseUnaryOp, const Derived> Abs2ReturnType; -typedef CwiseUnaryOp, const Derived> SqrtReturnType; +typedef CwiseUnaryOp, const Derived> CwiseAbsReturnType; +typedef CwiseUnaryOp, const Derived> CwiseAbs2ReturnType; +typedef CwiseUnaryOp, const Derived> CwiseSqrtReturnType; typedef CwiseUnaryOp, const Derived> CwiseInverseReturnType; typedef CwiseUnaryOp >, const Derived> CwiseScalarEqualReturnType; /** \returns an expression of the coefficient-wise absolute value of \c *this @@ -23,8 +23,8 @@ typedef CwiseUnaryOp >, const Derived> Cwis * \sa cwiseAbs2() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const AbsReturnType -cwiseAbs() const { return AbsReturnType(derived()); } +EIGEN_STRONG_INLINE const CwiseAbsReturnType +cwiseAbs() const { return CwiseAbsReturnType(derived()); } /** \returns an expression of the coefficient-wise squared absolute value of \c *this * @@ -34,8 +34,8 @@ cwiseAbs() const { return AbsReturnType(derived()); } * \sa cwiseAbs() */ EIGEN_DEVICE_FUNC -EIGEN_STRONG_INLINE const Abs2ReturnType -cwiseAbs2() const { return Abs2ReturnType(derived()); } +EIGEN_STRONG_INLINE const CwiseAbs2ReturnType +cwiseAbs2() const { return CwiseAbs2ReturnType(derived()); } /** \returns an expression of the coefficient-wise square root of *this. * @@ -45,8 +45,8 @@ cwiseAbs2() const { return Abs2ReturnType(derived()); } * \sa cwisePow(), cwiseSquare() */ EIGEN_DEVICE_FUNC -inline const SqrtReturnType -cwiseSqrt() const { return SqrtReturnType(derived()); } +inline const CwiseSqrtReturnType +cwiseSqrt() const { return CwiseSqrtReturnType(derived()); } /** \returns an expression of the coefficient-wise inverse of *this. * -- cgit v1.2.3 From 13cbc751c92248e0dfa969bfe5f5060773ac9972 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 23 Sep 2014 22:10:32 +0200 Subject: bug #880: automatically preserves buildtool flags when modifying DartConfiguration.tcl file. --- cmake/EigenConfigureTesting.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/EigenConfigureTesting.cmake b/cmake/EigenConfigureTesting.cmake index 190509958..05c8c1466 100644 --- a/cmake/EigenConfigureTesting.cmake +++ b/cmake/EigenConfigureTesting.cmake @@ -23,7 +23,12 @@ set(EIGEN_TEST_BUILD_FLAGS "" CACHE STRING "Options passed to the build command # Recall that our unit tests are not in the "all" target, so we have to explicitely ask ctest to build our custom 'buildtests' target. # At this stage, we can also add custom flags to the build tool through the user defined EIGEN_TEST_BUILD_FLAGS variable. file(READ "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" EIGEN_DART_CONFIG_FILE) -string(REGEX REPLACE "MakeCommand:.*DefaultCTestConfigurationType" "MakeCommand: ${CMAKE_COMMAND} --build . --target buildtests --config '' -- -i ${EIGEN_TEST_BUILD_FLAGS}\nDefaultCTestConfigurationType" +# try to grab the default flags +string(REGEX MATCH "MakeCommand:.*-- (.*)DefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) +if(NOT CMAKE_MATCH_1) +string(REGEX MATCH "MakeCommand:.*gmake (.*)DefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) +endif() +string(REGEX REPLACE "MakeCommand:.*DefaultCTestConfigurationType" "MakeCommand: ${CMAKE_COMMAND} --build . --target buildtests --config \"\${CTEST_CONFIGURATION_TYPE}\" -- ${CMAKE_MATCH_1} ${EIGEN_TEST_BUILD_FLAGS}\nDefaultCTestConfigurationType" EIGEN_DART_CONFIG_FILE2 ${EIGEN_DART_CONFIG_FILE}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" ${EIGEN_DART_CONFIG_FILE2}) -- cgit v1.2.3 From 446001ef51be920649cb4f3c07848967b6788532 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 24 Sep 2014 09:39:09 +0200 Subject: Fix nested_eval > which wrongly returned a Product<> expression --- Eigen/src/Core/Inverse.h | 3 +-- Eigen/src/Core/ProductEvaluators.h | 10 +++++++--- test/geo_orthomethods.cpp | 5 ++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/Inverse.h b/Eigen/src/Core/Inverse.h index 706796b78..f3b0dff87 100644 --- a/Eigen/src/Core/Inverse.h +++ b/Eigen/src/Core/Inverse.h @@ -25,8 +25,7 @@ struct traits > typedef typename XprType::PlainObject PlainObject; typedef traits BaseTraits; enum { - Flags = BaseTraits::Flags & RowMajorBit, - CoeffReadCost = Dynamic + Flags = BaseTraits::Flags & RowMajorBit }; }; diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index 69e569908..c944ec9fc 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -97,11 +97,12 @@ struct product_evaluator, ProductTag, LhsShape : public evaluator::PlainObject>::type { typedef Product XprType; -// enum { -// CoeffReadCost = 0 // FIXME why is it needed? (this was already the case before the evaluators, see traits) -// }; typedef typename XprType::PlainObject PlainObject; typedef typename evaluator::type Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit +// CoeffReadCost = 0 // FIXME why is it needed? (this was already the case before the evaluators, see traits) + }; explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) @@ -508,6 +509,9 @@ struct product_evaluator, LazyCoeffBasedProduc typedef Product XprType; typedef Product BaseProduct; typedef product_evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; explicit product_evaluator(const XprType& xpr) : Base(BaseProduct(xpr.lhs(),xpr.rhs())) {} diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp index 7f8beb205..e178df257 100644 --- a/test/geo_orthomethods.cpp +++ b/test/geo_orthomethods.cpp @@ -39,7 +39,10 @@ template void orthomethods_3() (v0.cross(v1)).normalized(), (v0.cross(v1).cross(v0)).normalized(); VERIFY(mat3.isUnitary()); - + + mat3.setRandom(); + VERIFY_IS_APPROX(v0.cross(mat3*v1), -(mat3*v1).cross(v0)); + VERIFY_IS_APPROX(v0.cross(mat3.lazyProduct(v1)), -(mat3.lazyProduct(v1)).cross(v0)); // colwise/rowwise cross product mat3.setRandom(); -- cgit v1.2.3 From 27d6b4daf90488e105d70f45e5d5684b8f1a906d Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Wed, 24 Sep 2014 14:37:13 +0200 Subject: Tridiagonalization::diagonal() and ::subDiagonal() did not work. Added unit-test --- Eigen/src/Eigenvalues/Tridiagonalization.h | 11 ++++------- test/eigensolver_selfadjoint.cpp | 11 ++++++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index f20528f86..bedd1cb34 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -91,10 +91,8 @@ template class Tridiagonalization >::type DiagonalReturnType; typedef typename internal::conditional::IsComplex, - typename internal::add_const_on_value_type >::RealReturnType>::type, - const Diagonal< - Block > + typename internal::add_const_on_value_type::RealReturnType>::type, + const Diagonal >::type SubDiagonalReturnType; /** \brief Return type of matrixQ() */ @@ -307,7 +305,7 @@ typename Tridiagonalization::DiagonalReturnType Tridiagonalization::diagonal() const { eigen_assert(m_isInitialized && "Tridiagonalization is not initialized."); - return m_matrix.diagonal(); + return m_matrix.diagonal().real(); } template @@ -315,8 +313,7 @@ typename Tridiagonalization::SubDiagonalReturnType Tridiagonalization::subDiagonal() const { eigen_assert(m_isInitialized && "Tridiagonalization is not initialized."); - Index n = m_matrix.rows(); - return Block(m_matrix, 1, 0, n-1,n-1).diagonal(); + return m_matrix.template diagonal<-1>().real(); } namespace internal { diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 3851f9df2..41b598795 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -111,8 +111,17 @@ template void selfadjointeigensolver(const MatrixType& m) // test Tridiagonalization's methods Tridiagonalization tridiag(symmC); - // FIXME tridiag.matrixQ().adjoint() does not work + VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().template diagonal()); + VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>()); + MatrixType T = tridiag.matrixT(); + if(rows>1 && cols>1) { + // FIXME check that upper and lower part are 0: + //VERIFY(T.topRightCorner(rows-2, cols-2).template triangularView().isZero()); + } + VERIFY_IS_APPROX(tridiag.diagonal(), T.diagonal().real()); + VERIFY_IS_APPROX(tridiag.subDiagonal(), T.template diagonal<1>().real()); VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint()); + VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView()), tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint()); // Test computation of eigenvalues from tridiagonal matrix if(rows > 1) -- cgit v1.2.3 From 4ba8aa14822ae0b444baa9e0d41d8744cdcd6b03 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Thu, 25 Sep 2014 16:05:17 +0200 Subject: Fix bug #884: No malloc for zero-sized matrices or for Ref without temporaries --- Eigen/src/Core/util/Memory.h | 2 ++ test/nomalloc.cpp | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 30133ba67..af46c449c 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -454,6 +454,8 @@ template inline T* conditional_aligned_realloc_new(T* pt template inline T* conditional_aligned_new_auto(size_t size) { + if(size==0) + return 0; // short-cut. Also fixes Bug 884 check_size_for_overflow(size); T *result = reinterpret_cast(conditional_aligned_malloc(sizeof(T)*size)); if(NumTraits::RequireInitialization) diff --git a/test/nomalloc.cpp b/test/nomalloc.cpp index cbd02dd21..5458806f5 100644 --- a/test/nomalloc.cpp +++ b/test/nomalloc.cpp @@ -165,6 +165,38 @@ void ctms_decompositions() Eigen::JacobiSVD jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV); } +void test_zerosized() { + // default constructors: + Eigen::MatrixXd A; + Eigen::VectorXd v; + // explicit zero-sized: + Eigen::ArrayXXd A0(0,0); + Eigen::ArrayXd v0(0); + + // assigning empty objects to each other: + A=A0; + v=v0; +} + +template void test_reference(const MatrixType& m) { + typedef typename MatrixType::Scalar Scalar; + enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; + enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; + typename MatrixType::Index rows = m.rows(), cols=m.cols(); + // Dynamic reference: + typedef Eigen::Ref > Ref; + typedef Eigen::Ref > RefT; + + Ref r1(m); + Ref r2(m.block(rows/3, cols/4, rows/2, cols/2)); + RefT r3(m.transpose()); + RefT r4(m.topLeftCorner(rows/2, cols/2).transpose()); + + VERIFY_RAISES_ASSERT(RefT r5(m)); + VERIFY_RAISES_ASSERT(Ref r6(m.transpose())); + VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m)); +} + void test_nomalloc() { // check that our operator new is indeed called: @@ -175,5 +207,6 @@ void test_nomalloc() // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms) CALL_SUBTEST_4(ctms_decompositions()); - + CALL_SUBTEST_5(test_zerosized()); + CALL_SUBTEST_6(test_reference(Matrix())); } -- cgit v1.2.3 From 6d0f0b8cecd0ee944503d885fd34278044bab746 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Thu, 25 Sep 2014 16:06:16 +0000 Subject: add VSX identifier --- cmake/EigenTesting.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 6383c6eac..65bb29413 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -424,6 +424,8 @@ macro(ei_get_cxxflags VAR) ei_is_64bit_env(IS_64BIT_ENV) if(EIGEN_TEST_NEON) set(${VAR} NEON) + elseif(EIGEN_TEST_VSX) + set(${VAR} VSX) elseif(EIGEN_TEST_ALTIVEC) set(${VAR} ALVEC) elseif(EIGEN_TEST_FMA) -- cgit v1.2.3 From ce2035af868d57b85b4078c15843d5c1f51047dc Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 27 Sep 2014 23:25:58 +0100 Subject: New doc page on implementing a new expression class. --- doc/Manual.dox | 1 + doc/NewExpressionType.dox | 137 +++++++++++++++++++++++++++++ doc/examples/make_circulant.cpp | 11 +++ doc/examples/make_circulant.cpp.entry | 5 ++ doc/examples/make_circulant.cpp.evaluator | 33 +++++++ doc/examples/make_circulant.cpp.expression | 20 +++++ doc/examples/make_circulant.cpp.main | 8 ++ doc/examples/make_circulant.cpp.preamble | 4 + doc/examples/make_circulant.cpp.traits | 19 ++++ 9 files changed, 238 insertions(+) create mode 100644 doc/NewExpressionType.dox create mode 100644 doc/examples/make_circulant.cpp create mode 100644 doc/examples/make_circulant.cpp.entry create mode 100644 doc/examples/make_circulant.cpp.evaluator create mode 100644 doc/examples/make_circulant.cpp.expression create mode 100644 doc/examples/make_circulant.cpp.main create mode 100644 doc/examples/make_circulant.cpp.preamble create mode 100644 doc/examples/make_circulant.cpp.traits diff --git a/doc/Manual.dox b/doc/Manual.dox index 43af857a5..bf1a33229 100644 --- a/doc/Manual.dox +++ b/doc/Manual.dox @@ -13,6 +13,7 @@ namespace Eigen { - \subpage TopicUsingIntelMKL - \subpage TopicCUDA - \subpage TopicTemplateKeyword + - \subpage TopicNewExpressionType - \subpage UserManual_UnderstandingEigen */ diff --git a/doc/NewExpressionType.dox b/doc/NewExpressionType.dox new file mode 100644 index 000000000..ad8b7f86b --- /dev/null +++ b/doc/NewExpressionType.dox @@ -0,0 +1,137 @@ +namespace Eigen { + +/** \page TopicNewExpressionType Adding a new expression type + +This page describes with the help of an example how to implement a new +light-weight expression type in %Eigen. This consists of three parts: +the expression type itself, a traits class containing compile-time +information about the expression, and the evaluator class which is +used to evaluate the expression to a matrix. + +\b TO \b DO: Write a page explaining the design, with details on +vectorization etc., and refer to that page here. + + +\eigenAutoToc + +\section TopicSetting The setting + +A circulant matrix is a matrix where each column is the same as the +column to the left, except that it is cyclically shifted downwards. +For example, here is a 4-by-4 circulant matrix: +\f[ \begin{bmatrix} + 1 & 8 & 4 & 2 \\ + 2 & 1 & 8 & 4 \\ + 4 & 2 & 1 & 8 \\ + 8 & 4 & 2 & 1 +\end{bmatrix} \f] +A circulant matrix is uniquely determined by its first column. We wish +to write a function \c makeCirculant which, given the first column, +returns an expression representing the circulant matrix. + +For simplicity, we restrict the \c makeCirculant function to dense +matrices. It may make sense to also allow arrays, or sparse matrices, +but we will not do so here. We also do not want to support +vectorization. + + +\section TopicPreamble Getting started + +We will present the file implementing the \c makeCirculant function +part by part. We start by including the appropriate header files and +forward declaring the expression class, which we will call +\c Circulant. The \c makeCirculant function will return an object of +this type. The class \c Circulant is in fact a class template; the +template argument \c ArgType refers to the type of the vector passed +to the \c makeCirculant function. + +\include make_circulant.cpp.preamble + + +\section TopicTraits The traits class + +For every expression class \c X, there should be a traits class +\c Traits in the \c Eigen::internal namespace containing +information about \c X known as compile time. + +As explained in \ref TopicSetting, we designed the \c Circulant +expression class to refer to dense matrices. The entries of the +circulant matrix have the same type as the entries of the vector +passed to the \c makeCirculant function. The type used to index the +entries is also the same. Again for simplicity, we will only return +column-major matrices. Finally, the circulant matrix is a square +matrix (number of rows equals number of columns), and the number of +rows equals the number of rows of the column vector passed to the +\c makeCirculant function. If this is a dynamic-size vector, then the +size of the circulant matrix is not known at compile-time. + +This leads to the following code: + +\include make_circulant.cpp.traits + + +\section TopicExpression The expression class + +The next step is to define the expression class itself. In our case, +we want to inherit from \c MatrixBase in order to expose the interface +for dense matrices. In the constructor, we check that we are passed a +column vector (see \ref TopicAssertions) and we store the vector from +which we are going to build the circulant matrix in the member +variable \c m_arg. Finally, the expression class should compute the +size of the corresponding circulant matrix. As explained above, this +is a square matrix with as many columns as the vector used to +construct the matrix. + +\b TO \b DO: What about the \c Nested typedef? It seems to be +necessary; is this only temporary? + +\include make_circulant.cpp.expression + + +\section TopicEvaluator The evaluator + +The last big fragment implements the evaluator for the \c Circulant +expression. The evaluator computes the entries of the circulant +matrix; this is done in the \c .coeff() member function. The entries +are computed by finding the corresponding entry of the vector from +which the circulant matrix is constructed. Getting this entry may +actually be non-trivial when the circulant matrix is constructed from +a vector which is given by a complicated expression, so we use the +evaluator which corresponds to the vector. + +The \c CoeffReadCost constant records the cost of computing an entry +of the circulant matrix; we ignore the index computation and say that +this is the same as the cost of computing an entry of the vector from +which the circulant matrix is constructed. + +In the constructor, we save the evaluator for the column vector which +defined the circulant matrix. We also save the size of that vector; +remember that we can query an expression object to find the size but +not the evaluator. + +\include make_circulant.cpp.evaluator + + +\section TopicEntry The entry point + +After all this, the \c makeCirculant function is very simple. It +simply creates an expression object and returns it. + +\include make_circulant.cpp.entry + + +\section TopicMain A simple main function for testing + +Finally, a short \c main function that shows how the \c makeCirculant +function can be called. + +\include make_circulant.cpp.main + +If all the fragments are combined, the following output is produced, +showing that the program works as expected: + +\verbinclude make_circulant.out + +*/ +} + diff --git a/doc/examples/make_circulant.cpp b/doc/examples/make_circulant.cpp new file mode 100644 index 000000000..92e6aaa2b --- /dev/null +++ b/doc/examples/make_circulant.cpp @@ -0,0 +1,11 @@ +/* +This program is presented in several fragments in the doc page. +Every fragment is in its own file; this file simply combines them. +*/ + +#include "make_circulant.cpp.preamble" +#include "make_circulant.cpp.traits" +#include "make_circulant.cpp.expression" +#include "make_circulant.cpp.evaluator" +#include "make_circulant.cpp.entry" +#include "make_circulant.cpp.main" diff --git a/doc/examples/make_circulant.cpp.entry b/doc/examples/make_circulant.cpp.entry new file mode 100644 index 000000000..f9d2eb8a9 --- /dev/null +++ b/doc/examples/make_circulant.cpp.entry @@ -0,0 +1,5 @@ +template +Circulant makeCirculant(const Eigen::MatrixBase& arg) +{ + return Circulant(arg.derived()); +} diff --git a/doc/examples/make_circulant.cpp.evaluator b/doc/examples/make_circulant.cpp.evaluator new file mode 100644 index 000000000..98713cdc0 --- /dev/null +++ b/doc/examples/make_circulant.cpp.evaluator @@ -0,0 +1,33 @@ +namespace Eigen { + namespace internal { + template + struct evaluator > + : evaluator_base > + { + typedef Circulant XprType; + typedef typename nested_eval::type ArgTypeNested; + typedef typename remove_all::type ArgTypeNestedCleaned; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::Index Index; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = Eigen::ColMajor + }; + + evaluator(const XprType& xpr) + : m_argImpl(xpr.m_arg), m_rows(xpr.rows()) + { } + + CoeffReturnType coeff(Index row, Index col) const + { + Index index = row - col; + if (index < 0) index += m_rows; + return m_argImpl.coeff(index); + } + + typename evaluator::nestedType m_argImpl; + const Index m_rows; + }; + } +} diff --git a/doc/examples/make_circulant.cpp.expression b/doc/examples/make_circulant.cpp.expression new file mode 100644 index 000000000..a68bcb730 --- /dev/null +++ b/doc/examples/make_circulant.cpp.expression @@ -0,0 +1,20 @@ +template +class Circulant : public Eigen::MatrixBase > +{ +public: + Circulant(const ArgType& arg) + : m_arg(arg) + { + EIGEN_STATIC_ASSERT(ArgType::ColsAtCompileTime == 1, + YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX); + } + + typedef typename Eigen::internal::ref_selector::type Nested; + + typedef typename Eigen::internal::traits::Index Index; + Index rows() const { return m_arg.rows(); } + Index cols() const { return m_arg.rows(); } + + typedef typename Eigen::internal::ref_selector::type ArgTypeNested; + ArgTypeNested m_arg; +}; diff --git a/doc/examples/make_circulant.cpp.main b/doc/examples/make_circulant.cpp.main new file mode 100644 index 000000000..877f97f62 --- /dev/null +++ b/doc/examples/make_circulant.cpp.main @@ -0,0 +1,8 @@ +int main() +{ + Eigen::VectorXd vec(4); + vec << 1, 2, 4, 8; + Eigen::MatrixXd mat; + mat = makeCirculant(vec); + std::cout << mat << std::endl; +} diff --git a/doc/examples/make_circulant.cpp.preamble b/doc/examples/make_circulant.cpp.preamble new file mode 100644 index 000000000..e575cce14 --- /dev/null +++ b/doc/examples/make_circulant.cpp.preamble @@ -0,0 +1,4 @@ +#include +#include + +template class Circulant; diff --git a/doc/examples/make_circulant.cpp.traits b/doc/examples/make_circulant.cpp.traits new file mode 100644 index 000000000..f91e43717 --- /dev/null +++ b/doc/examples/make_circulant.cpp.traits @@ -0,0 +1,19 @@ +namespace Eigen { + namespace internal { + template + struct traits > + { + typedef Eigen::Dense StorageKind; + typedef Eigen::MatrixXpr XprKind; + typedef typename ArgType::Index Index; + typedef typename ArgType::Scalar Scalar; + enum { + Flags = Eigen::ColMajor, + RowsAtCompileTime = ArgType::RowsAtCompileTime, + ColsAtCompileTime = ArgType::RowsAtCompileTime, + MaxRowsAtCompileTime = ArgType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ArgType::MaxRowsAtCompileTime + }; + }; + } +} -- cgit v1.2.3 From 74cde0c925ae91598276c3dcb1c0e1250b770dfc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 28 Sep 2014 09:16:13 +0200 Subject: Add missing return derived() in ArrayBase::operator= --- Eigen/src/Core/ArrayBase.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Eigen/src/Core/ArrayBase.h b/Eigen/src/Core/ArrayBase.h index b37b49ac4..d42693d4b 100644 --- a/Eigen/src/Core/ArrayBase.h +++ b/Eigen/src/Core/ArrayBase.h @@ -121,6 +121,7 @@ template class ArrayBase Derived& operator=(const ArrayBase& other) { internal::call_assignment(derived(), other.derived()); + return derived(); } /** Set all the entries to \a value. -- cgit v1.2.3 From 75e269c77b82fdac35fa8516f256bb44df1e52cc Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Sat, 20 Sep 2014 14:57:42 +0200 Subject: Fixed warning on implicit integer conversion in test case code by using type VectorXd::Index instead of int. --- unsupported/test/NonLinearOptimization.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index 75974f84f..724ea7b5b 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -246,9 +246,9 @@ struct hybrj_functor : Functor int operator()(const VectorXd &x, VectorXd &fvec) { double temp, temp1, temp2; - const int n = x.size(); + const VectorXd::Index n = x.size(); assert(fvec.size()==n); - for (int k = 0; k < n; k++) + for (VectorXd::Index k = 0; k < n; k++) { temp = (3. - 2.*x[k])*x[k]; temp1 = 0.; @@ -261,12 +261,12 @@ struct hybrj_functor : Functor } int df(const VectorXd &x, MatrixXd &fjac) { - const int n = x.size(); + const VectorXd::Index n = x.size(); assert(fjac.rows()==n); assert(fjac.cols()==n); - for (int k = 0; k < n; k++) + for (VectorXd::Index k = 0; k < n; k++) { - for (int j = 0; j < n; j++) + for (VectorXd::Index j = 0; j < n; j++) fjac(k,j) = 0.; fjac(k,k) = 3.- 4.*x[k]; if (k) fjac(k,k-1) = -1.; @@ -351,10 +351,10 @@ struct hybrd_functor : Functor int operator()(const VectorXd &x, VectorXd &fvec) const { double temp, temp1, temp2; - const int n = x.size(); + const VectorXd::Index n = x.size(); assert(fvec.size()==n); - for (int k=0; k < n; k++) + for (VectorXd::Index k=0; k < n; k++) { temp = (3. - 2.*x[k])*x[k]; temp1 = 0.; @@ -455,7 +455,7 @@ struct lmstr_functor : Functor assert(jac_row.size()==x.size()); double tmp1, tmp2, tmp3, tmp4; - int i = rownb-2; + VectorXd::Index i = rownb-2; tmp1 = i+1; tmp2 = 16 - i - 1; tmp3 = (i>=8)? tmp2 : tmp1; -- cgit v1.2.3 From 3bd31e21b5aac1aaf1c0e217f472846450b2d5fb Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Sat, 20 Sep 2014 15:00:36 +0200 Subject: Fixed compiler warning on implicit integer conversion by separating index type for matrix and permutation matrix which may not be equal. --- unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h b/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h index f5290dee4..db3a0ef2c 100644 --- a/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h +++ b/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h @@ -19,18 +19,19 @@ namespace Eigen { namespace internal { -template +template void lmqrsolv( Matrix &s, - const PermutationMatrix &iPerm, + const PermutationMatrix &iPerm, const Matrix &diag, const Matrix &qtb, Matrix &x, Matrix &sdiag) { + typedef typename Matrix::Index Index; /* Local variables */ - Index i, j, k, l; + Index i, j, k; Scalar temp; Index n = s.cols(); Matrix wa(n); @@ -52,7 +53,7 @@ void lmqrsolv( /* prepare the row of d to be eliminated, locating the */ /* diagonal element using p from the qr factorization. */ - l = iPerm.indices()(j); + const PermIndex l = iPerm.indices()(j); if (diag[l] == 0.) break; sdiag.tail(n-j).setZero(); -- cgit v1.2.3 From edaefeb9786d529cdf17a7d396a4c1962b23cdd3 Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Sun, 21 Sep 2014 10:01:12 +0200 Subject: Using Kernel::Index type instead of int to prevent possible implicit conversion from long to int. --- Eigen/src/Core/AssignEvaluator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 8ab71446c..5d5095a67 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -182,7 +182,7 @@ struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &kernel, int outer) + static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) { kernel.assignCoeffByOuterInner(outer, Index); copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); @@ -192,7 +192,7 @@ struct copy_using_evaluator_DefaultTraversal_InnerUnrolling template struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel&, int) { } + static EIGEN_STRONG_INLINE void run(Kernel&, typename Kernel::Index) { } }; /*********************** @@ -249,7 +249,7 @@ struct copy_using_evaluator_innervec_CompleteUnrolling template struct copy_using_evaluator_innervec_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &kernel, int outer) + static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) { kernel.template assignPacketByOuterInner(outer, Index); enum { NextIndex = Index + packet_traits::size }; @@ -260,7 +260,7 @@ struct copy_using_evaluator_innervec_InnerUnrolling template struct copy_using_evaluator_innervec_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &, int) { } + static EIGEN_STRONG_INLINE void run(Kernel &, typename Kernel::Index) { } }; /*************************************************************************** -- cgit v1.2.3 From d1ef3c35465dca670002f47ad07c1618fc2d8905 Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Sun, 21 Sep 2014 10:21:20 +0200 Subject: Changed Diagonal::index() to return an Index type instead of int to prevent possible implicit conversion from long to int. Added inline keyword to member methods. --- Eigen/src/Core/Diagonal.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index ba7ddbb14..6ffc0c762 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -80,7 +80,6 @@ template class Diagonal EIGEN_USING_STD_MATH(min); return m_index.value()<0 ? (min)(Index(m_matrix.cols()),Index(m_matrix.rows()+m_index.value())) : (min)(Index(m_matrix.rows()),Index(m_matrix.cols()-m_index.value())); - } EIGEN_DEVICE_FUNC @@ -148,14 +147,14 @@ template class Diagonal } EIGEN_DEVICE_FUNC - const typename internal::remove_all::type& + inline const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } EIGEN_DEVICE_FUNC - int index() const + inline Index index() const { return m_index.value(); } @@ -172,7 +171,7 @@ template class Diagonal EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } - // triger a compile time error is someone try to call packet + // trigger a compile time error is someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; -- cgit v1.2.3 From b2755edcddfc60c508e78f1e49c6cf137894195d Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Sun, 21 Sep 2014 23:15:35 +0200 Subject: Replaced hard coded int types with Index types preventing implicit integer conversions. --- Eigen/src/Core/PermutationMatrix.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 98c83047a..b67046144 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -119,7 +119,7 @@ class PermutationBase : public EigenBase void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i * * \returns a reference to *this. * - * \warning This is much slower than applyTranspositionOnTheRight(int,int): + * \warning This is much slower than applyTranspositionOnTheRight(Index,Index): * this has linear complexity and requires a lot of branching. * - * \sa applyTranspositionOnTheRight(int,int) + * \sa applyTranspositionOnTheRight(Index,Index) */ Derived& applyTranspositionOnTheLeft(Index i, Index j) { @@ -186,7 +186,7 @@ class PermutationBase : public EigenBase * * This is a fast operation, it only consists in swapping two indices. * - * \sa applyTranspositionOnTheLeft(int,int) + * \sa applyTranspositionOnTheLeft(Index,Index) */ Derived& applyTranspositionOnTheRight(Index i, Index j) { @@ -216,13 +216,13 @@ class PermutationBase : public EigenBase template void assignTranspose(const PermutationBase& other) { - for (int i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i >& other) : m_indices(other.nestedPermutation().size()) { - for (int i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) @@ -596,7 +596,7 @@ struct permut_matrix_product_retval } else { - for(int i = 0; i < n; ++i) + for(Index i = 0; i < n; ++i) { Block (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) @@ -645,19 +645,20 @@ class Transpose > MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; typedef typename Traits::Scalar Scalar; + typedef typename Traits::Index Index; #endif Transpose(const PermutationType& p) : m_permutation(p) {} - inline int rows() const { return m_permutation.rows(); } - inline int cols() const { return m_permutation.cols(); } + inline Index rows() const { return m_permutation.rows(); } + inline Index cols() const { return m_permutation.cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i Date: Sun, 21 Sep 2014 23:19:29 +0200 Subject: Correcting the ReturnType in traits> to include the correct Index type. Fixed mixup of types Rhs::Index and Lhs:Index in various loop variables. Added explicit type conversion for arithmetic expressions which may return a wider type. --- .../src/KroneckerProduct/KroneckerTensorProduct.h | 31 ++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h index 72e25db19..608c72021 100644 --- a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h @@ -48,8 +48,8 @@ class KroneckerProductBase : public ReturnByValue */ Scalar coeff(Index row, Index col) const { - return m_A.coeff(row / m_B.rows(), col / m_B.cols()) * - m_B.coeff(row % m_B.rows(), col % m_B.cols()); + return m_A.coeff(typename Lhs::Index(row / m_B.rows()), typename Lhs::Index(col / m_B.cols())) * + m_B.coeff(typename Rhs::Index(row % m_B.rows()), typename Rhs::Index(col % m_B.cols())); } /*! @@ -59,7 +59,7 @@ class KroneckerProductBase : public ReturnByValue Scalar coeff(Index i) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); - return m_A.coeff(i / m_A.size()) * m_B.coeff(i % m_A.size()); + return m_A.coeff(typename Lhs::Index(i / m_A.size())) * m_B.coeff(typename Rhs::Index(i % m_A.size())); } protected: @@ -148,10 +148,12 @@ template template void KroneckerProductSparse::evalTo(Dest& dst) const { - typedef typename Base::Index Index; - const Index Br = m_B.rows(), - Bc = m_B.cols(); - dst.resize(this->rows(), this->cols()); + typedef typename Dest::Index DestIndex; + const typename Rhs::Index Br = m_B.rows(), + Bc = m_B.cols(); + eigen_assert(this->rows() <= NumTraits::highest()); + eigen_assert(this->cols() <= NumTraits::highest()); + dst.resize(DestIndex(this->rows()), DestIndex(this->cols())); dst.resizeNonZeros(0); // 1 - evaluate the operands if needed: @@ -182,12 +184,12 @@ void KroneckerProductSparse::evalTo(Dest& dst) const // compute number of non-zeros per innervectors of dst { VectorXi nnzA = VectorXi::Zero(Dest::IsRowMajor ? m_A.rows() : m_A.cols()); - for (Index kA=0; kA < m_A.outerSize(); ++kA) + for (typename Lhs::Index kA=0; kA < m_A.outerSize(); ++kA) for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) nnzA(Dest::IsRowMajor ? itA.row() : itA.col())++; VectorXi nnzB = VectorXi::Zero(Dest::IsRowMajor ? m_B.rows() : m_B.cols()); - for (Index kB=0; kB < m_B.outerSize(); ++kB) + for (typename Rhs::Index kB=0; kB < m_B.outerSize(); ++kB) for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) nnzB(Dest::IsRowMajor ? itB.row() : itB.col())++; @@ -195,16 +197,17 @@ void KroneckerProductSparse::evalTo(Dest& dst) const dst.reserve(VectorXi::Map(nnzAB.data(), nnzAB.size())); } - for (Index kA=0; kA < m_A.outerSize(); ++kA) + for (typename Lhs::Index kA=0; kA < m_A.outerSize(); ++kA) { - for (Index kB=0; kB < m_B.outerSize(); ++kB) + for (typename Rhs::Index kB=0; kB < m_B.outerSize(); ++kB) { for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) { for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) { - const Index i = itA.row() * Br + itB.row(), - j = itA.col() * Bc + itB.col(); + const DestIndex + i = DestIndex(itA.row() * Br + itB.row()), + j = DestIndex(itA.col() * Bc + itB.col()); dst.insert(i,j) = itA.value() * itB.value(); } } @@ -259,7 +262,7 @@ struct traits > CoeffReadCost = Dynamic }; - typedef SparseMatrix ReturnType; + typedef SparseMatrix ReturnType; }; } // end namespace internal -- cgit v1.2.3 From 2c4cace56ca2a937d73700c2e8348dadb711758b Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Mon, 22 Sep 2014 15:54:34 +0200 Subject: Using Index instead of hard coded int type to prevent potential implicit integer conversion --- Eigen/src/Core/GeneralProduct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index e05ff8dce..4eb01b1b3 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -261,7 +261,7 @@ template<> struct gemv_dense_sense_selector if(!evalToDest) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); + Index size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif if(!alphaIsCompatible) @@ -327,7 +327,7 @@ template<> struct gemv_dense_sense_selector if(!DirectlyUseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); + Index size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif Map(actualRhsPtr, actualRhs.size()) = actualRhs; -- cgit v1.2.3 From 821ff0ecfb4efe86e5045742682c918b01e5a263 Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Mon, 22 Sep 2014 16:12:35 +0200 Subject: Using Index instead of hard coded int type to prevent potential implicit integer conversion --- Eigen/src/Core/products/SelfadjointMatrixVector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index d9c041f0c..372a44e47 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h @@ -218,7 +218,7 @@ struct selfadjoint_product_impl if(!EvalToDest) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); + Index size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif MappedDest(actualDestPtr, dest.size()) = dest; @@ -227,7 +227,7 @@ struct selfadjoint_product_impl if(!UseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = rhs.size(); + Index size = rhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif Map(actualRhsPtr, rhs.size()) = rhs; -- cgit v1.2.3 From 2946992ad4bc929d231282b477a23175cc1c0090 Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Mon, 22 Sep 2014 17:59:02 +0200 Subject: Using StorageIndexType for loop assigning initial permutation. Adding assert for index overflow. --- Eigen/src/Core/PermutationMatrix.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index b67046144..d5113ce19 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -374,7 +374,9 @@ class PermutationMatrix : public PermutationBase >& other) : m_indices(other.nestedPermutation().size()) { - for (typename IndicesType::Index i=0; i::highest()); + for (StorageIndexType i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) -- cgit v1.2.3 From f0a62c90bcb59bbea04cbb3cb4cc818cda9251ce Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 29 Sep 2014 10:27:51 +0200 Subject: Avoid comparisons between different index types. --- Eigen/src/Core/PermutationMatrix.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index d5113ce19..4846f2ae1 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -303,7 +303,9 @@ class PermutationMatrix : public PermutationBase::highest()); + } /** Copy constructor. */ template @@ -375,7 +377,8 @@ class PermutationMatrix : public PermutationBase::highest()); - for (StorageIndexType i=0; i -- cgit v1.2.3 From 9a04cd307c1cbb271373d6c4f32b5921da6144ef Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Mon, 22 Sep 2014 18:47:33 +0200 Subject: Added implicit integer conversion by using explicit integer type conversion. Adding assert to catch overflow. --- Eigen/src/SparseLU/SparseLU.h | 7 +++++-- Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index cd4ea5b13..1789830b9 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -675,8 +675,11 @@ struct SparseLUMatrixUReturnType : internal::no_assignment_operator template void solveInPlace(MatrixBase &X) const { - Index nrhs = X.cols(); - Index n = X.rows(); + /* Explicit type conversion as the Index type of MatrixBase may be wider than Index */ + eigen_assert(X.rows() <= NumTraits::highest()); + eigen_assert(X.cols() <= NumTraits::highest()); + Index nrhs = Index(X.cols()); + Index n = Index(X.rows()); // Backward solve with U for (Index k = m_mapL.nsuper(); k >= 0; k--) { diff --git a/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h b/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h index ad6f2183f..6b0b83e0b 100644 --- a/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +++ b/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h @@ -233,8 +233,11 @@ template template void MappedSuperNodalMatrix::solveInPlace( MatrixBase&X) const { - Index n = X.rows(); - Index nrhs = X.cols(); + /* Explicit type conversion as the Index type of MatrixBase may be wider than Index */ + eigen_assert(X.rows() <= NumTraits::highest()); + eigen_assert(X.cols() <= NumTraits::highest()); + Index n = Index(X.rows()); + Index nrhs = Index(X.cols()); const Scalar * Lval = valuePtr(); // Nonzero values Matrix work(n, nrhs); // working vector work.setZero(); -- cgit v1.2.3 From bc34ee3365eadd742eefe59561ad11c51adecd41 Mon Sep 17 00:00:00 2001 From: Georg Drenkhahn Date: Mon, 22 Sep 2014 18:56:36 +0200 Subject: Using Index type instead of hard coded int type to prevent potential implicit integer conversion. --- Eigen/src/SparseLU/SparseLU_kernel_bmod.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Eigen/src/SparseLU/SparseLU_kernel_bmod.h b/Eigen/src/SparseLU/SparseLU_kernel_bmod.h index 0d0283b13..cad149ded 100644 --- a/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +++ b/Eigen/src/SparseLU/SparseLU_kernel_bmod.h @@ -31,13 +31,13 @@ namespace internal { template struct LU_kernel_bmod { template - static EIGEN_DONT_INLINE void run(const int segsize, BlockScalarVector& dense, ScalarVector& tempv, ScalarVector& lusup, Index& luptr, const Index lda, + static EIGEN_DONT_INLINE void run(const Index segsize, BlockScalarVector& dense, ScalarVector& tempv, ScalarVector& lusup, Index& luptr, const Index lda, const Index nrow, IndexVector& lsub, const Index lptr, const Index no_zeros); }; template template -EIGEN_DONT_INLINE void LU_kernel_bmod::run(const int segsize, BlockScalarVector& dense, ScalarVector& tempv, ScalarVector& lusup, Index& luptr, const Index lda, +EIGEN_DONT_INLINE void LU_kernel_bmod::run(const Index segsize, BlockScalarVector& dense, ScalarVector& tempv, ScalarVector& lusup, Index& luptr, const Index lda, const Index nrow, IndexVector& lsub, const Index lptr, const Index no_zeros) { typedef typename ScalarVector::Scalar Scalar; @@ -45,7 +45,7 @@ EIGEN_DONT_INLINE void LU_kernel_bmod::run(const int segsi // The result of triangular solve is in tempv[*]; // The result of matric-vector update is in dense[*] Index isub = lptr + no_zeros; - int i; + Index i; Index irow; for (i = 0; i < ((SegSizeAtCompileTime==Dynamic)?segsize:SegSizeAtCompileTime); i++) { @@ -92,13 +92,13 @@ EIGEN_DONT_INLINE void LU_kernel_bmod::run(const int segsi template <> struct LU_kernel_bmod<1> { template - static EIGEN_DONT_INLINE void run(const int /*segsize*/, BlockScalarVector& dense, ScalarVector& /*tempv*/, ScalarVector& lusup, Index& luptr, + static EIGEN_DONT_INLINE void run(const Index /*segsize*/, BlockScalarVector& dense, ScalarVector& /*tempv*/, ScalarVector& lusup, Index& luptr, const Index lda, const Index nrow, IndexVector& lsub, const Index lptr, const Index no_zeros); }; template -EIGEN_DONT_INLINE void LU_kernel_bmod<1>::run(const int /*segsize*/, BlockScalarVector& dense, ScalarVector& /*tempv*/, ScalarVector& lusup, Index& luptr, +EIGEN_DONT_INLINE void LU_kernel_bmod<1>::run(const Index /*segsize*/, BlockScalarVector& dense, ScalarVector& /*tempv*/, ScalarVector& lusup, Index& luptr, const Index lda, const Index nrow, IndexVector& lsub, const Index lptr, const Index no_zeros) { typedef typename ScalarVector::Scalar Scalar; -- cgit v1.2.3 From 76c3cf694987382c7d92c3fb7cdf65215bfdeb5e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 29 Sep 2014 10:33:16 +0200 Subject: Re-enable -Wshorten-64-to-32 compilation flag. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3753edb0..ea42cc8db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,7 +143,7 @@ if(NOT MSVC) ei_add_cxx_compiler_flag("-Wpointer-arith") ei_add_cxx_compiler_flag("-Wwrite-strings") ei_add_cxx_compiler_flag("-Wformat-security") -# ei_add_cxx_compiler_flag("-Wshorten-64-to-32") + ei_add_cxx_compiler_flag("-Wshorten-64-to-32") ei_add_cxx_compiler_flag("-Wenum-conversion") ei_add_cxx_compiler_flag("-Wc++11-extensions") -- cgit v1.2.3 From abd3502e9ea3e659c39dd5edc17d6deabd26e048 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 29 Sep 2014 13:36:57 +0200 Subject: Introduce a generic InnerIterator classes compatible with evaluators. --- Eigen/src/Core/CoreEvaluators.h | 3 - Eigen/src/Core/CoreIterators.h | 143 ++++++++++++++++++++++-------- Eigen/src/Core/DenseBase.h | 6 +- Eigen/src/Core/util/Constants.h | 10 +++ Eigen/src/Core/util/ForwardDeclarations.h | 1 + 5 files changed, 122 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index ab4320c2a..50caf4bab 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -17,9 +17,6 @@ namespace Eigen { namespace internal { -struct IndexBased {}; -struct IteratorBased {}; - // This class returns the evaluator kind from the expression storage kind. // Default assumes index based accessors template diff --git a/Eigen/src/Core/CoreIterators.h b/Eigen/src/Core/CoreIterators.h index 6da4683d2..7feebc4e4 100644 --- a/Eigen/src/Core/CoreIterators.h +++ b/Eigen/src/Core/CoreIterators.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,47 +15,116 @@ namespace Eigen { /* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core */ -/** \ingroup SparseCore_Module - * \class InnerIterator - * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression - * - * todo +namespace internal { + +template +class inner_iterator_selector; + +} + +/** \class InnerIterator + * \brief An InnerIterator allows to loop over the element of any matrix expression. + * + * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. + * + * TODO: add a usage example */ +template +class InnerIterator +{ +protected: + typedef internal::inner_iterator_selector::Kind> IteratorType; + typedef typename internal::evaluator::type EvaluatorType; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::Index Index; +public: + /** Construct an iterator over the \a outerId -th row or column of \a xpr */ + InnerIterator(const XprType &xpr, const Index &outerId) + : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) + {} + + /// \returns the value of the current coefficient. + EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } + /** Increment the iterator \c *this to the next non-zero coefficient. + * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView + */ + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } + /// \returns the column or row index of the current coefficient. + EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } + /// \returns the row index of the current coefficient. + EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } + /// \returns the column index of the current coefficient. + EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } + /// \returns \c true if the iterator \c *this still references a valid coefficient. + EIGEN_STRONG_INLINE operator bool() const { return m_iter; } + +protected: + EvaluatorType m_eval; + IteratorType m_iter; +private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const EigenBase&,Index outer); +}; + +namespace internal { -// generic version for dense matrix and expressions -template class DenseBase::InnerIterator +// Generic inner iterator implementation for dense objects +template +class inner_iterator_selector { - protected: - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; - public: - EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) - : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) - {} - - EIGEN_STRONG_INLINE Scalar value() const - { - return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) - : m_expression.coeff(m_inner, m_outer); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } - - EIGEN_STRONG_INLINE Index index() const { return m_inner; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } - - protected: - const Derived& m_expression; - Index m_inner; - const Index m_outer; - const Index m_end; +protected: + typedef typename evaluator::type EvaluatorType; + typedef typename traits::Scalar Scalar; + typedef typename traits::Index Index; + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) + : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) + : m_eval.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE inner_iterator_selector& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + +protected: + const EvaluatorType& m_eval; + Index m_inner; + const Index m_outer; + const Index m_end; }; +// For iterator-based evaluator, inner-iterator is already implemented as +// evaluator<>::InnerIterator +template +class inner_iterator_selector + : public evaluator::InnerIterator +{ +protected: + typedef typename evaluator::InnerIterator Base; + typedef typename evaluator::type EvaluatorType; + typedef typename traits::Index Index; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) + : Base(eval, outerId) + {} +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_COREITERATORS_H diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 101ef6f20..c4128e192 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -50,7 +50,11 @@ template class DenseBase using internal::special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real>::operator*; - class InnerIterator; + + /** Inner iterator type to iterate over the coefficients of a row or column. + * \sa class InnerIterator + */ + typedef InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 2c9fb443d..5c7d70af6 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -468,6 +468,16 @@ struct SelfAdjointShape { static std::string debugName() { return "SelfAdj struct PermutationShape { static std::string debugName() { return "PermutationShape"; } }; struct SparseShape { static std::string debugName() { return "SparseShape"; } }; +namespace internal { + + // random access iterators based on coeff*() accessors. +struct IndexBased {}; + +// evaluator based on iterators to access coefficients. +struct IteratorBased {}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_CONSTANTS_H diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 9ec57468b..be156a44a 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -137,6 +137,7 @@ template struct CommaInitializer; template class ReturnByValue; template class ArrayWrapper; template class MatrixWrapper; +template class InnerIterator; namespace internal { template struct kernel_retval_base; -- cgit v1.2.3 From 842e31cf5c8fd31f394156ada84a1aeeab89ef7e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 29 Sep 2014 13:37:49 +0200 Subject: Let KroneckerProduct exploits the recently introduced generic InnerIterator class. --- .../src/KroneckerProduct/KroneckerTensorProduct.h | 33 +++++++--------------- unsupported/test/kronecker_product.cpp | 12 ++++++++ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h index 608c72021..b459360df 100644 --- a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h @@ -157,40 +157,27 @@ void KroneckerProductSparse::evalTo(Dest& dst) const dst.resizeNonZeros(0); // 1 - evaluate the operands if needed: - typedef typename internal::nested_eval::type Lhs1; + typedef typename internal::nested_eval::type Lhs1; typedef typename internal::remove_all::type Lhs1Cleaned; const Lhs1 lhs1(m_A); - typedef typename internal::nested_eval::type Rhs1; + typedef typename internal::nested_eval::type Rhs1; typedef typename internal::remove_all::type Rhs1Cleaned; const Rhs1 rhs1(m_B); - - // 2 - construct a SparseView for dense operands - typedef typename internal::conditional::StorageKind,Sparse>::value, Lhs1, SparseView >::type Lhs2; - typedef typename internal::remove_all::type Lhs2Cleaned; - const Lhs2 lhs2(lhs1); - typedef typename internal::conditional::StorageKind,Sparse>::value, Rhs1, SparseView >::type Rhs2; - typedef typename internal::remove_all::type Rhs2Cleaned; - const Rhs2 rhs2(rhs1); - - // 3 - construct respective evaluators - typedef typename internal::evaluator::type LhsEval; - LhsEval lhsEval(lhs2); - typedef typename internal::evaluator::type RhsEval; - RhsEval rhsEval(rhs2); - - typedef typename LhsEval::InnerIterator LhsInnerIterator; - typedef typename RhsEval::InnerIterator RhsInnerIterator; + + // 2 - construct respective iterators + typedef InnerIterator LhsInnerIterator; + typedef InnerIterator RhsInnerIterator; // compute number of non-zeros per innervectors of dst { VectorXi nnzA = VectorXi::Zero(Dest::IsRowMajor ? m_A.rows() : m_A.cols()); for (typename Lhs::Index kA=0; kA < m_A.outerSize(); ++kA) - for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) + for (LhsInnerIterator itA(lhs1,kA); itA; ++itA) nnzA(Dest::IsRowMajor ? itA.row() : itA.col())++; VectorXi nnzB = VectorXi::Zero(Dest::IsRowMajor ? m_B.rows() : m_B.cols()); for (typename Rhs::Index kB=0; kB < m_B.outerSize(); ++kB) - for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) + for (RhsInnerIterator itB(rhs1,kB); itB; ++itB) nnzB(Dest::IsRowMajor ? itB.row() : itB.col())++; Matrix nnzAB = nnzB * nnzA.transpose(); @@ -201,9 +188,9 @@ void KroneckerProductSparse::evalTo(Dest& dst) const { for (typename Rhs::Index kB=0; kB < m_B.outerSize(); ++kB) { - for (LhsInnerIterator itA(lhsEval,kA); itA; ++itA) + for (LhsInnerIterator itA(lhs1,kA); itA; ++itA) { - for (RhsInnerIterator itB(rhsEval,kB); itB; ++itB) + for (RhsInnerIterator itB(rhs1,kB); itB; ++itB) { const DestIndex i = DestIndex(itA.row() * Br + itB.row()), diff --git a/unsupported/test/kronecker_product.cpp b/unsupported/test/kronecker_product.cpp index 753a2d417..02411a262 100644 --- a/unsupported/test/kronecker_product.cpp +++ b/unsupported/test/kronecker_product.cpp @@ -216,5 +216,17 @@ void test_kronecker_product() sC2 = kroneckerProduct(sA,sB); dC = kroneckerProduct(dA,dB); VERIFY_IS_APPROX(MatrixXf(sC2),dC); + + sC2 = kroneckerProduct(dA,sB); + dC = kroneckerProduct(dA,dB); + VERIFY_IS_APPROX(MatrixXf(sC2),dC); + + sC2 = kroneckerProduct(sA,dB); + dC = kroneckerProduct(dA,dB); + VERIFY_IS_APPROX(MatrixXf(sC2),dC); + + sC2 = kroneckerProduct(2*sA,sB); + dC = kroneckerProduct(2*dA,dB); + VERIFY_IS_APPROX(MatrixXf(sC2),dC); } } -- cgit v1.2.3 From 56a0bbbbee6b882995e065504c15fadbcfb1a6ef Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 29 Sep 2014 18:28:18 +0200 Subject: Fix compilation with GCC --- Eigen/src/Core/DenseBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index c4128e192..14c1902e4 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -54,7 +54,7 @@ template class DenseBase /** Inner iterator type to iterate over the coefficients of a row or column. * \sa class InnerIterator */ - typedef InnerIterator InnerIterator; + typedef Eigen::InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; -- cgit v1.2.3 From 15c946338ff8c9ada9e2daa1044121115d45a0f6 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Mon, 29 Sep 2014 19:20:01 +0200 Subject: Related to bug #880: Accept make as well a gmake when searching the MakeCommand. And don't include \n in match expression --- cmake/EigenConfigureTesting.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/EigenConfigureTesting.cmake b/cmake/EigenConfigureTesting.cmake index 05c8c1466..1f19e81a9 100644 --- a/cmake/EigenConfigureTesting.cmake +++ b/cmake/EigenConfigureTesting.cmake @@ -24,9 +24,9 @@ set(EIGEN_TEST_BUILD_FLAGS "" CACHE STRING "Options passed to the build command # At this stage, we can also add custom flags to the build tool through the user defined EIGEN_TEST_BUILD_FLAGS variable. file(READ "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" EIGEN_DART_CONFIG_FILE) # try to grab the default flags -string(REGEX MATCH "MakeCommand:.*-- (.*)DefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) +string(REGEX MATCH "MakeCommand:.*-- (.*)\nDefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) if(NOT CMAKE_MATCH_1) -string(REGEX MATCH "MakeCommand:.*gmake (.*)DefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) +string(REGEX MATCH "MakeCommand:.*make (.*)\nDefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) endif() string(REGEX REPLACE "MakeCommand:.*DefaultCTestConfigurationType" "MakeCommand: ${CMAKE_COMMAND} --build . --target buildtests --config \"\${CTEST_CONFIGURATION_TYPE}\" -- ${CMAKE_MATCH_1} ${EIGEN_TEST_BUILD_FLAGS}\nDefaultCTestConfigurationType" EIGEN_DART_CONFIG_FILE2 ${EIGEN_DART_CONFIG_FILE}) -- cgit v1.2.3 From e404841235cf9d995f59e9b629ebf111f9271e0b Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Mon, 29 Sep 2014 19:28:10 +0000 Subject: make sure that regex does not match cmake --- cmake/EigenConfigureTesting.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EigenConfigureTesting.cmake b/cmake/EigenConfigureTesting.cmake index 1f19e81a9..737f77232 100644 --- a/cmake/EigenConfigureTesting.cmake +++ b/cmake/EigenConfigureTesting.cmake @@ -26,7 +26,7 @@ file(READ "${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl" EIGEN_DART_CONFIG # try to grab the default flags string(REGEX MATCH "MakeCommand:.*-- (.*)\nDefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) if(NOT CMAKE_MATCH_1) -string(REGEX MATCH "MakeCommand:.*make (.*)\nDefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) +string(REGEX MATCH "MakeCommand:.*[^c]make (.*)\nDefaultCTestConfigurationType" EIGEN_DUMMY ${EIGEN_DART_CONFIG_FILE}) endif() string(REGEX REPLACE "MakeCommand:.*DefaultCTestConfigurationType" "MakeCommand: ${CMAKE_COMMAND} --build . --target buildtests --config \"\${CTEST_CONFIGURATION_TYPE}\" -- ${CMAKE_MATCH_1} ${EIGEN_TEST_BUILD_FLAGS}\nDefaultCTestConfigurationType" EIGEN_DART_CONFIG_FILE2 ${EIGEN_DART_CONFIG_FILE}) -- cgit v1.2.3 From 12d59465cb78ba058192ec4ce3039aa097bf2696 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 30 Sep 2014 14:57:54 +0200 Subject: bug #884: Copy constructor of Ref shall never malloc, constructing from other RefBase shall only malloc if the memory layout is incompatible. --- Eigen/src/Core/Ref.h | 9 +++++++++ test/nomalloc.cpp | 32 +++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 09921c9e7..2653f2bbe 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -232,6 +232,15 @@ template class Ref< construct(expr.derived(), typename Traits::template match::type()); } + inline Ref(const Ref& other) : Base(other) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template + inline Ref(const RefBase& other) { + construct(other.derived(), typename Traits::template match::type()); + } + protected: template diff --git a/test/nomalloc.cpp b/test/nomalloc.cpp index 5458806f5..306664210 100644 --- a/test/nomalloc.cpp +++ b/test/nomalloc.cpp @@ -21,7 +21,7 @@ // discard stack allocation as that too bypasses malloc #define EIGEN_STACK_ALLOCATION_LIMIT 0 // any heap allocation will raise an assert -#define EIGEN_NO_MALLOC +#define EIGEN_RUNTIME_NO_MALLOC #include "main.h" #include @@ -183,9 +183,11 @@ template void test_reference(const MatrixType& m) { enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; typename MatrixType::Index rows = m.rows(), cols=m.cols(); + typedef Eigen::Matrix MatrixX; + typedef Eigen::Matrix MatrixXT; // Dynamic reference: - typedef Eigen::Ref > Ref; - typedef Eigen::Ref > RefT; + typedef Eigen::Ref Ref; + typedef Eigen::Ref RefT; Ref r1(m); Ref r2(m.block(rows/3, cols/4, rows/2, cols/2)); @@ -195,10 +197,30 @@ template void test_reference(const MatrixType& m) { VERIFY_RAISES_ASSERT(RefT r5(m)); VERIFY_RAISES_ASSERT(Ref r6(m.transpose())); VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m)); + + // Copy constructors shall also never malloc + Ref r8 = r1; + RefT r9 = r3; + + // Initializing from a compatible Ref shall also never malloc + Eigen::Ref > r10=r8, r11=m; + + // Initializing from an incompatible Ref will malloc: + typedef Eigen::Ref RefAligned; + VERIFY_RAISES_ASSERT(RefAligned r12=r10); + VERIFY_RAISES_ASSERT(Ref r13=r10); // r10 has more dynamic strides + } void test_nomalloc() { + // create some dynamic objects + Eigen::MatrixXd M1 = MatrixXd::Random(3,3); + Ref R1 = 2.0*M1; // Ref requires temporary + + // from here on prohibit malloc: + Eigen::internal::set_is_malloc_allowed(false); + // check that our operator new is indeed called: VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3,3))); CALL_SUBTEST_1(nomalloc(Matrix()) ); @@ -207,6 +229,10 @@ void test_nomalloc() // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms) CALL_SUBTEST_4(ctms_decompositions()); + CALL_SUBTEST_5(test_zerosized()); + CALL_SUBTEST_6(test_reference(Matrix())); + CALL_SUBTEST_7(test_reference(R1)); + CALL_SUBTEST_8(Ref R2 = M1.topRows<2>(); test_reference(R2)); } -- cgit v1.2.3 From 81517eebc1c371cedc057130af7513ddd72de35a Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 30 Sep 2014 16:42:04 +0200 Subject: Missing explicit --- Eigen/src/Core/CoreEvaluators.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 50caf4bab..2980d7a40 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -231,7 +231,7 @@ struct evaluator > evaluator() {} - evaluator(const XprType& m) + explicit evaluator(const XprType& m) : evaluator >(m) { } }; -- cgit v1.2.3 From 6d26deb894fa62a429b717efd4d4b3aa31aba88a Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 30 Sep 2014 16:43:19 +0200 Subject: Missing outerStride in AlignedVector3 resulted in infinite recursion --- unsupported/Eigen/AlignedVector3 | 1 + 1 file changed, 1 insertion(+) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index 35493e87b..1fce00525 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -61,6 +61,7 @@ template class AlignedVector3 Scalar* data() { return m_coeffs.data(); } const Scalar* data() const { return m_coeffs.data(); } Index innerStride() const { return 1; } + Index outerStride() const { return m_coeffs.outerStride(); } inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); } -- cgit v1.2.3 From 01875049125a8da1da73b3ea0ad9319d6d80f4c2 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 30 Sep 2014 16:43:52 +0200 Subject: Avoid `unneeded-internal-declaration' warning --- test/linearstructure.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp index 87dfa1b6b..8e3cc9a86 100644 --- a/test/linearstructure.cpp +++ b/test/linearstructure.cpp @@ -92,6 +92,8 @@ template void real_complex(DenseIndex rows = MatrixType::Ro void test_linearstructure() { + g_called = true; + VERIFY(g_called); // avoid `unneeded-internal-declaration` warning. for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( linearStructure(Matrix()) ); CALL_SUBTEST_2( linearStructure(Matrix2f()) ); -- cgit v1.2.3 From 5180bb5e470c8b9cf9395270fca0f068c001ba44 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 30 Sep 2014 16:59:28 +0200 Subject: Add missing default ctor in Rotation2D --- Eigen/src/Geometry/Rotation2D.h | 7 +++++-- test/geo_transformations.cpp | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Geometry/Rotation2D.h b/Eigen/src/Geometry/Rotation2D.h index c82762acd..776c36144 100644 --- a/Eigen/src/Geometry/Rotation2D.h +++ b/Eigen/src/Geometry/Rotation2D.h @@ -60,6 +60,9 @@ public: /** Construct a 2D counter clock wise rotation from the angle \a a in radian. */ explicit inline Rotation2D(const Scalar& a) : m_angle(a) {} + + /** Default constructor wihtout initialization. The represented rotation is undefined. */ + Rotation2D() {} /** \returns the rotation angle */ inline Scalar angle() const { return m_angle; } @@ -81,10 +84,10 @@ public: /** Applies the rotation to a 2D vector */ Vector2 operator* (const Vector2& vec) const { return toRotationMatrix() * vec; } - + template Rotation2D& fromRotationMatrix(const MatrixBase& m); - Matrix2 toRotationMatrix(void) const; + Matrix2 toRotationMatrix() const; /** \returns the spherical interpolation between \c *this and \a other using * parameter \a t. It is in fact equivalent to a linear interpolation. diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index 7d9080333..1768d7b8a 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -397,6 +397,15 @@ template void transformations() t20 = Translation2(v20) * (Rotation2D(s0) * Eigen::Scaling(s0)); t21 = Translation2(v20) * Rotation2D(s0) * Eigen::Scaling(s0); VERIFY_IS_APPROX(t20,t21); + + // check basic features + { + Rotation2D r1; // default ctor + r1 = Rotation2D(s0); // copy assignment + VERIFY_IS_APPROX(r1.angle(),s0); + Rotation2D r2(r1); // copy ctor + VERIFY_IS_APPROX(r2.angle(),s0); + } } template void transform_alignment() -- cgit v1.2.3 From 9d3c69952bb99180c42b24911c1b10cad9e6fa00 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Wed, 1 Oct 2014 09:43:56 +0000 Subject: fixed to make big-endian VSX work as well --- Eigen/src/Core/arch/AltiVec/Complex.h | 2 ++ Eigen/src/Core/arch/AltiVec/PacketMath.h | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/arch/AltiVec/Complex.h b/Eigen/src/Core/arch/AltiVec/Complex.h index 30e2088ef..f9b93a42b 100644 --- a/Eigen/src/Core/arch/AltiVec/Complex.h +++ b/Eigen/src/Core/arch/AltiVec/Complex.h @@ -16,6 +16,8 @@ namespace internal { static Packet4ui p4ui_CONJ_XOR = vec_mergeh((Packet4ui)p4i_ZERO, (Packet4ui)p4f_ZERO_);//{ 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; #ifdef _BIG_ENDIAN +static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; +static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_ZERO_, 8);//{ 0x8000000000000000, 0x0000000000000000 }; #else static Packet2ul p2ul_CONJ_XOR1 = (Packet2ul) vec_sld((Packet4ui) p2l_ZERO, (Packet4ui) p2d_ZERO_, 8);//{ 0x8000000000000000, 0x0000000000000000 }; static Packet2ul p2ul_CONJ_XOR2 = (Packet2ul) vec_sld((Packet4ui) p2d_ZERO_, (Packet4ui) p2l_ZERO, 8);//{ 0x8000000000000000, 0x0000000000000000 }; diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 1b86e1227..fa02f57a1 100755 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -78,18 +78,24 @@ static Packet4i p4i_COUNTDOWN = { 0, 1, 2, 3 }; static Packet16uc p16uc_REVERSE32 = { 12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3 }; static Packet16uc p16uc_DUPLICATE32_HI = { 0,1,2,3, 0,1,2,3, 4,5,6,7, 4,5,6,7 }; +// Mask alignment +#ifdef __PPC64__ +#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 +#else +#define _EIGEN_MASK_ALIGNMENT 0xfffffff0 +#endif + +#define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) + // Handle endianness properly while loading constants // Define global static constants: #ifdef _BIG_ENDIAN static Packet16uc p16uc_FORWARD = vec_lvsl(0, (float*)0); +static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; static Packet16uc p16uc_PSET32_WEVEN = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 }; static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8); //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16}; #else -// Mask alignment -#define _EIGEN_MASK_ALIGNMENT 0xfffffffffffffff0 -#define _EIGEN_ALIGNED_PTR(x) ((ptrdiff_t)(x) & _EIGEN_MASK_ALIGNMENT) - static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 }; static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 }; @@ -716,7 +722,12 @@ static Packet2l p2l_ZERO = (Packet2l) p4i_ZERO; static Packet2d p2d_ONE = { 1.0, 1.0 }; static Packet2d p2d_ZERO = (Packet2d) p4f_ZERO; static Packet2d p2d_ZERO_ = { -0.0, -0.0 }; + +#ifdef _BIG_ENDIAN +static Packet2d p2d_COUNTDOWN = (Packet2d) vec_sld((Packet16uc) p2d_ZERO, (Packet16uc) p2d_ONE, 8); +#else static Packet2d p2d_COUNTDOWN = (Packet2d) vec_sld((Packet16uc) p2d_ONE, (Packet16uc) p2d_ZERO, 8); +#endif static EIGEN_STRONG_INLINE Packet2d vec_splat_dbl(Packet2d& a, int index) { @@ -862,11 +873,14 @@ template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) { Packet2d v[2], sum; - v[0] = vec_add(vecs[0], (Packet2d) vec_sld((Packet4ui) vecs[0], (Packet4ui) vecs[0], 8)); v[1] = vec_add(vecs[1], (Packet2d) vec_sld((Packet4ui) vecs[1], (Packet4ui) vecs[1], 8)); - + +#ifdef _BIG_ENDIAN + sum = (Packet2d) vec_sld((Packet4ui) v[0], (Packet4ui) v[1], 8); +#else sum = (Packet2d) vec_sld((Packet4ui) v[1], (Packet4ui) v[0], 8); +#endif return sum; } -- cgit v1.2.3 From 1fa6fe2abde9753807dc3f85bbf5e6eac3f31313 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Wed, 1 Oct 2014 14:33:55 +0200 Subject: template keyword not allowed before non-template function call --- test/eigensolver_selfadjoint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 41b598795..8ff48462e 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -111,7 +111,7 @@ template void selfadjointeigensolver(const MatrixType& m) // test Tridiagonalization's methods Tridiagonalization tridiag(symmC); - VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().template diagonal()); + VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().diagonal()); VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>()); MatrixType T = tridiag.matrixT(); if(rows>1 && cols>1) { -- cgit v1.2.3 From 7a1763995396e6119092ce5fc4ca2d536b6acb73 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Oct 2014 11:41:50 +0200 Subject: Extend unit tests to check uncompressed sparse inputs in sparse solvers --- test/sparse_solver.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/sparse_solver.h b/test/sparse_solver.h index d84aff070..8c8d7f939 100644 --- a/test/sparse_solver.h +++ b/test/sparse_solver.h @@ -67,6 +67,15 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, VERIFY(oldb.isApprox(db) && "sparse solver testing: the rhs should not be modified!"); VERIFY(x.isApprox(refX,test_precision())); } + + // test uncompressed inputs + { + Mat A2 = A; + A2.reserve((ArrayXf::Random(A.outerSize())+2).template cast().eval()); + solver.compute(A2); + Rhs x = solver.solve(b); + VERIFY(x.isApprox(refX,test_precision())); + } } template -- cgit v1.2.3 From fb53ff1edaa96bc1c6090e5ab4982751dbdfc910 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Oct 2014 11:42:31 +0200 Subject: Fix SparseLU regarding uncompressed inputs and avoid manual new/delete calls. --- Eigen/src/SparseLU/SparseLU.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index 1789830b9..b02796293 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -364,30 +364,32 @@ void SparseLU::analyzePattern(const MatrixType& mat) //TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat. + // Firstly, copy the whole input matrix. + m_mat = mat; + + // Compute fill-in ordering OrderingType ord; - ord(mat,m_perm_c); + ord(m_mat,m_perm_c); // Apply the permutation to the column of the input matrix - //First copy the whole input matrix. - m_mat = mat; - if (m_perm_c.size()) { + if (m_perm_c.size()) + { m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers. FIXME : This vector is filled but not subsequently used. - //Then, permute only the column pointers - const Index * outerIndexPtr; - if (mat.isCompressed()) outerIndexPtr = mat.outerIndexPtr(); - else - { - Index *outerIndexPtr_t = new Index[mat.cols()+1]; - for(Index i = 0; i <= mat.cols(); i++) outerIndexPtr_t[i] = m_mat.outerIndexPtr()[i]; - outerIndexPtr = outerIndexPtr_t; - } + // Then, permute only the column pointers + ei_declare_aligned_stack_constructed_variable(Index,outerIndexPtr,mat.cols()+1,mat.isCompressed()?const_cast(mat.outerIndexPtr()):0); + + // If the input matrix 'mat' is uncompressed, then the outer-indices do not match the ones of m_mat, and a copy is thus needed. + if(!mat.isCompressed()) + IndexVector::Map(outerIndexPtr, mat.cols()+1) = IndexVector::Map(m_mat.outerIndexPtr(),mat.cols()+1); + + // Apply the permutation and compute the nnz per column. for (Index i = 0; i < mat.cols(); i++) { m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i]; m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = outerIndexPtr[i+1] - outerIndexPtr[i]; } - if(!mat.isCompressed()) delete[] outerIndexPtr; } + // Compute the column elimination tree of the permuted matrix IndexVector firstRowElt; internal::coletree(m_mat, m_etree,firstRowElt); -- cgit v1.2.3 From 893bfcf95fd7aaa49747f029bac708a02a1526cd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Oct 2014 11:54:30 +0200 Subject: bug #887: use ei_declare_aligned_stack_constructed_variable instead of manual new[]/delete[] pairs in AMD and Paralellizer --- Eigen/src/Core/products/Parallelizer.h | 4 +--- Eigen/src/OrderingMethods/Amd.h | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h index 4079063eb..126cfbbff 100644 --- a/Eigen/src/Core/products/Parallelizer.h +++ b/Eigen/src/Core/products/Parallelizer.h @@ -129,7 +129,7 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos Index blockRows = (rows / threads); blockRows = (blockRows/Functor::Traits::mr)*Functor::Traits::mr; - GemmParallelInfo* info = new GemmParallelInfo[threads]; + ei_declare_aligned_stack_constructed_variable(GemmParallelInfo,info,threads,0); #pragma omp parallel num_threads(threads) { @@ -146,8 +146,6 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos if(transpose) func(c0, actualBlockCols, 0, rows, info); else func(0, rows, c0, actualBlockCols, info); } - - delete[] info; #endif } diff --git a/Eigen/src/OrderingMethods/Amd.h b/Eigen/src/OrderingMethods/Amd.h index 41b4fd7e3..ce7c0bbf3 100644 --- a/Eigen/src/OrderingMethods/Amd.h +++ b/Eigen/src/OrderingMethods/Amd.h @@ -106,7 +106,8 @@ void minimum_degree_ordering(SparseMatrix& C, Permutation t = cnz + cnz/5 + 2*n; /* add elbow room to C */ C.resizeNonZeros(t); - Index* W = new Index[8*(n+1)]; /* get workspace */ + // get workspace + ei_declare_aligned_stack_constructed_variable(Index,W,8*(n+1),0); Index* len = W; Index* nv = W + (n+1); Index* next = W + 2*(n+1); @@ -424,8 +425,6 @@ void minimum_degree_ordering(SparseMatrix& C, Permutation } perm.indices().conservativeResize(n); - - delete[] W; } } // namespace internal -- cgit v1.2.3 From d44d432baa142fdbe17f9d3abeab2c7629e199b8 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Oct 2014 16:11:26 +0200 Subject: Re-enable products with triangular views of sparse matrices: we simply have to treat them as a sparse matrix. --- Eigen/src/Core/TriangularMatrix.h | 8 +++++--- .../SparseCore/ConservativeSparseSparseProduct.h | 2 ++ Eigen/src/SparseCore/SparseDenseProduct.h | 12 +++++++++++- Eigen/src/SparseCore/SparseProduct.h | 13 +++++++++++++ test/sparse_product.cpp | 22 ++++++++++++++++++---- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 36bbd46e1..263d54485 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -247,7 +247,7 @@ template class TriangularView inline const AdjointReturnType adjoint() const { return AdjointReturnType(m_matrix.adjoint()); } - typedef TriangularView,TransposeMode> TransposeReturnType; + typedef TriangularView TransposeReturnType; /** \sa MatrixBase::transpose() */ EIGEN_DEVICE_FUNC inline TransposeReturnType transpose() @@ -255,11 +255,13 @@ template class TriangularView EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return TransposeReturnType(m_matrix.const_cast_derived().transpose()); } + + typedef TriangularView ConstTransposeReturnType; /** \sa MatrixBase::transpose() const */ EIGEN_DEVICE_FUNC - inline const TransposeReturnType transpose() const + inline const ConstTransposeReturnType transpose() const { - return TransposeReturnType(m_matrix.transpose()); + return ConstTransposeReturnType(m_matrix.transpose()); } template diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 19d9eaa42..a30522ff7 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -141,6 +141,8 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrixAux; typedef typename sparse_eval::type ColMajorMatrix; + // If the result is tall and thin (in the extreme case a column vector) + // then it is faster to sort the coefficients inplace instead of transposing twice. // FIXME, the following heuristic is probably not very good. if(lhs.rows()>=rhs.cols()) { diff --git a/Eigen/src/SparseCore/SparseDenseProduct.h b/Eigen/src/SparseCore/SparseDenseProduct.h index ed3cb1990..5aea11425 100644 --- a/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/Eigen/src/SparseCore/SparseDenseProduct.h @@ -146,6 +146,11 @@ struct generic_product_impl } }; +template +struct generic_product_impl + : generic_product_impl +{}; + template struct generic_product_impl { @@ -158,12 +163,17 @@ struct generic_product_impl RhsNested rhsNested(rhs); dst.setZero(); - // transpoe everything + // transpose everything Transpose dstT(dst); internal::sparse_time_dense_product(rhsNested.transpose(), lhsNested.transpose(), dstT, typename Dest::Scalar(1)); } }; +template +struct generic_product_impl + : generic_product_impl +{}; + template struct sparse_dense_outer_product_evaluator { diff --git a/Eigen/src/SparseCore/SparseProduct.h b/Eigen/src/SparseCore/SparseProduct.h index ae707376a..c62386ed1 100644 --- a/Eigen/src/SparseCore/SparseProduct.h +++ b/Eigen/src/SparseCore/SparseProduct.h @@ -33,6 +33,7 @@ SparseMatrixBase::operator*(const SparseMatrixBase &other namespace internal { +// sparse * sparse template struct generic_product_impl { @@ -48,6 +49,18 @@ struct generic_product_impl } }; +// sparse * sparse-triangular +template +struct generic_product_impl + : public generic_product_impl +{}; + +// sparse-triangular * sparse +template +struct generic_product_impl + : public generic_product_impl +{}; + template struct evaluator > > : public evaluator::PlainObject>::type diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index fa9be5440..366e27274 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -194,7 +194,7 @@ template void sparse_product() VERIFY_IS_APPROX(d3=d1*m2.transpose(), refM3=d1*refM2.transpose()); } - // test self adjoint products + // test self-adjoint and traingular-view products { DenseMatrix b = DenseMatrix::Random(rows, rows); DenseMatrix x = DenseMatrix::Random(rows, rows); @@ -202,9 +202,12 @@ template void sparse_product() DenseMatrix refUp = DenseMatrix::Zero(rows, rows); DenseMatrix refLo = DenseMatrix::Zero(rows, rows); DenseMatrix refS = DenseMatrix::Zero(rows, rows); + DenseMatrix refA = DenseMatrix::Zero(rows, rows); SparseMatrixType mUp(rows, rows); SparseMatrixType mLo(rows, rows); SparseMatrixType mS(rows, rows); + SparseMatrixType mA(rows, rows); + initSparse(density, refA, mA); do { initSparse(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular); } while (refUp.isZero()); @@ -224,19 +227,30 @@ template void sparse_product() VERIFY_IS_APPROX(mS, refS); VERIFY_IS_APPROX(x=mS*b, refX=refS*b); + // sparse selfadjointView with dense matrices VERIFY_IS_APPROX(x=mUp.template selfadjointView()*b, refX=refS*b); VERIFY_IS_APPROX(x=mLo.template selfadjointView()*b, refX=refS*b); VERIFY_IS_APPROX(x=mS.template selfadjointView()*b, refX=refS*b); - // sparse selfadjointView * sparse + // sparse selfadjointView with sparse matrices SparseMatrixType mSres(rows,rows); VERIFY_IS_APPROX(mSres = mLo.template selfadjointView()*mS, refX = refLo.template selfadjointView()*refS); - // sparse * sparse selfadjointview VERIFY_IS_APPROX(mSres = mS * mLo.template selfadjointView(), refX = refS * refLo.template selfadjointView()); + + // sparse triangularView with dense matrices + VERIFY_IS_APPROX(x=mA.template triangularView()*b, refX=refA.template triangularView()*b); + VERIFY_IS_APPROX(x=mA.template triangularView()*b, refX=refA.template triangularView()*b); + VERIFY_IS_APPROX(x=b*mA.template triangularView(), refX=b*refA.template triangularView()); + VERIFY_IS_APPROX(x=b*mA.template triangularView(), refX=b*refA.template triangularView()); + + // sparse triangularView with sparse matrices + VERIFY_IS_APPROX(mSres = mA.template triangularView()*mS, refX = refA.template triangularView()*refS); + VERIFY_IS_APPROX(mSres = mS * mA.template triangularView(), refX = refS * refA.template triangularView()); + VERIFY_IS_APPROX(mSres = mA.template triangularView()*mS, refX = refA.template triangularView()*refS); + VERIFY_IS_APPROX(mSres = mS * mA.template triangularView(), refX = refS * refA.template triangularView()); } - } // New test for Bug in SparseTimeDenseProduct -- cgit v1.2.3 From dbdd8b0883ebd1ebafeb21640d6e4bead1999565 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 6 Oct 2014 19:35:57 +0200 Subject: D&C SVD: add scaling to avoid overflow, fix handling of fixed size matrices --- test/svd_common.h | 6 +++--- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 35 ++++++++++++++++++++--------------- unsupported/test/bdcsvd.cpp | 10 +++++----- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/test/svd_common.h b/test/svd_common.h index 4631939e5..b880efce5 100644 --- a/test/svd_common.h +++ b/test/svd_common.h @@ -301,7 +301,7 @@ void svd_underoverflow() 0, 5.60844e-313; SVD_DEFAULT(Matrix2d) svd; svd.compute(M,ComputeFullU|ComputeFullV); - svd_check_full(M,svd); + CALL_SUBTEST( svd_check_full(M,svd) ); // Check all 2x2 matrices made with the following coefficients: VectorXd value_set(9); @@ -312,7 +312,7 @@ void svd_underoverflow() { M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); svd.compute(M,ComputeFullU|ComputeFullV); - svd_check_full(M,svd); + CALL_SUBTEST( svd_check_full(M,svd) ); id(k)++; if(id(k)>=value_set.size()) @@ -336,7 +336,7 @@ void svd_underoverflow() SVD_DEFAULT(Matrix3d) svd3; svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely - svd_check_full(M3,svd3); + CALL_SUBTEST( svd_check_full(M3,svd3) ); } // void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index b13ee415e..5bf9b0ae2 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -236,26 +236,29 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign { allocate(matrix.rows(), matrix.cols(), computationOptions); using std::abs; - - //**** step 1 Bidiagonalization - MatrixType copy; - if (m_isTranspose) copy = matrix.adjoint(); - else copy = matrix; + //**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows + RealScalar scale = matrix.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + MatrixX copy; + if (m_isTranspose) copy = matrix.adjoint()/scale; + else copy = matrix/scale; + + //**** step 1 - Bidiagonalization internal::UpperBidiagonalization bid(copy); - //**** step 2 Divide + //**** step 2 - Divide & Conquer m_naiveU.setZero(); m_naiveV.setZero(); m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); m_computed.template bottomRows<1>().setZero(); divide(0, m_diagSize - 1, 0, 0, 0); - //**** step 3 copy + //**** step 3 - Copy singular values and vectors for (int i=0; i& BDCSVD::compute(const MatrixType& matrix, unsign break; } } -// std::cout << "m_naiveU\n" << m_naiveU << "\n\n"; -// std::cout << "m_naiveV\n" << m_naiveV << "\n\n"; +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "m_naiveU\n" << m_naiveU << "\n\n"; + std::cout << "m_naiveV\n" << m_naiveV << "\n\n"; +#endif if(m_isTranspose) copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU); else copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV); -// std::cout << "DONE\n"; + m_isInitialized = true; return *this; }// end compute @@ -569,13 +574,13 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec computeSingVecs(zhat, diag, singVals, shifts, mus, U, V); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "U^T U: " << (U.transpose() * U - MatrixType(MatrixType::Identity(U.cols(),U.cols()))).norm() << "\n"; - std::cout << "V^T V: " << (V.transpose() * V - MatrixType(MatrixType::Identity(V.cols(),V.cols()))).norm() << "\n"; + std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() << "\n"; + std::cout << "V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() << "\n"; #endif #ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert((U.transpose() * U - MatrixType(MatrixType::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); - assert((V.transpose() * V - MatrixType(MatrixType::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); + assert((U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); + assert((V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); assert(m_naiveU.allFinite()); assert(m_naiveV.allFinite()); assert(m_computed.allFinite()); diff --git a/unsupported/test/bdcsvd.cpp b/unsupported/test/bdcsvd.cpp index 4ad991522..95cdb6a2e 100644 --- a/unsupported/test/bdcsvd.cpp +++ b/unsupported/test/bdcsvd.cpp @@ -70,13 +70,13 @@ void test_bdcsvd() CALL_SUBTEST_7(( svd_verify_assert >(MatrixXf(10,12)) )); CALL_SUBTEST_8(( svd_verify_assert >(MatrixXcd(7,5)) )); -// svd_all_trivial_2x2(bdcsvd); -// svd_all_trivial_2x2(bdcsvd); + CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); + CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); for(int i = 0; i < g_repeat; i++) { -// CALL_SUBTEST_3(( bdcsvd() )); -// CALL_SUBTEST_4(( bdcsvd() )); -// CALL_SUBTEST_5(( bdcsvd >() )); + CALL_SUBTEST_3(( bdcsvd() )); + CALL_SUBTEST_4(( bdcsvd() )); + CALL_SUBTEST_5(( bdcsvd >() )); int r = internal::random(1, EIGEN_TEST_MAX_SIZE/2), c = internal::random(1, EIGEN_TEST_MAX_SIZE/2); -- cgit v1.2.3 From 503c176d8edc6e2877b2ade7b3ed3a5ae17cf4e7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 7 Oct 2014 09:53:27 +0200 Subject: Fix missing outer() member in DynamicSparseMatrix --- unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h index e4dc1c1de..976f9f270 100644 --- a/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h +++ b/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h @@ -331,6 +331,7 @@ class DynamicSparseMatrix::InnerIterator : public Sparse inline Index row() const { return IsRowMajor ? m_outer : Base::index(); } inline Index col() const { return IsRowMajor ? Base::index() : m_outer; } + inline Index outer() const { return m_outer; } protected: const Index m_outer; @@ -347,6 +348,7 @@ class DynamicSparseMatrix::ReverseInnerIterator : public inline Index row() const { return IsRowMajor ? m_outer : Base::index(); } inline Index col() const { return IsRowMajor ? Base::index() : m_outer; } + inline Index outer() const { return m_outer; } protected: const Index m_outer; -- cgit v1.2.3 From 118b1113d9a4fa1a263597cdd699e237e5f2b4ac Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 7 Oct 2014 09:53:39 +0200 Subject: Workaround MSVC issue. --- unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h index b459360df..446fcac16 100644 --- a/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +++ b/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h @@ -165,8 +165,8 @@ void KroneckerProductSparse::evalTo(Dest& dst) const const Rhs1 rhs1(m_B); // 2 - construct respective iterators - typedef InnerIterator LhsInnerIterator; - typedef InnerIterator RhsInnerIterator; + typedef Eigen::InnerIterator LhsInnerIterator; + typedef Eigen::InnerIterator RhsInnerIterator; // compute number of non-zeros per innervectors of dst { -- cgit v1.2.3 From 57413492948d4c9dd6572f5bde6720b80122054a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 7 Oct 2014 18:29:28 +0200 Subject: bug #882: fix various const-correctness issues with *View classes. --- Eigen/src/CholmodSupport/CholmodSupport.h | 2 +- Eigen/src/Core/CwiseUnaryView.h | 5 +++-- Eigen/src/Core/SelfAdjointView.h | 4 +++- Eigen/src/Core/TriangularMatrix.h | 18 ++++++++---------- Eigen/src/SparseCholesky/SimplicialCholesky.h | 8 ++++---- Eigen/src/SparseCore/SparseMatrixBase.h | 4 ++-- Eigen/src/SparseCore/SparseSelfAdjointView.h | 4 ++-- Eigen/src/SparseCore/SparseTriangularView.h | 4 ++-- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Eigen/src/CholmodSupport/CholmodSupport.h b/Eigen/src/CholmodSupport/CholmodSupport.h index 0c3b86dd2..3eadb83a0 100644 --- a/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/Eigen/src/CholmodSupport/CholmodSupport.h @@ -105,7 +105,7 @@ const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& /** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. * The data are not copied but shared. */ template -cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) +cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) { cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 61fd8ee35..6384dfdc3 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -37,7 +37,8 @@ struct traits > typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { - Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | LvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values @@ -63,7 +64,7 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::type NestedExpression; - explicit inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + explicit inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index f5fbd7215..1c44d9c9a 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -38,7 +38,8 @@ struct traits > : traits typedef typename MatrixType::PlainObject FullMatrixType; enum { Mode = UpLo | SelfAdjoint, - Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits) + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = MatrixTypeNestedCleaned::Flags & (HereditaryBits|FlagsLvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit)) // FIXME these flags should be preserved }; }; @@ -95,6 +96,7 @@ template class SelfAdjointView EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { + EIGEN_STATIC_ASSERT_LVALUE(SelfAdjointView); Base::check_coordinates_internal(row, col); return m_matrix.const_cast_derived().coeffRef(row, col); } diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 263d54485..055ed7514 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -173,7 +173,8 @@ struct traits > : traits typedef MatrixType ExpressionType; enum { Mode = _Mode, - Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | LvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = (MatrixTypeNestedCleaned::Flags & (HereditaryBits | FlagsLvalueBit) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) }; }; } @@ -213,7 +214,7 @@ template class TriangularView // FIXME This, combined with const_cast_derived in transpose() leads to a const-correctness loophole EIGEN_DEVICE_FUNC - explicit inline TriangularView(const MatrixType& matrix) : m_matrix(matrix) + explicit inline TriangularView(MatrixType& matrix) : m_matrix(matrix) {} using Base::operator=; @@ -229,14 +230,9 @@ template class TriangularView const NestedExpression& nestedExpression() const { return m_matrix; } EIGEN_DEVICE_FUNC NestedExpression& nestedExpression() { return *const_cast(&m_matrix); } - - typedef TriangularView ConjugateReturnType; - /** \sa MatrixBase::conjugate() */ - EIGEN_DEVICE_FUNC - inline ConjugateReturnType conjugate() - { return ConjugateReturnType(m_matrix.conjugate()); } + /** \sa MatrixBase::conjugate() const */ - + typedef TriangularView ConjugateReturnType; EIGEN_DEVICE_FUNC inline const ConjugateReturnType conjugate() const { return ConjugateReturnType(m_matrix.conjugate()); } @@ -253,7 +249,8 @@ template class TriangularView inline TransposeReturnType transpose() { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return TransposeReturnType(m_matrix.const_cast_derived().transpose()); + typename MatrixType::TransposeReturnType tmp(m_matrix.const_cast_derived()); + return TransposeReturnType(tmp); } typedef TriangularView ConstTransposeReturnType; @@ -392,6 +389,7 @@ template class TriangularViewImpl<_Mat EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { + EIGEN_STATIC_ASSERT_LVALUE(TriangularViewType); Base::check_coordinates_internal(row, col); return derived().nestedExpression().const_cast_derived().coeffRef(row, col); } diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index 0e8fa6628..918a34e13 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -237,8 +237,8 @@ template struct traits CholMatrixType; - typedef TriangularView MatrixL; - typedef TriangularView MatrixU; + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; @@ -251,8 +251,8 @@ template struct traits CholMatrixType; - typedef TriangularView MatrixL; - typedef TriangularView MatrixU; + typedef TriangularView MatrixL; + typedef TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; diff --git a/Eigen/src/SparseCore/SparseMatrixBase.h b/Eigen/src/SparseCore/SparseMatrixBase.h index f96042f27..04baabe4f 100644 --- a/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/Eigen/src/SparseCore/SparseMatrixBase.h @@ -297,9 +297,9 @@ template class SparseMatrixBase : public EigenBase Derived& operator*=(const SparseMatrixBase& other); template - inline const TriangularView triangularView() const; + inline const TriangularView triangularView() const; - template inline const SparseSelfAdjointView selfadjointView() const; + template inline const SparseSelfAdjointView selfadjointView() const; template inline SparseSelfAdjointView selfadjointView(); template Scalar dot(const MatrixBase& other) const; diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 247d4e6d3..5da7d2bef 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h @@ -170,9 +170,9 @@ template class SparseSelfAdjointView template template -const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const +const SparseSelfAdjointView SparseMatrixBase::selfadjointView() const { - return SparseSelfAdjointView(derived()); + return SparseSelfAdjointView(derived()); } template diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index e200bc815..1f5e53155 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -266,10 +266,10 @@ protected: template template -inline const TriangularView +inline const TriangularView SparseMatrixBase::triangularView() const { - return TriangularView(derived()); + return TriangularView(derived()); } } // end namespace Eigen -- cgit v1.2.3 From 4b886e6b39e4fd82365830b1dfa1bdc75a36f302 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 8 Oct 2014 07:48:30 +0200 Subject: bug #889: fix protected typedef --- Eigen/src/IterativeLinearSolvers/SolveWithGuess.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h index 6cd4872dc..251c6fa1a 100644 --- a/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +++ b/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h @@ -42,6 +42,7 @@ class SolveWithGuess : public internal::generic_xpr_base::Scalar Scalar; typedef typename internal::traits::PlainObject PlainObject; typedef typename internal::generic_xpr_base, MatrixXpr, typename internal::traits::StorageKind>::type Base; @@ -61,8 +62,6 @@ protected: const RhsType &m_rhs; const GuessType &m_guess; - typedef typename internal::traits::Scalar Scalar; - private: Scalar coeff(Index row, Index col) const; Scalar coeff(Index i) const; -- cgit v1.2.3 From ccd70ba123562b77f132c562f76d1286af7d5fe3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:29:01 +0200 Subject: Various numerical fixes in D&C SVD: I cannot make it fail with double, but still need to tune for single precision, and carefully test with duplicated singular values --- test/svd_common.h | 6 +-- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 73 ++++++++++++++++----------- unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt | 34 ++++--------- unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt | 15 +----- unsupported/test/bdcsvd.cpp | 3 +- 5 files changed, 58 insertions(+), 73 deletions(-) diff --git a/test/svd_common.h b/test/svd_common.h index b880efce5..e902d2320 100644 --- a/test/svd_common.h +++ b/test/svd_common.h @@ -146,6 +146,7 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions) m2.setRandom(); } while(SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision()).rank()!=rank && (++guard)<10); VERIFY(guard<10); + RhsType2 rhs2 = RhsType2::Random(rank); // use QR to find a reference minimal norm solution HouseholderQR qr(m2.adjoint()); @@ -159,7 +160,7 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions) VERIFY_IS_APPROX(m2*x21, rhs2); VERIFY_IS_APPROX(m2*x22, rhs2); VERIFY_IS_APPROX(x21, x22); - + // Now check with a rank deficient matrix typedef Matrix MatrixType3; typedef Matrix RhsType3; @@ -172,7 +173,6 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions) VERIFY_IS_APPROX(m3*x3, rhs3); VERIFY_IS_APPROX(m3*x21, rhs3); VERIFY_IS_APPROX(m2*x3, rhs2); - VERIFY_IS_APPROX(x21, x3); } @@ -209,7 +209,7 @@ void svd_test_all_computation_options(const MatrixType& m, bool full_only) CALL_SUBTEST(( svd_least_square(m, ComputeFullU | ComputeThinV) )); CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeFullV) )); CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeThinV) )); - + CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeThinV) )); CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeFullV) )); CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeThinV) )); diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index 5bf9b0ae2..d5e8140a4 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -272,8 +272,8 @@ BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsign } } #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "m_naiveU\n" << m_naiveU << "\n\n"; - std::cout << "m_naiveV\n" << m_naiveV << "\n\n"; +// std::cout << "m_naiveU\n" << m_naiveU << "\n\n"; +// std::cout << "m_naiveV\n" << m_naiveV << "\n\n"; #endif if(m_isTranspose) copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU); else copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV); @@ -612,22 +612,23 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia Index n = col0.size(); Index actual_n = n; while(actual_n>1 && col0(actual_n-1)==0) --actual_n; - Index m = 0; - Array perm(actual_n); - { - for(Index k=0;k perm(actual_n); +// { +// for(Index k=0;k::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // otherwise, use secular equation to find singular value RealScalar left = diag(k); - RealScalar right = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm()); + RealScalar right; // was: = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm()); + if(k==actual_n-1) + right = (diag(actual_n-1) + col0.matrix().norm()); + else + { + // Skip deflated singular values + Index l = k+1; + while(col0(l)==0) { ++l; eigen_internal_assert(l::computeSingVals(const ArrayXr& col0, const ArrayXr& dia { muPrev = (right - left) * 0.1; if (k == actual_n-1) muCur = right - left; - else muCur = (right - left) * 0.5; + else muCur = (right - left) * 0.5; } else { @@ -671,7 +681,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // rational interpolation: fit a function of the form a / mu + b through the two previous // iterates and use its zero to compute the next iterate - bool useBisection = false; + bool useBisection = fPrev*fCur>0; while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) { ++m_numIters; @@ -684,32 +694,36 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia muCur = -a / b; fCur = secularEq(muCur, col0, diag, diagShifted, shift, actual_n); - if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; + if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true; } // fall back on bisection method if rational interpolation did not work if (useBisection) { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "useBisection for k = " << k << ", actual_n = " << actual_n << "\n"; +#endif RealScalar leftShifted, rightShifted; if (shift == left) { - leftShifted = 1e-30; - if (k == 0) rightShifted = right - left; - else rightShifted = (right - left) * 0.6; // theoretically we can take 0.5, but let's be safe + leftShifted = RealScalar(1)/NumTraits::highest(); + // I don't understand why the case k==0 would be special there: + // if (k == 0) rightShifted = right - left; else + rightShifted = (right - left) * 0.6; // theoretically we can take 0.5, but let's be safe } else { leftShifted = -(right - left) * 0.6; - rightShifted = -1e-30; + rightShifted = -RealScalar(1)/NumTraits::highest(); } RealScalar fLeft = secularEq(leftShifted, col0, diag, diagShifted, shift, actual_n); RealScalar fRight = secularEq(rightShifted, col0, diag, diagShifted, shift, actual_n); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - if(fLeft * fRight>0) - std::cout << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; + if(fLeft * fRight>=0) + std::cout << k << " : " << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; #endif eigen_internal_assert(fLeft * fRight < 0); @@ -738,8 +752,9 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // perturb singular value slightly if it equals diagonal entry to avoid division by zero later // (deflation is supposed to avoid this from happening) - if (singVals[k] == left) singVals[k] *= 1 + NumTraits::epsilon(); - if (singVals[k] == right) singVals[k] *= 1 - NumTraits::epsilon(); + // - this does no seem to be necessary anymore - +// if (singVals[k] == left) singVals[k] *= 1 + NumTraits::epsilon(); +// if (singVals[k] == right) singVals[k] *= 1 - NumTraits::epsilon(); } } @@ -989,7 +1004,7 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index #endif deflation43(firstCol, shift, i, length); } - + #ifdef EIGEN_BDCSVD_SANITY_CHECKS assert(m_naiveU.allFinite()); assert(m_naiveV.allFinite()); @@ -1027,7 +1042,7 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index realInd[pos] = pos; } - for(Index i = 1; i < length - 1; i++) + for(Index i = 1; i < length; i++) { const Index pi = permutation[length - i]; const Index J = realCol[pi]; @@ -1056,7 +1071,7 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index #ifdef EIGEN_BDCSVD_SANITY_CHECKS for(int k=2;k, ...) +- To solve the secular equation using FMM: +http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf -(optional optimization) - do all the allocations in the allocate part - - support static matrices - - return a error at compilation time when using integer matrices (int, long, std::complex, ...) - -to finish the algorithm : - -implement the last part of the algorithm as described on the reference paper. - You may find more information on that part on this paper - - -to replace the call to JacobiSVD at the end of the divide algorithm, just after the call to - deflation. - -(suggested step by step resolution) - 0) comment the call to Jacobi in the last part of the divide method and everything right after - until the end of the method. What is commented can be a guideline to steps 3) 4) and 6) - 1) solve the secular equation (Characteristic equation) on the values that are not null (zi!=0 and di!=0), after the deflation - wich should be uncommented in the divide method - 2) remember the values of the singular values that are already computed (zi=0) - 3) assign the singular values found in m_computed at the right places (with the ones found in step 2) ) - in decreasing order - 4) set the firstcol to zero (except the first element) in m_computed - 5) compute all the singular vectors when CompV is set to true and only the left vectors when - CompV is set to false - 6) multiply naiveU and naiveV to the right by the matrices found, only naiveU when CompV is set to - false, /!\ if CompU is false NaiveU has only 2 rows - 7) delete everything commented in step 0) diff --git a/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt b/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt index 8563ddab8..29ab9cd40 100644 --- a/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt +++ b/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt @@ -3,19 +3,6 @@ This unsupported package is about a divide and conquer algorithm to compute SVD. The implementation follows as closely as possible the following reference paper : http://www.cs.yale.edu/publications/techreports/tr933.pdf -The code documentation uses the same names for variables as the reference paper. The code, deflation included, is -working but there are a few things that could be optimised as explained in the TODOBdsvd. - -In the code comments were put at the line where would be the third step of the algorithm so one could simply add the call -of a function doing the last part of the algorithm and that would not require any knowledge of the part we implemented. - -In the TODOBdcsvd we explain what is the main difficulty of the last part and suggest a reference paper to help solve it. - -The implemented has trouble with fixed size matrices. - -In the actual implementation, it returns matrices of zero when ask to do a svd on an int matrix. - - -Paper for the third part: +To solve the secular equation using FMM: http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf diff --git a/unsupported/test/bdcsvd.cpp b/unsupported/test/bdcsvd.cpp index 95cdb6a2e..9e5c29a8c 100644 --- a/unsupported/test/bdcsvd.cpp +++ b/unsupported/test/bdcsvd.cpp @@ -21,8 +21,7 @@ #define SVD_DEFAULT(M) BDCSVD -// #define SVD_FOR_MIN_NORM(M) BDCSVD -#define SVD_FOR_MIN_NORM(M) JacobiSVD +#define SVD_FOR_MIN_NORM(M) BDCSVD #include "../../test/svd_common.h" // Check all variants of JacobiSVD -- cgit v1.2.3 From a48b82eece435e24418beb95f16ab32be7970183 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:34:05 +0200 Subject: Add a scoped_array helper class to handle locally allocated/used arrays --- Eigen/src/Core/util/Memory.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index af46c449c..6ed158972 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -618,7 +618,7 @@ template struct smart_memmove_helper { // This helper class construct the allocated memory, and takes care of destructing and freeing the handled data // at destruction time. In practice this helper class is mainly useful to avoid memory leak in case of exceptions. -template class aligned_stack_memory_handler +template class aligned_stack_memory_handler : noncopyable { public: /* Creates a stack_memory_handler responsible for the buffer \a ptr of size \a size. @@ -646,6 +646,30 @@ template class aligned_stack_memory_handler bool m_deallocate; }; +template class scoped_array : noncopyable +{ + T* m_ptr; +public: + explicit scoped_array(std::ptrdiff_t size) + { + m_ptr = new T[size]; + } + ~scoped_array() + { + delete[] m_ptr; + } + T& operator[](std::ptrdiff_t i) { return m_ptr[i]; } + const T& operator[](std::ptrdiff_t i) const { return m_ptr[i]; } + T* &ptr() { return m_ptr; } + const T* ptr() const { return m_ptr; } + operator const T*() const { return m_ptr; } +}; + +template void swap(scoped_array &a,scoped_array &b) +{ + std::swap(a.ptr(),b.ptr()); +} + } // end namespace internal /** \internal -- cgit v1.2.3 From 538c059aa4d02a9f1a282e8fc4b181c8eb0b4f47 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:35:05 +0200 Subject: bug #887: fix CompressedStorage::reallocate wrt memory leaks --- Eigen/src/SparseCore/CompressedStorage.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h index a93550340..4f3695773 100644 --- a/Eigen/src/SparseCore/CompressedStorage.h +++ b/Eigen/src/SparseCore/CompressedStorage.h @@ -204,17 +204,14 @@ class CompressedStorage inline void reallocate(size_t size) { - Scalar* newValues = new Scalar[size]; - Index* newIndices = new Index[size]; + eigen_internal_assert(size!=m_allocatedSize); + internal::scoped_array newValues(size); + internal::scoped_array newIndices(size); size_t copySize = (std::min)(size, m_size); - // copy - internal::smart_copy(m_values, m_values+copySize, newValues); - internal::smart_copy(m_indices, m_indices+copySize, newIndices); - // delete old stuff - delete[] m_values; - delete[] m_indices; - m_values = newValues; - m_indices = newIndices; + internal::smart_copy(m_values, m_values+copySize, newValues.ptr()); + internal::smart_copy(m_indices, m_indices+copySize, newIndices.ptr()); + std::swap(m_values,newValues.ptr()); + std::swap(m_indices,newIndices.ptr()); m_allocatedSize = size; } -- cgit v1.2.3 From 48d537f59fd3c7efd954bb99581dac83fd1c0f16 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:35:26 +0200 Subject: Fix indentation --- Eigen/src/Core/util/Memory.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 6ed158972..7b39285ea 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -578,27 +578,27 @@ template struct smart_memmove_helper; template void smart_memmove(const T* start, const T* end, T* target) { - smart_memmove_helper::RequireInitialization>::run(start, end, target); + smart_memmove_helper::RequireInitialization>::run(start, end, target); } template struct smart_memmove_helper { - static inline void run(const T* start, const T* end, T* target) - { std::memmove(target, start, std::ptrdiff_t(end)-std::ptrdiff_t(start)); } + static inline void run(const T* start, const T* end, T* target) + { std::memmove(target, start, std::ptrdiff_t(end)-std::ptrdiff_t(start)); } }; template struct smart_memmove_helper { - static inline void run(const T* start, const T* end, T* target) - { - if (uintptr_t(target) < uintptr_t(start)) - { - std::copy(start, end, target); - } - else - { - std::ptrdiff_t count = (std::ptrdiff_t(end)-std::ptrdiff_t(start)) / sizeof(T); - std::copy_backward(start, end, target + count); - } + static inline void run(const T* start, const T* end, T* target) + { + if (uintptr_t(target) < uintptr_t(start)) + { + std::copy(start, end, target); } + else + { + std::ptrdiff_t count = (std::ptrdiff_t(end)-std::ptrdiff_t(start)) / sizeof(T); + std::copy_backward(start, end, target + count); + } + } }; -- cgit v1.2.3 From 349c2c9235ce93b50bd8e38be3e876ee73442ccc Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:35:49 +0200 Subject: bug #367: fix double copies in atWithInsertion, and add respective unit-test --- Eigen/src/SparseCore/CompressedStorage.h | 27 +++++++++++++++++++++++---- test/sparse_vector.cpp | 18 ++++++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h index 4f3695773..f408dd3a6 100644 --- a/Eigen/src/SparseCore/CompressedStorage.h +++ b/Eigen/src/SparseCore/CompressedStorage.h @@ -172,12 +172,31 @@ class CompressedStorage size_t id = searchLowerIndex(0,m_size,key); if (id>=m_size || m_indices[id]!=key) { - resize(m_size+1,1); - for (size_t j=m_size-1; j>id; --j) + if (m_allocatedSize newValues(m_allocatedSize); + internal::scoped_array newIndices(m_allocatedSize); + + // copy first chunk + internal::smart_copy(m_values, m_values +id, newValues.ptr()); + internal::smart_copy(m_indices, m_indices+id, newIndices.ptr()); + + // copy the rest + if(m_size>id) + { + internal::smart_copy(m_values +id, m_values +m_size, newValues.ptr() +id+1); + internal::smart_copy(m_indices+id, m_indices+m_size, newIndices.ptr()+id+1); + } + std::swap(m_values,newValues.ptr()); + std::swap(m_indices,newIndices.ptr()); } + else if(m_size>id) + { + internal::smart_memmove(m_values +id, m_values +m_size, m_values +id+1); + internal::smart_memmove(m_indices+id, m_indices+m_size, m_indices+id+1); + } + m_size++; m_indices[id] = key; m_values[id] = defaultValue; } diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 5eea9edfd..5dc421976 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -23,8 +23,8 @@ template void sparse_vector(int rows, int cols) SparseVectorType v1(rows), v2(rows), v3(rows); DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); DenseVector refV1 = DenseVector::Random(rows), - refV2 = DenseVector::Random(rows), - refV3 = DenseVector::Random(rows); + refV2 = DenseVector::Random(rows), + refV3 = DenseVector::Random(rows); std::vector zerocoords, nonzerocoords; initSparse(densityVec, refV1, v1, &zerocoords, &nonzerocoords); @@ -52,6 +52,20 @@ template void sparse_vector(int rows, int cols) } } VERIFY_IS_APPROX(v1, refV1); + + // test coeffRef with reallocation + { + SparseVectorType v1(rows); + DenseVector v2 = DenseVector::Zero(rows); + for(int k=0; k(0,rows-1); + Scalar v = internal::random(); + v1.coeffRef(i) += v; + v2.coeffRef(i) += v; + } + VERIFY_IS_APPROX(v1,v2); + } v1.coeffRef(nonzerocoords[0]) = Scalar(5); refV1.coeffRef(nonzerocoords[0]) = Scalar(5); -- cgit v1.2.3 From a80e17cfe86c5803965dd002c8bd9c5b80591135 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 9 Oct 2014 23:42:33 +0200 Subject: Remove unused and dangerous CompressedStorage::Map function --- Eigen/src/SparseCore/CompressedStorage.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h index f408dd3a6..2845e44e7 100644 --- a/Eigen/src/SparseCore/CompressedStorage.h +++ b/Eigen/src/SparseCore/CompressedStorage.h @@ -108,15 +108,6 @@ class CompressedStorage inline Index& index(size_t i) { return m_indices[i]; } inline const Index& index(size_t i) const { return m_indices[i]; } - static CompressedStorage Map(Index* indices, Scalar* values, size_t size) - { - CompressedStorage res; - res.m_indices = indices; - res.m_values = values; - res.m_allocatedSize = res.m_size = size; - return res; - } - /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ inline Index searchLowerIndex(Index key) const { -- cgit v1.2.3 From d3f52debc6c45d1f26bb9406207ebc5a8638a429 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Mon, 13 Oct 2014 17:18:26 +0200 Subject: Make cuda_basic test compile again by adding lots of EIGEN_DEVICE_FUNC. Although the test passes now, there might still be some missing. --- Eigen/src/Core/AssignEvaluator.h | 108 ++++++++++---------- Eigen/src/Core/Block.h | 2 +- Eigen/src/Core/CoreEvaluators.h | 146 +++++++++++++-------------- Eigen/src/Core/CwiseUnaryView.h | 8 +- Eigen/src/Core/Flagged.h | 26 ++--- Eigen/src/Core/ForceAlignedAccess.h | 20 ++-- Eigen/src/Core/MapBase.h | 2 +- Eigen/src/Core/MatrixBase.h | 2 +- Eigen/src/Core/NestByValue.h | 20 ++-- Eigen/src/Core/PlainObjectBase.h | 4 +- Eigen/src/Core/Product.h | 16 +-- Eigen/src/Core/ProductEvaluators.h | 33 +++--- Eigen/src/Core/Redux.h | 19 ++-- Eigen/src/Core/Ref.h | 22 ++-- Eigen/src/Core/ReturnByValue.h | 2 +- Eigen/src/Core/Reverse.h | 22 ++-- Eigen/src/Core/SelfAdjointView.h | 8 +- Eigen/src/Core/Solve.h | 2 +- Eigen/src/Core/Swap.h | 2 +- Eigen/src/Core/Transpose.h | 4 +- Eigen/src/Core/TriangularMatrix.h | 18 ++-- Eigen/src/Core/functors/AssignmentFunctors.h | 7 +- test/cuda_basic.cu | 6 +- 23 files changed, 255 insertions(+), 244 deletions(-) diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index 5d5095a67..f481a7a36 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h @@ -166,7 +166,7 @@ struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling inner = Index % DstXprType::InnerSizeAtCompileTime }; - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { kernel.assignCoeffByOuterInner(outer, inner); copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); @@ -176,13 +176,13 @@ struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling template struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel&) { } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; template struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) { kernel.assignCoeffByOuterInner(outer, Index); copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); @@ -192,7 +192,7 @@ struct copy_using_evaluator_DefaultTraversal_InnerUnrolling template struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel&, typename Kernel::Index) { } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, typename Kernel::Index) { } }; /*********************** @@ -202,7 +202,7 @@ struct copy_using_evaluator_DefaultTraversal_InnerUnrolling template struct copy_using_evaluator_LinearTraversal_CompleteUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel& kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) { kernel.assignCoeff(Index); copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); @@ -212,7 +212,7 @@ struct copy_using_evaluator_LinearTraversal_CompleteUnrolling template struct copy_using_evaluator_LinearTraversal_CompleteUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel&) { } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; /************************** @@ -232,7 +232,7 @@ struct copy_using_evaluator_innervec_CompleteUnrolling JointAlignment = Kernel::AssignmentTraits::JointAlignment }; - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { kernel.template assignPacketByOuterInner(outer, inner); enum { NextIndex = Index + packet_traits::size }; @@ -243,13 +243,13 @@ struct copy_using_evaluator_innervec_CompleteUnrolling template struct copy_using_evaluator_innervec_CompleteUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel&) { } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; template struct copy_using_evaluator_innervec_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index outer) { kernel.template assignPacketByOuterInner(outer, Index); enum { NextIndex = Index + packet_traits::size }; @@ -260,7 +260,7 @@ struct copy_using_evaluator_innervec_InnerUnrolling template struct copy_using_evaluator_innervec_InnerUnrolling { - static EIGEN_STRONG_INLINE void run(Kernel &, typename Kernel::Index) { } + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, typename Kernel::Index) { } }; /*************************************************************************** @@ -281,7 +281,7 @@ struct dense_assignment_loop; template struct dense_assignment_loop { - static void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static void run(Kernel &kernel) { typedef typename Kernel::Index Index; @@ -296,7 +296,7 @@ struct dense_assignment_loop template struct dense_assignment_loop { - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); @@ -307,7 +307,7 @@ template struct dense_assignment_loop { typedef typename Kernel::Index Index; - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; @@ -330,7 +330,7 @@ struct unaligned_dense_assignment_loop { // if IsAligned = true, then do nothing template - static EIGEN_STRONG_INLINE void run(Kernel&, typename Kernel::Index, typename Kernel::Index) {} + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, typename Kernel::Index, typename Kernel::Index) {} }; template <> @@ -346,7 +346,7 @@ struct unaligned_dense_assignment_loop typename Kernel::Index end) #else template - static EIGEN_STRONG_INLINE void run(Kernel &kernel, + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, typename Kernel::Index start, typename Kernel::Index end) #endif @@ -359,7 +359,7 @@ struct unaligned_dense_assignment_loop template struct dense_assignment_loop { - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::Index Index; @@ -387,7 +387,7 @@ template struct dense_assignment_loop { typedef typename Kernel::Index Index; - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; @@ -407,7 +407,7 @@ struct dense_assignment_loop struct dense_assignment_loop { - static inline void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static inline void run(Kernel &kernel) { typedef typename Kernel::Index Index; @@ -423,7 +423,7 @@ struct dense_assignment_loop template struct dense_assignment_loop { - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); @@ -434,7 +434,7 @@ template struct dense_assignment_loop { typedef typename Kernel::Index Index; - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; const Index outerSize = kernel.outerSize(); @@ -450,7 +450,7 @@ struct dense_assignment_loop template struct dense_assignment_loop { - static inline void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static inline void run(Kernel &kernel) { typedef typename Kernel::Index Index; const Index size = kernel.size(); @@ -462,7 +462,7 @@ struct dense_assignment_loop template struct dense_assignment_loop { - static EIGEN_STRONG_INLINE void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); @@ -476,7 +476,7 @@ struct dense_assignment_loop template struct dense_assignment_loop { - static inline void run(Kernel &kernel) + EIGEN_DEVICE_FUNC static inline void run(Kernel &kernel) { typedef typename Kernel::Index Index; typedef packet_traits PacketTraits; @@ -537,7 +537,7 @@ public: typedef copy_using_evaluator_traits AssignmentTraits; - generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) { #ifdef EIGEN_DEBUG_ASSIGN @@ -545,33 +545,33 @@ public: #endif } - Index size() const { return m_dstExpr.size(); } - Index innerSize() const { return m_dstExpr.innerSize(); } - Index outerSize() const { return m_dstExpr.outerSize(); } - Index rows() const { return m_dstExpr.rows(); } - Index cols() const { return m_dstExpr.cols(); } - Index outerStride() const { return m_dstExpr.outerStride(); } + EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); } + EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); } // TODO get rid of this one: - DstXprType& dstExpression() const { return m_dstExpr; } + EIGEN_DEVICE_FUNC DstXprType& dstExpression() const { return m_dstExpr; } - DstEvaluatorType& dstEvaluator() { return m_dst; } - const SrcEvaluatorType& srcEvaluator() const { return m_src; } + EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; } + EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; } /// Assign src(row,col) to dst(row,col) through the assignment functor. - void assignCoeff(Index row, Index col) + EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) { m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); } /// \sa assignCoeff(Index,Index) - void assignCoeff(Index index) + EIGEN_DEVICE_FUNC void assignCoeff(Index index) { m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); } /// \sa assignCoeff(Index,Index) - void assignCoeffByOuterInner(Index outer, Index inner) + EIGEN_DEVICE_FUNC void assignCoeffByOuterInner(Index outer, Index inner) { Index row = rowIndexByOuterInner(outer, inner); Index col = colIndexByOuterInner(outer, inner); @@ -580,26 +580,26 @@ public: template - void assignPacket(Index row, Index col) + EIGEN_DEVICE_FUNC void assignPacket(Index row, Index col) { m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); } template - void assignPacket(Index index) + EIGEN_DEVICE_FUNC void assignPacket(Index index) { m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); } template - void assignPacketByOuterInner(Index outer, Index inner) + EIGEN_DEVICE_FUNC void assignPacketByOuterInner(Index outer, Index inner) { Index row = rowIndexByOuterInner(outer, inner); Index col = colIndexByOuterInner(outer, inner); assignPacket(row, col); } - static Index rowIndexByOuterInner(Index outer, Index inner) + EIGEN_DEVICE_FUNC static Index rowIndexByOuterInner(Index outer, Index inner) { typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::RowsAtCompileTime) == 1 ? 0 @@ -608,7 +608,7 @@ public: : inner; } - static Index colIndexByOuterInner(Index outer, Index inner) + EIGEN_DEVICE_FUNC static Index colIndexByOuterInner(Index outer, Index inner) { typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::ColsAtCompileTime) == 1 ? 0 @@ -630,7 +630,7 @@ protected: ***************************************************************************/ template -void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) +EIGEN_DEVICE_FUNC void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); @@ -647,7 +647,7 @@ void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src, co } template -void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src) +EIGEN_DEVICE_FUNC void call_dense_assignment_loop(const DstXprType& dst, const SrcXprType& src) { call_dense_assignment_loop(dst, src, internal::assign_op()); } @@ -681,26 +681,26 @@ struct Assignment; // does not has to bother about these annoying details. template -void call_assignment(Dst& dst, const Src& src) +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src) { call_assignment(dst, src, internal::assign_op()); } template -void call_assignment(const Dst& dst, const Src& src) +EIGEN_DEVICE_FUNC void call_assignment(const Dst& dst, const Src& src) { call_assignment(dst, src, internal::assign_op()); } // Deal with AssumeAliasing template -void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==1, void*>::type = 0) { typename plain_matrix_type::type tmp(src); call_assignment_no_alias(dst, tmp, func); } template -void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) +EIGEN_DEVICE_FUNC void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::AssumeAliasing==0, void*>::type = 0) { call_assignment_no_alias(dst, src, func); } @@ -709,19 +709,19 @@ void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable // FIXME the const version should probably not be needed // When there is no aliasing, we require that 'dst' has been properly resized template class StorageBase, typename Src, typename Func> -void call_assignment(const NoAlias& dst, const Src& src, const Func& func) +EIGEN_DEVICE_FUNC void call_assignment(const NoAlias& dst, const Src& src, const Func& func) { call_assignment_no_alias(dst.expression(), src, func); } template class StorageBase, typename Src, typename Func> -void call_assignment(NoAlias& dst, const Src& src, const Func& func) +EIGEN_DEVICE_FUNC void call_assignment(NoAlias& dst, const Src& src, const Func& func) { call_assignment_no_alias(dst.expression(), src, func); } template -void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +EIGEN_DEVICE_FUNC void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) { enum { NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) @@ -752,19 +752,19 @@ void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) Assignment::run(actualDst, src, func); } template -void call_assignment_no_alias(Dst& dst, const Src& src) +EIGEN_DEVICE_FUNC void call_assignment_no_alias(Dst& dst, const Src& src) { call_assignment_no_alias(dst, src, internal::assign_op()); } -// forxard declaration +// forward declaration template void check_for_aliasing(const Dst &dst, const Src &src); // Generic Dense to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); @@ -781,7 +781,7 @@ struct Assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index 737e5dc24..9cf9d5432 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -178,7 +178,7 @@ template struct evaluator : public unary_evaluator { typedef unary_evaluator Base; - explicit evaluator(const T& xpr) : Base(xpr) {} + EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : Base(xpr) {} }; @@ -145,18 +145,18 @@ struct evaluator > Derived::Options,Derived::MaxRowsAtCompileTime,Derived::MaxColsAtCompileTime>::ret }; - evaluator() + EIGEN_DEVICE_FUNC evaluator() : m_data(0), m_outerStride(IsVectorAtCompileTime ? 0 : int(IsRowMajor) ? ColsAtCompileTime : RowsAtCompileTime) {} - explicit evaluator(const PlainObjectType& m) + EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { } - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { if (IsRowMajor) return m_data[row * m_outerStride.value() + col]; @@ -164,12 +164,12 @@ struct evaluator > return m_data[row + col * m_outerStride.value()]; } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_data[index]; } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { if (IsRowMajor) return const_cast(m_data)[row * m_outerStride.value() + col]; @@ -177,7 +177,7 @@ struct evaluator > return const_cast(m_data)[row + col * m_outerStride.value()]; } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return const_cast(m_data)[index]; } @@ -231,7 +231,7 @@ struct evaluator > evaluator() {} - explicit evaluator(const XprType& m) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) : evaluator >(m) { } }; @@ -244,7 +244,7 @@ struct evaluator > evaluator() {} - explicit evaluator(const XprType& m) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) : evaluator >(m) { } }; @@ -262,7 +262,7 @@ struct unary_evaluator, IndexBased> Flags = evaluator::Flags ^ RowMajorBit }; - explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -270,22 +270,22 @@ struct unary_evaluator, IndexBased> typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(col, row); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index); } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(col, row); } - typename XprType::Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC typename XprType::Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index); } @@ -339,7 +339,7 @@ struct evaluator > | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit) // FIXME EvalBeforeNestingBit should be needed anymore }; - explicit evaluator(const XprType& n) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) : m_functor(n.functor()) { } @@ -347,12 +347,12 @@ struct evaluator > typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::PacketScalar PacketScalar; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_functor(row, col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_functor(index); } @@ -389,7 +389,7 @@ struct unary_evaluator, IndexBased > | (functor_traits::PacketAccess ? PacketAccessBit : 0)) }; - explicit unary_evaluator(const XprType& op) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -398,12 +398,12 @@ struct unary_evaluator, IndexBased > typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::PacketScalar PacketScalar; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_functor(m_argImpl.coeff(row, col)); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_functor(m_argImpl.coeff(index)); } @@ -435,7 +435,7 @@ struct evaluator > typedef CwiseBinaryOp XprType; typedef binary_evaluator > Base; - explicit evaluator(const XprType& xpr) : Base(xpr) {} + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} }; template @@ -463,7 +463,7 @@ struct binary_evaluator, IndexBased, IndexBase Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit) }; - explicit binary_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) @@ -473,12 +473,12 @@ struct binary_evaluator, IndexBased, IndexBase typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::PacketScalar PacketScalar; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_functor(m_lhsImpl.coeff(row, col), m_rhsImpl.coeff(row, col)); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index)); } @@ -517,7 +517,7 @@ struct unary_evaluator, IndexBased> Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)) }; - explicit unary_evaluator(const XprType& op) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) : m_unaryOp(op.functor()), m_argImpl(op.nestedExpression()) { } @@ -526,22 +526,22 @@ struct unary_evaluator, IndexBased> typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_unaryOp(m_argImpl.coeff(row, col)); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_unaryOp(m_argImpl.coeff(index)); } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_unaryOp(m_argImpl.coeffRef(row, col)); } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return m_unaryOp(m_argImpl.coeffRef(index)); } @@ -575,7 +575,7 @@ struct mapbase_evaluator : evaluator_base CoeffReadCost = NumTraits::ReadCost }; - explicit mapbase_evaluator(const XprType& map) + EIGEN_DEVICE_FUNC explicit mapbase_evaluator(const XprType& map) : m_data(const_cast(map.data())), m_xpr(map) { @@ -583,22 +583,22 @@ struct mapbase_evaluator : evaluator_base PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); } - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_data[index * m_xpr.innerStride()]; } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_data[col * m_xpr.colStride() + row * m_xpr.rowStride()]; } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return m_data[index * m_xpr.innerStride()]; } @@ -665,7 +665,7 @@ struct evaluator > Flags = KeepsPacketAccess ? int(Flags2) : (int(Flags2) & ~PacketAccessBit) }; - explicit evaluator(const XprType& map) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) : mapbase_evaluator(map) { } }; @@ -682,7 +682,7 @@ struct evaluator > Flags = evaluator >::Flags }; - explicit evaluator(const XprType& ref) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& ref) : mapbase_evaluator(ref) { } }; @@ -733,7 +733,7 @@ struct evaluator > Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit }; typedef block_evaluator block_evaluator_type; - explicit evaluator(const XprType& block) : block_evaluator_type(block) {} + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) {} }; // no direct-access => dispatch to a unary evaluator @@ -743,7 +743,7 @@ struct block_evaluator XprType; - explicit block_evaluator(const XprType& block) + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) : unary_evaluator(block) {} }; @@ -754,7 +754,7 @@ struct unary_evaluator, IndexBa { typedef Block XprType; - explicit unary_evaluator(const XprType& block) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block) : m_argImpl(block.nestedExpression()), m_startRow(block.startRow()), m_startCol(block.startCol()) @@ -770,22 +770,22 @@ struct unary_evaluator, IndexBa RowsAtCompileTime = XprType::RowsAtCompileTime }; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); } @@ -833,7 +833,7 @@ struct block_evaluator XprType; - explicit block_evaluator(const XprType& block) + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) : mapbase_evaluator(block) { // FIXME this should be an internal assertion @@ -859,7 +859,7 @@ struct evaluator > Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits }; - explicit evaluator(const XprType& select) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), m_thenImpl(select.thenMatrix()), m_elseImpl(select.elseMatrix()) @@ -868,7 +868,7 @@ struct evaluator > typedef typename XprType::Index Index; typedef typename XprType::CoeffReturnType CoeffReturnType; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { if (m_conditionImpl.coeff(row, col)) return m_thenImpl.coeff(row, col); @@ -876,7 +876,7 @@ struct evaluator > return m_elseImpl.coeff(row, col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { if (m_conditionImpl.coeff(index)) return m_thenImpl.coeff(index); @@ -913,14 +913,14 @@ struct unary_evaluator > Flags = (evaluator::Flags & HereditaryBits & ~RowMajorBit) | (traits::Flags & RowMajorBit) }; - explicit unary_evaluator(const XprType& replicate) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& replicate) : m_arg(replicate.nestedExpression()), m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), m_cols(replicate.nestedExpression().cols()) {} - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { // try to avoid using modulo; this is a pure optimization strategy const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 @@ -977,19 +977,19 @@ struct evaluator > Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&HereditaryBits) }; - explicit evaluator(const XprType expr) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType expr) : m_expr(expr) {} typedef typename XprType::Index Index; typedef typename XprType::CoeffReturnType CoeffReturnType; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_expr.coeff(row, col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_expr.coeff(index); } @@ -1014,7 +1014,7 @@ struct evaluator_wrapper_base Flags = evaluator::Flags }; - explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + EIGEN_DEVICE_FUNC explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} typedef typename ArgType::Index Index; typedef typename ArgType::Scalar Scalar; @@ -1022,22 +1022,22 @@ struct evaluator_wrapper_base typedef typename ArgType::PacketScalar PacketScalar; typedef typename ArgType::PacketReturnType PacketReturnType; - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(row, col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index); } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(row, col); } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index); } @@ -1076,7 +1076,7 @@ struct unary_evaluator > { typedef MatrixWrapper XprType; - explicit unary_evaluator(const XprType& wrapper) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -1087,7 +1087,7 @@ struct unary_evaluator > { typedef ArrayWrapper XprType; - explicit unary_evaluator(const XprType& wrapper) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; @@ -1133,30 +1133,30 @@ struct unary_evaluator > }; typedef internal::reverse_packet_cond reverse_packet; - explicit unary_evaluator(const XprType& reverse) + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& reverse) : m_argImpl(reverse.nestedExpression()), m_rows(ReverseRow ? reverse.nestedExpression().rows() : 0), m_cols(ReverseCol ? reverse.nestedExpression().cols() : 0) { } - CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); } - Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col); } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); } @@ -1214,7 +1214,7 @@ struct evaluator > Flags = (unsigned int)evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit) & ~RowMajorBit }; - explicit evaluator(const XprType& diagonal) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& diagonal) : m_argImpl(diagonal.nestedExpression()), m_index(diagonal.index()) { } @@ -1223,22 +1223,22 @@ struct evaluator > typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; - CoeffReturnType coeff(Index row, Index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index) const { return m_argImpl.coeff(row + rowOffset(), row + colOffset()); } - CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index + rowOffset(), index + colOffset()); } - Scalar& coeffRef(Index row, Index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index row, Index) { return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); } - Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); } @@ -1248,8 +1248,8 @@ protected: const internal::variable_if_dynamicindex m_index; private: - EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } - EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } }; @@ -1311,7 +1311,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -1320,7 +1320,7 @@ struct evaluator > } // This constructor is used when nesting an EvalTo evaluator in another evaluator - evaluator(const ArgType& arg) + EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) : m_result(arg.rows(), arg.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 6384dfdc3..6680f32dd 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -110,15 +110,15 @@ class CwiseUnaryViewImpl EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - inline Scalar* data() { return &(this->coeffRef(0)); } - inline const Scalar* data() const { return &(this->coeff(0)); } + EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } diff --git a/Eigen/src/Core/Flagged.h b/Eigen/src/Core/Flagged.h index 6ce11edf3..2e2a50be5 100644 --- a/Eigen/src/Core/Flagged.h +++ b/Eigen/src/Core/Flagged.h @@ -50,37 +50,37 @@ template clas explicit inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_matrix.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.innerStride(); } - inline CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index col) const { return m_matrix.coeff(row, col); } - inline CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index index) const { return m_matrix.coeff(index); } - inline const Scalar& coeffRef(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index row, Index col) const { return m_matrix.const_cast_derived().coeffRef(row, col); } - inline const Scalar& coeffRef(Index index) const + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_matrix.const_cast_derived().coeffRef(index); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(row, col); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_matrix.const_cast_derived().coeffRef(index); } @@ -109,13 +109,13 @@ template clas m_matrix.const_cast_derived().template writePacket(index, x); } - const ExpressionType& _expression() const { return m_matrix; } + EIGEN_DEVICE_FUNC const ExpressionType& _expression() const { return m_matrix; } template - typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; + EIGEN_DEVICE_FUNC typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; template - void solveTriangularInPlace(const MatrixBase& other) const; + EIGEN_DEVICE_FUNC void solveTriangularInPlace(const MatrixBase& other) const; protected: ExpressionTypeNested m_matrix; diff --git a/Eigen/src/Core/ForceAlignedAccess.h b/Eigen/src/Core/ForceAlignedAccess.h index 065acfa64..7b08b45e6 100644 --- a/Eigen/src/Core/ForceAlignedAccess.h +++ b/Eigen/src/Core/ForceAlignedAccess.h @@ -39,29 +39,29 @@ template class ForceAlignedAccess typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -90,7 +90,7 @@ template class ForceAlignedAccess m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 3e68b1e91..3c67edae5 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -85,7 +85,7 @@ template class MapBase * * \sa innerStride(), outerStride() */ - inline const Scalar* data() const { return m_data; } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index rowId, Index colId) const diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 048060e6b..001513187 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -180,7 +180,7 @@ template class MatrixBase #ifdef __CUDACC__ template EIGEN_DEVICE_FUNC - const typename LazyProductReturnType::Type + const Product operator*(const MatrixBase &other) const { return this->lazyProduct(other); } #else diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h index 248dd8eb0..9aeaf8d18 100644 --- a/Eigen/src/Core/NestByValue.h +++ b/Eigen/src/Core/NestByValue.h @@ -40,29 +40,29 @@ template class NestByValue typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -91,7 +91,7 @@ template class NestByValue m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index ec7621d09..58fe0f6e0 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h @@ -221,11 +221,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type } /** \returns a const pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE const Scalar *data() const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE Scalar *data() + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index ae64d5200..cb79543ef 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -68,7 +68,7 @@ struct traits > typename RhsTraits::StorageKind, internal::product_type::ret>::ret StorageKind; typedef typename promote_index_type::type Index; + typename RhsTraits::Index>::type Index; enum { RowsAtCompileTime = LhsTraits::RowsAtCompileTime, @@ -113,18 +113,18 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option, typedef typename internal::remove_all::type LhsNestedCleaned; typedef typename internal::remove_all::type RhsNestedCleaned; - Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) + EIGEN_DEVICE_FUNC Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { eigen_assert(lhs.cols() == rhs.rows() && "invalid matrix product" && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); } - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_lhs.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_rhs.cols(); } - const LhsNestedCleaned& lhs() const { return m_lhs; } - const RhsNestedCleaned& rhs() const { return m_rhs; } + EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; } + EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; } protected: @@ -186,7 +186,7 @@ class ProductImpl public: - Scalar coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const { EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); @@ -194,7 +194,7 @@ class ProductImpl return typename internal::evaluator::type(derived()).coeff(row,col); } - Scalar coeff(Index i) const + EIGEN_DEVICE_FUNC Scalar coeff(Index i) const { EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index c944ec9fc..3cebbbd12 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h @@ -35,7 +35,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const XprType& xpr) : Base(xpr) {} + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} }; // Catch scalar * ( A * B ) and transform it to (A*scalar) * B @@ -50,7 +50,7 @@ struct evaluator, const Produ typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr.functor().m_other * xpr.nestedExpression().lhs() * xpr.nestedExpression().rhs()) {} }; @@ -66,7 +66,7 @@ struct evaluator, DiagIndex> > typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(Diagonal, DiagIndex>( Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), xpr.index() )) @@ -104,7 +104,7 @@ struct product_evaluator, ProductTag, LhsShape // CoeffReadCost = 0 // FIXME why is it needed? (this was already the case before the evaluators, see traits) }; - explicit product_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); @@ -378,7 +378,7 @@ struct product_evaluator, ProductTag, DenseShape, typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; - explicit product_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : m_lhs(xpr.lhs()), m_rhs(xpr.rhs()), m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! @@ -461,7 +461,7 @@ struct product_evaluator, ProductTag, DenseShape, && (InnerSize % packet_traits::size == 0) }; - const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index row, Index col) const { // TODO check performance regression wrt to Eigen 3.2 which has special handling of this function return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); @@ -471,7 +471,7 @@ struct product_evaluator, ProductTag, DenseShape, * which is why we don't set the LinearAccessBit. * TODO: this seems possible when the result is a vector */ - const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const { const Index row = RowsAtCompileTime == 1 ? 0 : index; const Index col = RowsAtCompileTime == 1 ? index : 0; @@ -512,7 +512,7 @@ struct product_evaluator, LazyCoeffBasedProduc enum { Flags = Base::Flags | EvalBeforeNestingBit }; - explicit product_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(BaseProduct(xpr.lhs(),xpr.rhs())) {} }; @@ -694,7 +694,7 @@ public: { } - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const { return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); } @@ -743,19 +743,21 @@ struct product_evaluator, ProductTag, DiagonalSha StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; - explicit product_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) { } - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); } +#ifndef __CUDACC__ template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { + // NVCC complains about template keyword, so we disable this function in CUDA mode return this->template packet_impl(row,col, row, typename internal::conditional::type()); } @@ -765,7 +767,7 @@ struct product_evaluator, ProductTag, DiagonalSha { return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } - +#endif }; // dense * diagonal @@ -787,16 +789,17 @@ struct product_evaluator, ProductTag, DenseShape, enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; - explicit product_evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) { } - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); } +#ifndef __CUDACC__ template EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const { @@ -809,7 +812,7 @@ struct product_evaluator, ProductTag, DenseShape, { return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } - +#endif }; /*************************************************************************** diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 14a2671e9..f6546917e 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -277,7 +277,7 @@ struct redux_impl typedef typename packet_traits::type PacketScalar; typedef typename Derived::Index Index; - static Scalar run(const Derived &mat, const Func& func) + EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); @@ -319,7 +319,7 @@ struct redux_impl Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); if (VectorizedSize > 0) { @@ -340,7 +340,7 @@ class redux_evaluator { public: typedef _XprType XprType; - explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} typedef typename XprType::Index Index; typedef typename XprType::Scalar Scalar; @@ -359,15 +359,17 @@ public: CoeffReadCost = evaluator::CoeffReadCost }; - Index rows() const { return m_xpr.rows(); } - Index cols() const { return m_xpr.cols(); } - Index size() const { return m_xpr.size(); } - Index innerSize() const { return m_xpr.innerSize(); } - Index outerSize() const { return m_xpr.outerSize(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_evaluator.coeff(row, col); } + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_evaluator.coeff(index); } @@ -379,6 +381,7 @@ public: PacketReturnType packet(Index index) const { return m_evaluator.template packet(index); } + EIGEN_DEVICE_FUNC CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 2653f2bbe..27fa178cd 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -127,12 +127,12 @@ public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() @@ -140,7 +140,7 @@ public: : this->rows(); } - RefBase() + EIGEN_DEVICE_FUNC RefBase() : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, @@ -154,7 +154,7 @@ protected: typedef Stride StrideBase; template - void construct(Expression& expr) + EIGEN_DEVICE_FUNC void construct(Expression& expr) { if(PlainObjectType::RowsAtCompileTime==1) { @@ -192,13 +192,13 @@ template class Ref #ifndef EIGEN_PARSED_BY_DOXYGEN template - inline Ref(PlainObjectBase& expr, + EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { Base::construct(expr); } template - inline Ref(const DenseBase& expr, + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, typename internal::enable_if::value&&bool(Traits::template match::MatchAtCompileTime)),Derived>::type* = 0, int = Derived::ThisConstantIsPrivateInPlainObjectBase) #else @@ -224,7 +224,7 @@ template class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template - inline Ref(const DenseBase& expr) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; @@ -232,25 +232,25 @@ template class Ref< construct(expr.derived(), typename Traits::template match::type()); } - inline Ref(const Ref& other) : Base(other) { + EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy } template - inline Ref(const RefBase& other) { + EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { construct(other.derived(), typename Traits::template match::type()); } protected: template - void construct(const Expression& expr,internal::true_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) { Base::construct(expr); } template - void construct(const Expression& expr, internal::false_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) { internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); Base::construct(m_object); diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 5fcd9e3fc..4e2a81b56 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -103,7 +103,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const XprType& xpr) + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h index 9ba6ea2e6..291300a4a 100644 --- a/Eigen/src/Core/Reverse.h +++ b/Eigen/src/Core/Reverse.h @@ -89,47 +89,47 @@ template class Reverse typedef internal::reverse_packet_cond reverse_packet; public: - explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return -m_matrix.innerStride(); } - inline Scalar& operator()(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& operator()(Index row, Index col) { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return coeffRef(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, ReverseCol ? m_matrix.cols() - col - 1 : col); } - inline CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index col) const { return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, ReverseCol ? m_matrix.cols() - col - 1 : col); } - inline CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index index) const { return m_matrix.coeff(m_matrix.size() - index - 1); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); } - inline Scalar& operator()(Index index) + EIGEN_DEVICE_FUNC inline Scalar& operator()(Index index) { eigen_assert(index >= 0 && index < m_matrix.size()); return coeffRef(index); @@ -164,7 +164,7 @@ template class Reverse m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); } - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_matrix; diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index 1c44d9c9a..b785e8e1e 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -228,11 +228,11 @@ public: typedef typename Base::AssignmentTraits AssignmentTraits; - triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + EIGEN_DEVICE_FUNC triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) : Base(dst, src, func, dstExpr) {} - void assignCoeff(Index row, Index col) + EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) { eigen_internal_assert(row!=col); Scalar tmp = m_src.coeff(row,col); @@ -240,12 +240,12 @@ public: m_functor.assignCoeff(m_dst.coeffRef(col,row), numext::conj(tmp)); } - void assignDiagonalCoeff(Index id) + EIGEN_DEVICE_FUNC void assignDiagonalCoeff(Index id) { Base::assignCoeff(id,id); } - void assignOppositeCoeff(Index, Index) + EIGEN_DEVICE_FUNC void assignOppositeCoeff(Index, Index) { eigen_internal_assert(false && "should never be called"); } }; diff --git a/Eigen/src/Core/Solve.h b/Eigen/src/Core/Solve.h index 641ffa218..3905cd616 100644 --- a/Eigen/src/Core/Solve.h +++ b/Eigen/src/Core/Solve.h @@ -121,7 +121,7 @@ struct evaluator > typedef evaluator type; typedef evaluator nestedType; - explicit evaluator(const SolveType& solve) + EIGEN_DEVICE_FUNC explicit evaluator(const SolveType& solve) : m_result(solve.rows(), solve.cols()) { ::new (static_cast(this)) Base(m_result); diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 3277cb5ba..55319320a 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -32,7 +32,7 @@ public: typedef typename Base::DstXprType DstXprType; typedef swap_assign_op Functor; - generic_dense_assignment_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, const Functor &func, DstXprType& dstExpr) + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, const Functor &func, DstXprType& dstExpr) : Base(dst, src, func, dstExpr) {} diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 57d6fd2fe..a3b95256f 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -129,8 +129,8 @@ template class TransposeImpl const Scalar >::type ScalarWithConstIfNotLvalue; - inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } - inline const Scalar* data() const { return derived().nestedExpression().data(); } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return derived().nestedExpression().data(); } // FIXME: shall we keep the const version of coeffRef? EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 055ed7514..defe29cd4 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -692,12 +692,12 @@ public: typedef typename Base::AssignmentTraits AssignmentTraits; - triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + EIGEN_DEVICE_FUNC triangular_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) : Base(dst, src, func, dstExpr) {} #ifdef EIGEN_INTERNAL_DEBUGGING - void assignCoeff(Index row, Index col) + EIGEN_DEVICE_FUNC void assignCoeff(Index row, Index col) { eigen_internal_assert(row!=col); Base::assignCoeff(row,col); @@ -706,14 +706,14 @@ public: using Base::assignCoeff; #endif - void assignDiagonalCoeff(Index id) + EIGEN_DEVICE_FUNC void assignDiagonalCoeff(Index id) { if(Mode==UnitDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(1)); else if(Mode==ZeroDiag && SetOpposite) m_functor.assignCoeff(m_dst.coeffRef(id,id), Scalar(0)); else if(Mode==0) Base::assignCoeff(id,id); } - void assignOppositeCoeff(Index row, Index col) + EIGEN_DEVICE_FUNC void assignOppositeCoeff(Index row, Index col) { eigen_internal_assert(row!=col); if(SetOpposite) @@ -722,7 +722,7 @@ public: }; template -void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) +EIGEN_DEVICE_FUNC void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src, const Functor &func) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); @@ -746,7 +746,7 @@ void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& sr } template -void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src) +EIGEN_DEVICE_FUNC void call_triangular_assignment_loop(const DstXprType& dst, const SrcXprType& src) { call_triangular_assignment_loop(dst, src, internal::assign_op()); } @@ -759,7 +759,7 @@ template<> struct AssignmentKind { typedef Dens template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { eigen_assert(int(DstXprType::Mode) == int(SrcXprType::Mode)); @@ -770,7 +770,7 @@ struct Assignment struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { call_triangular_assignment_loop(dst, src, func); } @@ -779,7 +779,7 @@ struct Assignment template< typename DstXprType, typename SrcXprType, typename Functor, typename Scalar> struct Assignment { - static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + EIGEN_DEVICE_FUNC static void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { call_triangular_assignment_loop(dst, src, func); } diff --git a/Eigen/src/Core/functors/AssignmentFunctors.h b/Eigen/src/Core/functors/AssignmentFunctors.h index d4d85a1ca..161b0aa93 100644 --- a/Eigen/src/Core/functors/AssignmentFunctors.h +++ b/Eigen/src/Core/functors/AssignmentFunctors.h @@ -123,7 +123,7 @@ struct functor_traits > { /** \internal - * \brief Template functor for scalar/packet assignment with swaping + * \brief Template functor for scalar/packet assignment with swapping * * It works as follow. For a non-vectorized evaluation loop, we have: * for(i) func(A.coeffRef(i), B.coeff(i)); @@ -142,8 +142,13 @@ template struct swap_assign_op { EIGEN_EMPTY_STRUCT_CTOR(swap_assign_op) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Scalar& a, const Scalar& b) const { +#ifdef __CUDACC__ + // FIXME is there some kind of cuda::swap? + Scalar t=b; const_cast(b)=a; a=t; +#else using std::swap; swap(a,const_cast(b)); +#endif } template diff --git a/test/cuda_basic.cu b/test/cuda_basic.cu index 4c7e96c10..300bced02 100644 --- a/test/cuda_basic.cu +++ b/test/cuda_basic.cu @@ -65,7 +65,7 @@ struct redux { }; template -struct prod { +struct prod_test { EIGEN_DEVICE_FUNC void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const { @@ -125,8 +125,8 @@ void test_cuda_basic() CALL_SUBTEST( run_and_compare_to_cuda(redux(), nthreads, in, out) ); CALL_SUBTEST( run_and_compare_to_cuda(redux(), nthreads, in, out) ); - CALL_SUBTEST( run_and_compare_to_cuda(prod(), nthreads, in, out) ); - CALL_SUBTEST( run_and_compare_to_cuda(prod(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(prod_test(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(prod_test(), nthreads, in, out) ); CALL_SUBTEST( run_and_compare_to_cuda(diagonal(), nthreads, in, out) ); CALL_SUBTEST( run_and_compare_to_cuda(diagonal(), nthreads, in, out) ); -- cgit v1.2.3 From 0ec1fc9e114a2fb8fd0cbeee38669547f46804c8 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 14 Oct 2014 14:14:25 +0200 Subject: bug #891: Determine sizeof(void*) via CMAKE variable instead of test program --- cmake/EigenTesting.cmake | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 65bb29413..3ed002a87 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -489,20 +489,12 @@ macro(ei_set_build_string) endmacro(ei_set_build_string) macro(ei_is_64bit_env VAR) - - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/is64.cpp" - "int main() { return (sizeof(int*) == 8 ? 1 : 0); } - ") - try_run(run_res compile_res - ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/is64.cpp" - RUN_OUTPUT_VARIABLE run_output) - - if(compile_res AND run_res) - set(${VAR} ${run_res}) - elseif(CMAKE_CL_64) - set(${VAR} 1) - elseif("$ENV{Platform}" STREQUAL "X64") # nmake 64 bit + if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(${VAR} 1) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(${VAR} 0) + else() + message(WARNING "Unsupported pointer size. Please contact the authors.") endif() endmacro(ei_is_64bit_env) -- cgit v1.2.3 From c26e8a1af32a907eb6c78f0ae2165af5e1f79a76 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 15 Oct 2014 11:59:21 +0200 Subject: D&C SVD: fix deflation of repeated singular values, fix sorting of singular values, fix case of complete deflation --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 227 ++++++++++++++++++++++++---------- 1 file changed, 161 insertions(+), 66 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index d5e8140a4..d8d75624d 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -23,6 +23,10 @@ // #define EIGEN_BDCSVD_SANITY_CHECKS namespace Eigen { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE +IOFormat bdcsvdfmt(8, 0, ", ", "\n", " [", "]"); +#endif + template class BDCSVD; namespace internal { @@ -234,6 +238,9 @@ BDCSVD >& BDCSVD >:: template BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "\n\n\n======================================================================================================================\n\n\n"; +#endif allocate(matrix.rows(), matrix.cols(), computationOptions); using std::abs; @@ -478,9 +485,23 @@ void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + ArrayXr tmp1 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); +#endif // Second part: try to deflate singular values in combined matrix deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); - +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + ArrayXr tmp2 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); + std::cout << "\n\nj1 = " << tmp1.transpose().format(bdcsvdfmt) << "\n"; + std::cout << "j2 = " << tmp2.transpose().format(bdcsvdfmt) << "\n\n"; + std::cout << "err: " << ((tmp1-tmp2).abs()>1e-12*tmp2.abs()).transpose() << "\n"; + static int count = 0; + std::cout << "# " << ++count << "\n\n"; + assert((tmp1-tmp2).matrix().norm() < 1e-14*tmp2.matrix().norm()); +// assert(count<681); +// assert(((tmp1-tmp2).abs()<1e-13*tmp2.abs()).all()); +#endif + // Third part: compute SVD of combined matrix MatrixXr UofSVD, VofSVD; VectorType singVals; @@ -542,9 +563,20 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec computeSingVals(col0, diag, singVals, shifts, mus); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << " j: " << (m_computed.block(firstCol, firstCol, n, n)).jacobiSvd().singularValues().transpose().reverse() << "\n\n"; std::cout << " sing-val: " << singVals.transpose() << "\n"; std::cout << " mu: " << mus.transpose() << "\n"; std::cout << " shift: " << shifts.transpose() << "\n"; + + { + Index actual_n = n; + while(actual_n>1 && col0(actual_n-1)==0) --actual_n; + std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n"; + std::cout << " check1 (expect0) : " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check2 (>0) : " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check3 (>0) : " << ((diag.segment(1,actual_n-1)-singVals.head(actual_n-1).array()) / singVals.head(actual_n-1).array()).transpose() << "\n\n\n"; + std::cout << " check4 (>0) : " << ((singVals.segment(1,actual_n-1)-singVals.head(actual_n-1))).transpose() << "\n\n\n"; + } #endif #ifdef EIGEN_BDCSVD_SANITY_CHECKS @@ -557,16 +589,8 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec perturbCol0(col0, diag, singVals, shifts, mus, zhat); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE std::cout << " zhat: " << zhat.transpose() << "\n"; - { - Index actual_n = n; - while(actual_n>1 && col0(actual_n-1)==0) --actual_n; - std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n"; - std::cout << " check1: " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() << "\n\n"; - std::cout << " check2: " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() << "\n\n"; - std::cout << " check3: " << ((diag.segment(1,actual_n-1)-singVals.head(actual_n-1).array()) / singVals.head(actual_n-1).array()).transpose() << "\n\n\n"; - } #endif - + #ifdef EIGEN_BDCSVD_SANITY_CHECKS assert(zhat.allFinite()); #endif @@ -586,19 +610,40 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec assert(m_computed.allFinite()); #endif - // Reverse order so that singular values in increased order - // Because of deflation, the zeros singular-values are already at the end Index actual_n = n; while(actual_n>1 && singVals(actual_n-1)==0) --actual_n; + + // Because of deflation, the singular values might not be completely sorted. + // Fortunately, reordering them is a O(n) problem + for(Index i=0; isingVals(i+1)) + { + using std::swap; + swap(singVals(i),singVals(i+1)); + U.col(i).swap(U.col(i+1)); + if(m_compV) V.col(i).swap(V.col(i+1)); + } + } + + // Reverse order so that singular values in increased order + // Because of deflation, the zeros singular-values are already at the end singVals.head(actual_n).reverseInPlace(); U.leftCols(actual_n) = U.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary if (m_compV) V.leftCols(actual_n) = V.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + JacobiSVD jsvd(m_computed.block(firstCol, firstCol, n, n) ); + std::cout << " * j: " << jsvd.singularValues().transpose() << "\n\n"; + std::cout << " * sing-val: " << singVals.transpose() << "\n"; +// std::cout << " * err: " << ((jsvd.singularValues()-singVals)>1e-13*singVals.norm()).transpose() << "\n"; +#endif } template typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXr& diagShifted, RealScalar shift, Index n) { - return 1 + (col0.square() / ((diagShifted - mu) )/( (diag + shift + mu))).head(n).sum(); + return 1 + (col0.square() / ((diagShifted - mu) * (diag + shift + mu))).head(n).sum(); } template @@ -622,16 +667,16 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // } // } // perm.conservativeResize(m); - + for (Index k = 0; k < n; ++k) { if (col0(k) == 0 || actual_n==1) { // if col0(k) == 0, then entry is deflated, so singular value is on diagonal // if actual_n==1, then the deflated problem is already diagonalized - singVals(k) = diag(k); + singVals(k) = k==0 ? col0(0) : diag(k); mus(k) = 0; - shifts(k) = diag(k); + shifts(k) = k==0 ? col0(0) : diag(k); continue; } @@ -646,12 +691,23 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia Index l = k+1; while(col0(l)==0) { ++l; eigen_internal_assert(l 0) ? left : right; // measure everything relative to shift @@ -682,20 +738,26 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // rational interpolation: fit a function of the form a / mu + b through the two previous // iterates and use its zero to compute the next iterate bool useBisection = fPrev*fCur>0; - while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) + while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) { ++m_numIters; + // Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples. RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); RealScalar b = fCur - a / muCur; - + // And find mu such that f(mu)==0: + RealScalar muZero = -a/b; + RealScalar fZero = secularEq(muZero, col0, diag, diagShifted, shift, actual_n); + muPrev = muCur; fPrev = fCur; - muCur = -a / b; - fCur = secularEq(muCur, col0, diag, diagShifted, shift, actual_n); + muCur = muZero; + fCur = fZero; + if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true; + if (abs(fCur)>abs(fPrev)) useBisection = true; } // fall back on bisection method if rational interpolation did not work @@ -710,7 +772,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia leftShifted = RealScalar(1)/NumTraits::highest(); // I don't understand why the case k==0 would be special there: // if (k == 0) rightShifted = right - left; else - rightShifted = (right - left) * 0.6; // theoretically we can take 0.5, but let's be safe + rightShifted = (k==actual_n-1) ? right : ((right - left) * 0.6); // theoretically we can take 0.5, but let's be safe } else { @@ -722,7 +784,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia RealScalar fRight = secularEq(rightShifted, col0, diag, diagShifted, shift, actual_n); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - if(fLeft * fRight>=0) + if(!(fLeft * fRight<0)) std::cout << k << " : " << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; #endif eigen_internal_assert(fLeft * fRight < 0); @@ -805,7 +867,8 @@ void BDCSVD::perturbCol0 prod *= ((singVals(j)+dk) / ((diag(i)+dk))) * ((mus(j)+(shifts(j)-dk)) / ((diag(i)-dk))); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE if(i!=k && std::abs(((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) - 1) > 0.9 ) - std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk)) << ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n"; + std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk)) + << ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n"; #endif } } @@ -863,8 +926,6 @@ void BDCSVD::computeSingVecs if (m_compV) { V.col(k).setZero(); -// for(Index i=1;i::deflation43(Index firstCol, Index shift, Index i, Index // page 13 -// i,j >= 1, i != j and |di - dj| < epsilon * norm2(M) +// i,j >= 1, i!=j and |di - dj| < epsilon * norm2(M) // We apply two rotations to have zj = 0; // TODO deflation44 is still broken and not properly tested template @@ -943,15 +1004,10 @@ void BDCSVD::deflation44(Index firstColu , Index firstColm, Index fi m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); m_computed(firstColm + j, firstColm) = 0; - JacobiRotation J(c,s); - if (m_compU) - { - m_naiveU.middleRows(firstColu, size).applyOnTheRight(firstColu + i, firstColu + j, J); - } - if (m_compV) - { - m_naiveU.middleRows(firstRowW, size-1).applyOnTheRight(firstColW + i, firstColW + j, J.transpose()); - } + JacobiRotation J(c,-s); + if (m_compU) m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J); + else m_naiveU.applyOnTheRight(firstColu+i, firstColu+j, J); + if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J); }// end deflation 44 @@ -964,43 +1020,49 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index using std::max; const Index length = lastCol + 1 - firstCol; + Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); + Diagonal fulldiag(m_computed); + VectorBlock,Dynamic> diag(fulldiag, firstCol+shift, length); + + RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff(); + RealScalar epsilon_strict = NumTraits::epsilon() * maxDiag; + RealScalar epsilon_coarse = 8 * NumTraits::epsilon() * (max)(col0.cwiseAbs().maxCoeff(), maxDiag); + #ifdef EIGEN_BDCSVD_SANITY_CHECKS assert(m_naiveU.allFinite()); assert(m_naiveV.allFinite()); assert(m_computed.allFinite()); #endif - - Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); - Diagonal fulldiag(m_computed); - VectorBlock,Dynamic> diag(fulldiag, firstCol+shift, length); - - RealScalar epsilon = 8 * NumTraits::epsilon() * (max)(col0.cwiseAbs().maxCoeff(), diag.cwiseAbs().maxCoeff()); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "\ndeflate:" << diag.head(k+1).transpose() << " | " << diag.segment(k+1,length-k-1).transpose() << "\n"; +#endif //condition 4.1 - if (diag(0) < epsilon) + if (diag(0) < epsilon_coarse) { #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon << "\n"; + std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon_coarse << "\n"; #endif - diag(0) = epsilon; + diag(0) = epsilon_coarse; } //condition 4.2 for (Index i=1;i::deflation(Index firstCol, Index lastCol, Index k, Index assert(m_naiveV.allFinite()); assert(m_computed.allFinite()); #endif - +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "to be sorted: " << diag.transpose() << "\n\n"; +#endif { + // Check for total deflation + // If we have a total deflation, then we have to consider col0(0)==diag(0) as a singular value during sorting + bool total_deflation = (col0.tail(length-1).array()==RealScalar(0)).all(); + // Sort the diagonal entries, since diag(1:k-1) and diag(k:length) are already sorted, let's do a sorted merge. // First, compute the respective permutation. Index *permutation = new Index[length]; // FIXME avoid repeated dynamic memory allocation { permutation[0] = 0; Index p = 1; + + // Move deflated diagonal entries at the end. for(Index i=1; i::deflation(Index firstCol, Index lastCol, Index k, Index } } + // If we have a total deflation, then we have to insert diag(0) at the right place + if(total_deflation) + { + for(Index i=1; i::Map(permutation, length) << "\n\n"; + // Current index of each col, and current column of each index Index *realInd = new Index[length]; // FIXME avoid repeated dynamic memory allocation Index *realCol = new Index[length]; // FIXME avoid repeated dynamic memory allocation @@ -1042,15 +1129,15 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index realInd[pos] = pos; } - for(Index i = 1; i < length; i++) + for(Index i = total_deflation?0:1; i < length; i++) { - const Index pi = permutation[length - i]; + const Index pi = permutation[length - (total_deflation ? i+1 : i)]; const Index J = realCol[pi]; using std::swap; - // swap diaognal and first column entries: + // swap diagonal and first column entries: swap(diag(i), diag(J)); - swap(col0(i), col0(J)); + if(i!=0 && J!=0) swap(col0(i), col0(J)); // change columns if (m_compU) m_naiveU.col(firstCol+i).segment(firstCol, length + 1).swap(m_naiveU.col(firstCol+J).segment(firstCol, length + 1)); @@ -1068,22 +1155,30 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index delete[] realInd; delete[] realCol; } - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - for(int k=2;k::epsilon()*diag(i+1)) -// if ((diag(i+1) - diag(i)) < epsilon) - { + { + Index i = length-1; + while(i>0 && (diag(i)==0 || col0(i)==0)) --i; + for(; i>1;--i) + if( (diag(i) - diag(i-1)) < NumTraits::epsilon()*diag(i) ) + { #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i+1) - diag(i)) << " < " << epsilon << "\n"; + std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i) - diag(i-1)) << " < " << NumTraits::epsilon()*diag(i) << "\n"; +#endif + eigen_internal_assert(abs(diag(i) - diag(i-1)) Date: Wed, 15 Oct 2014 15:21:12 +0200 Subject: D&C SVD: fix some numerical issues by truly skipping deflated singular values when computing them --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 143 ++++++++++++++-------------------- 1 file changed, 59 insertions(+), 84 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index d8d75624d..e8e795589 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -84,6 +84,7 @@ public: typedef Matrix MatrixXr; typedef Matrix VectorType; typedef Array ArrayXr; + typedef Array ArrayXi; /** \brief Default Constructor. * @@ -159,19 +160,16 @@ private: void allocate(Index rows, Index cols, unsigned int computationOptions); void divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift); void computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V); - void computeSingVals(const ArrayXr& col0, const ArrayXr& diag, VectorType& singVals, - ArrayXr& shifts, ArrayXr& mus); - void perturbCol0(const ArrayXr& col0, const ArrayXr& diag, const VectorType& singVals, - const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat); - void computeSingVecs(const ArrayXr& zhat, const ArrayXr& diag, const VectorType& singVals, - const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V); + void computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, VectorType& singVals, ArrayXr& shifts, ArrayXr& mus); + void perturbCol0(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat); + void computeSingVecs(const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V); void deflation43(Index firstCol, Index shift, Index i, Index size); void deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size); void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift); template void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); static void structured_update(Block A, const MatrixXr &B, Index n1); - static RealScalar secularEq(RealScalar x, const ArrayXr& col0, const ArrayXr& diag, const ArrayXr& diagShifted, RealScalar shift, Index n); + static RealScalar secularEq(RealScalar x, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift); protected: MatrixXr m_naiveU, m_naiveV; @@ -543,13 +541,24 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); diag(0) = 0; - // compute singular values and vectors (in decreasing order) + // Allocate space for singular values and vectors singVals.resize(n); U.resize(n+1, n+1); if (m_compV) V.resize(n, n); if (col0.hasNaN() || diag.hasNaN()) { std::cout << "\n\nHAS NAN\n\n"; return; } - + + // Many singular values might have been deflated, the zero ones have been moved to the end, + // but others are interleaved and we must ignore them at this stage. + // To this end, let's compute a permutation skipping them: + Index actual_n = n; + while(actual_n>1 && diag(actual_n-1)==0) --actual_n; + Index m = 0; // size of the deflated problem + ArrayXi perm(actual_n); + for(Index k=0;k::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec #endif // Compute singVals, shifts, and mus - computeSingVals(col0, diag, singVals, shifts, mus); + computeSingVals(col0, diag, perm, singVals, shifts, mus); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE std::cout << " j: " << (m_computed.block(firstCol, firstCol, n, n)).jacobiSvd().singularValues().transpose().reverse() << "\n\n"; @@ -586,7 +595,7 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec #endif // Compute zhat - perturbCol0(col0, diag, singVals, shifts, mus, zhat); + perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE std::cout << " zhat: " << zhat.transpose() << "\n"; #endif @@ -595,7 +604,7 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec assert(zhat.allFinite()); #endif - computeSingVecs(zhat, diag, singVals, shifts, mus, U, V); + computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() << "\n"; @@ -610,9 +619,6 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec assert(m_computed.allFinite()); #endif - Index actual_n = n; - while(actual_n>1 && singVals(actual_n-1)==0) --actual_n; - // Because of deflation, the singular values might not be completely sorted. // Fortunately, reordering them is a O(n) problem for(Index i=0; i::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec } template -typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXr& diagShifted, RealScalar shift, Index n) +typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift) { - return 1 + (col0.square() / ((diagShifted - mu) * (diag + shift + mu))).head(n).sum(); + Index m = perm.size(); + RealScalar res = 1; + for(Index i=0; i -void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, +void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, VectorType& singVals, ArrayXr& shifts, ArrayXr& mus) { using std::abs; @@ -657,16 +670,6 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia Index n = col0.size(); Index actual_n = n; while(actual_n>1 && col0(actual_n-1)==0) --actual_n; -// Index m = 0; -// Array perm(actual_n); -// { -// for(Index k=0;k::computeSingVals(const ArrayXr& col0, const ArrayXr& dia Index l = k+1; while(col0(l)==0) { ++l; eigen_internal_assert(l 0) ? left : right; @@ -727,8 +733,8 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia muCur = -(right - left) * 0.5; } - RealScalar fPrev = secularEq(muPrev, col0, diag, diagShifted, shift, actual_n); - RealScalar fCur = secularEq(muCur, col0, diag, diagShifted, shift, actual_n); + RealScalar fPrev = secularEq(muPrev, col0, diag, perm, diagShifted, shift); + RealScalar fCur = secularEq(muCur, col0, diag, perm, diagShifted, shift); if (abs(fPrev) < abs(fCur)) { swap(fPrev, fCur); @@ -747,7 +753,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia RealScalar b = fCur - a / muCur; // And find mu such that f(mu)==0: RealScalar muZero = -a/b; - RealScalar fZero = secularEq(muZero, col0, diag, diagShifted, shift, actual_n); + RealScalar fZero = secularEq(muZero, col0, diag, perm, diagShifted, shift); muPrev = muCur; fPrev = fCur; @@ -780,8 +786,8 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia rightShifted = -RealScalar(1)/NumTraits::highest(); } - RealScalar fLeft = secularEq(leftShifted, col0, diag, diagShifted, shift, actual_n); - RealScalar fRight = secularEq(rightShifted, col0, diag, diagShifted, shift, actual_n); + RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift); + RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift); #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE if(!(fLeft * fRight<0)) @@ -792,7 +798,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (max)(abs(leftShifted), abs(rightShifted))) { RealScalar midShifted = (leftShifted + rightShifted) / 2; - RealScalar fMid = secularEq(midShifted, col0, diag, diagShifted, shift, actual_n); + RealScalar fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift); if (fLeft * fMid < 0) { rightShifted = midShifted; @@ -824,28 +830,13 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // zhat is perturbation of col0 for which singular vectors can be computed stably (see Section 3.1) template void BDCSVD::perturbCol0 - (const ArrayXr& col0, const ArrayXr& diag, const VectorType& singVals, + (const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) { using std::sqrt; Index n = col0.size(); - - // Ignore trailing zeros: - Index actual_n = n; - while(actual_n>1 && col0(actual_n-1)==0) --actual_n; - // Deflated non-zero singular values are kept in-place, - // we thus compute an indirection array to properly ignore all deflated entries. - // TODO compute it once! - Index m = 0; // size of the deflated problem - Array perm(actual_n); - { - for(Index k=0;k::perturbCol0 { // see equation (3.6) RealScalar dk = diag(k); - RealScalar prod = (singVals(actual_n-1) + dk) * (mus(actual_n-1) + (shifts(actual_n-1) - dk)); + RealScalar prod = (singVals(last) + dk) * (mus(last) + (shifts(last) - dk)); for(Index l = 0; l::perturbCol0 } } #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(actual_n-1) + dk) << " * " << mus(actual_n-1) + shifts(actual_n-1) << " - " << dk << "\n"; + std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(last) + dk) << " * " << mus(last) + shifts(last) << " - " << dk << "\n"; #endif RealScalar tmp = sqrt(prod); zhat(k) = col0(k) > 0 ? tmp : -tmp; @@ -884,26 +875,11 @@ void BDCSVD::perturbCol0 // compute singular vectors template void BDCSVD::computeSingVecs - (const ArrayXr& zhat, const ArrayXr& diag, const VectorType& singVals, + (const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V) { Index n = zhat.size(); - - // Deflated non-zero singular values are kept in-place, - // we thus compute an indirection array to properly ignore all deflated entries. - // TODO compute it once! - Index actual_n = n; - while(actual_n>1 && zhat(actual_n-1)==0) --actual_n; - Index m = 0; - Array perm(actual_n); - { - for(Index k=0;k::deflation44(Index firstColu , Index firstColm, Index fi c/=r; s/=r; m_computed(firstColm + i, firstColm) = r; - m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); + m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i); m_computed(firstColm + j, firstColm) = 0; JacobiRotation J(c,-s); @@ -1117,7 +1093,6 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index } } } -// std::cout << "perm: " << Matrix::Map(permutation, length) << "\n\n"; // Current index of each col, and current column of each index Index *realInd = new Index[length]; // FIXME avoid repeated dynamic memory allocation @@ -1165,7 +1140,7 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index Index i = length-1; while(i>0 && (diag(i)==0 || col0(i)==0)) --i; for(; i>1;--i) - if( (diag(i) - diag(i-1)) < NumTraits::epsilon()*diag(i) ) + if( (diag(i) - diag(i-1)) < NumTraits::epsilon()*maxDiag ) { #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i) - diag(i-1)) << " < " << NumTraits::epsilon()*diag(i) << "\n"; -- cgit v1.2.3 From c8060094535882e4fc46e5d54a13358d6c23b7a9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 15 Oct 2014 16:32:16 +0200 Subject: Extend svd unit tests to stress problems with duplicated singular values. --- test/svd_common.h | 71 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/test/svd_common.h b/test/svd_common.h index e902d2320..347ea8046 100644 --- a/test/svd_common.h +++ b/test/svd_common.h @@ -38,7 +38,6 @@ void svd_check_full(const MatrixType& m, const SvdType& svd) sigma.diagonal() = svd.singularValues().template cast(); MatrixUType u = svd.matrixU(); MatrixVType v = svd.matrixV(); - VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); VERIFY_IS_UNITARY(u); VERIFY_IS_UNITARY(v); @@ -90,31 +89,31 @@ void svd_least_square(const MatrixType& m, unsigned int computationOptions) SolutionType x = svd.solve(rhs); + // evaluate normal equation which works also for least-squares solutions + if(internal::is_same::value || svd.rank()==m.diagonal().size()) + { + // This test is not stable with single precision. + // This is probably because squaring m signicantly affects the precision. + VERIFY_IS_APPROX(m.adjoint()*(m*x),m.adjoint()*rhs); + } + RealScalar residual = (m*x-rhs).norm(); // Check that there is no significantly better solution in the neighborhood of x if(!test_isMuchSmallerThan(residual,rhs.norm())) { - // If the residual is very small, then we have an exact solution, so we are already good. - for(int k=0;k::epsilon(); + y.row(k) = (1.+2*NumTraits::epsilon())*x.row(k); RealScalar residual_y = (m*y-rhs).norm(); VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); - y.row(k) = x.row(k).array() - 2*NumTraits::epsilon(); + y.row(k) = (1.-2*NumTraits::epsilon())*x.row(k); residual_y = (m*y-rhs).norm(); VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); } } - - // evaluate normal equation which works also for least-squares solutions - if(internal::is_same::value) - { - // This test is not stable with single precision. - // This is probably because squaring m signicantly affects the precision. - VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); - } } // check minimal norm solutions, the inoput matrix m is only used to recover problem size @@ -234,11 +233,49 @@ void svd_fill_random(MatrixType &m) Matrix d = Matrix::Random(diagSize); for(Index k=0; k(-s,s)); - m = Matrix::Random(m.rows(),diagSize) * d.asDiagonal() * Matrix::Random(diagSize,m.cols()); + + bool dup = internal::random(0,10) < 3; + bool unit_uv = internal::random(0,10) < (dup?7:3); // if we duplicate some diagonal entries, then increase the chance to preserve them using unitary U and V factors + + // duplicate some singular values + if(dup) + { + Index n = internal::random(0,d.size()-1); + for(Index i=0; i(0,d.size()-1)) = d(internal::random(0,d.size()-1)); + } + + Matrix U(m.rows(),diagSize); + Matrix VT(diagSize,m.cols()); + if(unit_uv) + { + // in very rare cases let's try with a pure diagonal matrix + if(internal::random(0,10) < 1) + { + U.setIdentity(); + VT.setIdentity(); + } + else + { + createRandomPIMatrixOfRank(diagSize,U.rows(), U.cols(), U); + createRandomPIMatrixOfRank(diagSize,VT.rows(), VT.cols(), VT); + } + } + else + { + U.setRandom(); + VT.setRandom(); + } + + m = U * d.asDiagonal() * VT; + // cancel some coeffs - Index n = internal::random(0,m.size()-1); - for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); + if(!(dup && unit_uv)) + { + Index n = internal::random(0,m.size()-1); + for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); + } } -- cgit v1.2.3 From c566cfe2ba0aad4ef054a55b402209980a90d994 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 15 Oct 2014 23:37:47 +0200 Subject: Make SVD unit test even more tough --- test/svd_common.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/svd_common.h b/test/svd_common.h index 347ea8046..4c172cf9d 100644 --- a/test/svd_common.h +++ b/test/svd_common.h @@ -269,12 +269,14 @@ void svd_fill_random(MatrixType &m) m = U * d.asDiagonal() * VT; - // cancel some coeffs + // (partly) cancel some coeffs if(!(dup && unit_uv)) { - Index n = internal::random(0,m.size()-1); + Matrix samples(7); + samples << 0, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -1./NumTraits::highest(), 1./NumTraits::highest(); + Index n = internal::random(0,m.size()-1); for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); + m(internal::random(0,m.rows()-1), internal::random(0,m.cols()-1)) = samples(internal::random(0,6)); } } -- cgit v1.2.3 From 880e72c130a2817a278a05f6d2ed3ff00cb1cd6a Mon Sep 17 00:00:00 2001 From: Mark Borgerding Date: Thu, 16 Oct 2014 09:19:32 -0400 Subject: quieted more g++ warnings of the form: warning: typedef XXX locally defined but not used [-Wunused-local-typedefs] --- Eigen/src/Eigenvalues/ComplexSchur_MKL.h | 1 - Eigen/src/Eigenvalues/RealSchur_MKL.h | 4 ---- Eigen/src/QR/ColPivHouseholderQR_MKL.h | 1 - Eigen/src/SVD/JacobiSVD_MKL.h | 4 ++-- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexSchur_MKL.h b/Eigen/src/Eigenvalues/ComplexSchur_MKL.h index 91496ae5b..27aed923c 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur_MKL.h +++ b/Eigen/src/Eigenvalues/ComplexSchur_MKL.h @@ -45,7 +45,6 @@ ComplexSchur >& \ ComplexSchur >::compute(const Matrix& matrix, bool computeU) \ { \ typedef Matrix MatrixType; \ - typedef MatrixType::Scalar Scalar; \ typedef MatrixType::RealScalar RealScalar; \ typedef std::complex ComplexScalar; \ \ diff --git a/Eigen/src/Eigenvalues/RealSchur_MKL.h b/Eigen/src/Eigenvalues/RealSchur_MKL.h index ad9736460..c3089b468 100644 --- a/Eigen/src/Eigenvalues/RealSchur_MKL.h +++ b/Eigen/src/Eigenvalues/RealSchur_MKL.h @@ -44,10 +44,6 @@ template<> inline \ RealSchur >& \ RealSchur >::compute(const Matrix& matrix, bool computeU) \ { \ - typedef Matrix MatrixType; \ - typedef MatrixType::Scalar Scalar; \ - typedef MatrixType::RealScalar RealScalar; \ -\ eigen_assert(matrix.cols() == matrix.rows()); \ \ lapack_int n = matrix.cols(), sdim, info; \ diff --git a/Eigen/src/QR/ColPivHouseholderQR_MKL.h b/Eigen/src/QR/ColPivHouseholderQR_MKL.h index b5b198326..7b6ba0a5e 100644 --- a/Eigen/src/QR/ColPivHouseholderQR_MKL.h +++ b/Eigen/src/QR/ColPivHouseholderQR_MKL.h @@ -49,7 +49,6 @@ ColPivHouseholderQR MatrixType; \ - typedef MatrixType::Scalar Scalar; \ typedef MatrixType::RealScalar RealScalar; \ Index rows = matrix.rows();\ Index cols = matrix.cols();\ diff --git a/Eigen/src/SVD/JacobiSVD_MKL.h b/Eigen/src/SVD/JacobiSVD_MKL.h index decda7540..14e461c4e 100644 --- a/Eigen/src/SVD/JacobiSVD_MKL.h +++ b/Eigen/src/SVD/JacobiSVD_MKL.h @@ -45,8 +45,8 @@ JacobiSVD, ColPiv JacobiSVD, ColPivHouseholderQRPreconditioner>::compute(const Matrix& matrix, unsigned int computationOptions) \ { \ typedef Matrix MatrixType; \ - typedef MatrixType::Scalar Scalar; \ - typedef MatrixType::RealScalar RealScalar; \ + /*typedef MatrixType::Scalar Scalar;*/ \ + /*typedef MatrixType::RealScalar RealScalar;*/ \ allocate(matrix.rows(), matrix.cols(), computationOptions); \ \ /*const RealScalar precision = RealScalar(2) * NumTraits::epsilon();*/ \ -- cgit v1.2.3 From 8472e697ca606e2ea1a67cc2dfa175757666cc02 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 17 Oct 2014 15:31:11 +0200 Subject: Add lapack interface to JacobiSVD and BDCSVD --- Eigen/src/Core/util/Memory.h | 2 +- Eigen/src/SparseCore/CompressedStorage.h | 2 +- lapack/complex_double.cpp | 3 +- lapack/complex_single.cpp | 3 +- lapack/double.cpp | 3 +- lapack/eigenvalues.cpp | 23 +----- lapack/lapack_common.h | 7 +- lapack/single.cpp | 3 +- lapack/svd.cpp | 138 +++++++++++++++++++++++++++++++ 9 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 lapack/svd.cpp diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 7b39285ea..b49a18cc7 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2008-2009 Benoit Jacob // Copyright (C) 2009 Kenneth Riddile // Copyright (C) 2010 Hauke Heibel diff --git a/Eigen/src/SparseCore/CompressedStorage.h b/Eigen/src/SparseCore/CompressedStorage.h index 2845e44e7..e09ad97f0 100644 --- a/Eigen/src/SparseCore/CompressedStorage.h +++ b/Eigen/src/SparseCore/CompressedStorage.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-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed diff --git a/lapack/complex_double.cpp b/lapack/complex_double.cpp index 424d2b8ca..c9c575273 100644 --- a/lapack/complex_double.cpp +++ b/lapack/complex_double.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" +#include "svd.cpp" diff --git a/lapack/complex_single.cpp b/lapack/complex_single.cpp index c0b2d29ae..6d11b26cd 100644 --- a/lapack/complex_single.cpp +++ b/lapack/complex_single.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" +#include "svd.cpp" diff --git a/lapack/double.cpp b/lapack/double.cpp index d86549e19..ea78bb662 100644 --- a/lapack/double.cpp +++ b/lapack/double.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" #include "eigenvalues.cpp" +#include "svd.cpp" diff --git a/lapack/eigenvalues.cpp b/lapack/eigenvalues.cpp index 6141032ab..921c51569 100644 --- a/lapack/eigenvalues.cpp +++ b/lapack/eigenvalues.cpp @@ -7,10 +7,10 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#include "common.h" +#include "lapack_common.h" #include -// computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges +// computes eigen values and vectors of a general N-by-N matrix A EIGEN_LAPACK_FUNC(syev,(char *jobz, char *uplo, int* n, Scalar* a, int *lda, Scalar* w, Scalar* /*work*/, int* lwork, int *info)) { // TODO exploit the work buffer @@ -22,24 +22,7 @@ EIGEN_LAPACK_FUNC(syev,(char *jobz, char *uplo, int* n, Scalar* a, int *lda, Sca else if(*n<0) *info = -3; else if(*lda +// Copyright (C) 2010-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -18,6 +18,11 @@ typedef Eigen::Map > PivotsType; +#if ISCOMPLEX +#define EIGEN_LAPACK_ARG_IF_COMPLEX(X) X, +#else +#define EIGEN_LAPACK_ARG_IF_COMPLEX(X) +#endif #endif // EIGEN_LAPACK_COMMON_H diff --git a/lapack/single.cpp b/lapack/single.cpp index a64ed44e1..c7da3effa 100644 --- a/lapack/single.cpp +++ b/lapack/single.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" #include "eigenvalues.cpp" +#include "svd.cpp" diff --git a/lapack/svd.cpp b/lapack/svd.cpp new file mode 100644 index 000000000..ecac3bab1 --- /dev/null +++ b/lapack/svd.cpp @@ -0,0 +1,138 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "lapack_common.h" +#include +#include + +// computes the singular values/vectors a general M-by-N matrix A using divide-and-conquer +EIGEN_LAPACK_FUNC(gesdd,(char *jobz, int *m, int* n, Scalar* a, int *lda, RealScalar *s, Scalar *u, int *ldu, Scalar *vt, int *ldvt, Scalar* /*work*/, int* lwork, + EIGEN_LAPACK_ARG_IF_COMPLEX(RealScalar */*rwork*/) int * /*iwork*/, int *info)) +{ + // TODO exploit the work buffer + bool query_size = *lwork==-1; + int diag_size = (std::min)(*m,*n); + + *info = 0; + if(*jobz!='A' && *jobz!='S' && *jobz!='O' && *jobz!='N') *info = -1; + else if(*m<0) *info = -2; + else if(*n<0) *info = -3; + else if(*lda=*n && *ldvt<*n)) *info = -10; + + if(*info!=0) + { + int e = -*info; + return xerbla_(SCALAR_SUFFIX_UP"GESDD ", &e, 6); + } + + if(query_size) + { + *lwork = 0; + return 0; + } + + if(*n==0 || *m==0) + return 0; + + PlainMatrixType mat(*m,*n); + mat = matrix(a,*m,*n,*lda); + + int option = *jobz=='A' ? ComputeFullU|ComputeFullV + : *jobz=='S' ? ComputeThinU|ComputeThinV + : *jobz=='O' ? ComputeThinU|ComputeThinV + : 0; + + BDCSVD svd(mat,option); + + make_vector(s,diag_size) = svd.singularValues().head(diag_size); + + if(*jobz=='A') + { + matrix(u,*m,*m,*ldu) = svd.matrixU(); + matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='S') + { + matrix(u,*m,diag_size,*ldu) = svd.matrixU(); + matrix(vt,diag_size,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='O' && *m>=*n) + { + matrix(a,*m,*n,*lda) = svd.matrixU(); + matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='O') + { + matrix(u,*m,*m,*ldu) = svd.matrixU(); + matrix(a,diag_size,*n,*lda) = svd.matrixV().adjoint(); + } + + return 0; +} + +// computes the singular values/vectors a general M-by-N matrix A using two sided jacobi algorithm +EIGEN_LAPACK_FUNC(gesvd,(char *jobu, char *jobv, int *m, int* n, Scalar* a, int *lda, RealScalar *s, Scalar *u, int *ldu, Scalar *vt, int *ldvt, Scalar* /*work*/, int* lwork, + EIGEN_LAPACK_ARG_IF_COMPLEX(RealScalar */*rwork*/) int *info)) +{ + // TODO exploit the work buffer + bool query_size = *lwork==-1; + int diag_size = (std::min)(*m,*n); + + *info = 0; + if( *jobu!='A' && *jobu!='S' && *jobu!='O' && *jobu!='N') *info = -1; + else if((*jobv!='A' && *jobv!='S' && *jobv!='O' && *jobv!='N') + || (*jobu=='O' && *jobv=='O')) *info = -2; + else if(*m<0) *info = -3; + else if(*n<0) *info = -4; + else if(*lda svd(mat,option); + + make_vector(s,diag_size) = svd.singularValues().head(diag_size); + + if(*jobu=='A') matrix(u,*m,*m,*ldu) = svd.matrixU(); + else if(*jobu=='S') matrix(u,*m,diag_size,*ldu) = svd.matrixU(); + else if(*jobu=='O') matrix(a,*m,diag_size,*lda) = svd.matrixU(); + + if(*jobv=='A') matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + else if(*jobv=='S') matrix(vt,diag_size,*n,*ldvt) = svd.matrixV().adjoint(); + else if(*jobv=='O') matrix(a,diag_size,*n,*lda) = svd.matrixV().adjoint(); + + return 0; +} -- cgit v1.2.3 From feacfa5f83085a7289b4b2aefc3a64b576fea048 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 17 Oct 2014 15:32:06 +0200 Subject: Fix JacobiSVD wrt undeR/overflow by doing scaling prior to QR preconditioning --- Eigen/src/SVD/JacobiSVD.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 59f88a15a..7a8aa8d3f 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -692,21 +692,20 @@ JacobiSVD::compute(const MatrixType& matrix, unsig // limit for very small denormal numbers to be considered zero in order to avoid infinite loops (see bug 286) const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits::denorm_min(); + // Scaling factor to reduce over/under-flows + RealScalar scale = matrix.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */ - if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix)) + if(!m_qr_precond_morecols.run(*this, matrix/scale) && !m_qr_precond_morerows.run(*this, matrix/scale)) { - m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize); + m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale; if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows); if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize); if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols); if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize); } - - // Scaling factor to reduce over/under-flows - RealScalar scale = m_workMatrix.cwiseAbs().maxCoeff(); - if(scale==RealScalar(0)) scale = RealScalar(1); - m_workMatrix /= scale; /*** step 2. The main Jacobi SVD iteration. ***/ -- cgit v1.2.3 From 4b7c3abbea97c604d56f732cd5ba5f8ff8356814 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 17 Oct 2014 15:32:55 +0200 Subject: Fix D&C SVD wrt zero matrices --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index e8e795589..e2551cf88 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -194,7 +194,7 @@ public: }; //end class BDCSVD -// Methode to allocate ans initialize matrix and attributes +// Method to allocate and initialize matrix and attributes template void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) { @@ -215,24 +215,6 @@ void BDCSVD::allocate(Index rows, Index cols, unsigned int computati if (m_compV) m_naiveV = MatrixXr::Zero(m_diagSize, m_diagSize); }// end allocate -// Methode which compute the BDCSVD for the int -template<> -BDCSVD >& BDCSVD >::compute(const MatrixType& matrix, unsigned int computationOptions) -{ - allocate(matrix.rows(), matrix.cols(), computationOptions); - m_nonzeroSingularValues = 0; - m_computed = Matrix::Zero(rows(), cols()); - - m_singularValues.head(m_diagSize).setZero(); - - if (m_computeFullU) m_matrixU.setZero(rows(), rows()); - if (m_computeFullV) m_matrixV.setZero(cols(), cols()); - m_isInitialized = true; - return *this; -} - - -// Methode which compute the BDCSVD template BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) { @@ -612,6 +594,8 @@ void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec #endif #ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(U.allFinite()); + assert(V.allFinite()); assert((U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); assert((V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); assert(m_naiveU.allFinite()); @@ -836,8 +820,12 @@ void BDCSVD::perturbCol0 using std::sqrt; Index n = col0.size(); Index m = perm.size(); - Index last = perm(m-1); - + if(m==0) + { + zhat.setZero(); + return; + } + Index last = last = perm(m-1); // The offset permits to skip deflated entries while computing zhat for (Index k = 0; k < n; ++k) { -- cgit v1.2.3 From a13bc2220457224152e8e301c928f28013691d15 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 17 Oct 2014 15:34:39 +0200 Subject: Ignore automalically imported lapack source files --- .hgignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgignore b/.hgignore index e33ba2e9d..769a47f1f 100644 --- a/.hgignore +++ b/.hgignore @@ -30,3 +30,5 @@ log patch a a.* +lapack/testing +lapack/reference -- cgit v1.2.3 From a370b1f2e20804f0b99bcda1c3940f00300e4f90 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 17 Oct 2014 16:52:56 +0200 Subject: Fix SparseLU::absDeterminant and add respective unit test --- Eigen/src/SparseLU/SparseLU.h | 5 ++-- Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h | 4 ++-- test/sparse_solver.h | 33 ++++++++++++++++++++++++++ test/sparselu.cpp | 3 +++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index b02796293..d72d7f150 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h @@ -249,14 +249,13 @@ class SparseLU : public SparseSolverBase >, eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); // Initialize with the determinant of the row matrix Scalar det = Scalar(1.); - //Note that the diagonal blocks of U are stored in supernodes, + // Note that the diagonal blocks of U are stored in supernodes, // which are available in the L part :) for (Index j = 0; j < this->cols(); ++j) { for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) { - if(it.row() < j) continue; - if(it.row() == j) + if(it.index() == j) { det *= abs(it.value()); break; diff --git a/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h b/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h index 6b0b83e0b..e8ee35a94 100644 --- a/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +++ b/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h @@ -189,8 +189,8 @@ class MappedSuperNodalMatrix::InnerIterator m_idval(mat.colIndexPtr()[outer]), m_startidval(m_idval), m_endidval(mat.colIndexPtr()[outer+1]), - m_idrow(mat.rowIndexPtr()[outer]), - m_endidrow(mat.rowIndexPtr()[outer+1]) + m_idrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]]), + m_endidrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]+1]) {} inline InnerIterator& operator++() { diff --git a/test/sparse_solver.h b/test/sparse_solver.h index 8c8d7f939..b10eaebcc 100644 --- a/test/sparse_solver.h +++ b/test/sparse_solver.h @@ -133,7 +133,23 @@ void check_sparse_determinant(Solver& solver, const typename Solver::MatrixType& Scalar refDet = dA.determinant(); VERIFY_IS_APPROX(refDet,solver.determinant()); } +template +void check_sparse_abs_determinant(Solver& solver, const typename Solver::MatrixType& A, const DenseMat& dA) +{ + using std::abs; + typedef typename Solver::MatrixType Mat; + typedef typename Mat::Scalar Scalar; + + solver.compute(A); + if (solver.info() != Success) + { + std::cerr << "sparse solver testing: factorization failed (check_sparse_abs_determinant)\n"; + return; + } + Scalar refDet = abs(dA.determinant()); + VERIFY_IS_APPROX(refDet,solver.absDeterminant()); +} template int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typename Solver::MatrixType& halfA, DenseMat& dA, int maxSize = 300) @@ -333,3 +349,20 @@ template void check_sparse_square_determinant(Solver& solver) check_sparse_determinant(solver, A, dA); } } + +template void check_sparse_square_abs_determinant(Solver& solver) +{ + typedef typename Solver::MatrixType Mat; + typedef typename Mat::Scalar Scalar; + typedef Matrix DenseMatrix; + + // generate the problem + Mat A; + DenseMatrix dA; + generate_sparse_square_problem(solver, A, dA, 30); + A.makeCompressed(); + for (int i = 0; i < g_repeat; i++) { + check_sparse_abs_determinant(solver, A, dA); + } +} + diff --git a/test/sparselu.cpp b/test/sparselu.cpp index 37980defc..52371cb12 100644 --- a/test/sparselu.cpp +++ b/test/sparselu.cpp @@ -44,6 +44,9 @@ template void test_sparselu_T() check_sparse_square_solving(sparselu_colamd); check_sparse_square_solving(sparselu_amd); check_sparse_square_solving(sparselu_natural); + + check_sparse_square_abs_determinant(sparselu_colamd); + check_sparse_square_abs_determinant(sparselu_amd); } void test_sparselu() -- cgit v1.2.3 From 8838b0a1fff2cb01fab3a55312a16ae20daead13 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 19 Oct 2014 22:42:20 +0200 Subject: Fix SparseQR::rank for a completely empty matrix. --- Eigen/src/SparseQR/SparseQR.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index f6a9af672..879ac553d 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -378,6 +378,8 @@ void SparseQR::factorize(const MatrixType& mat) { RealScalar max2Norm = 0.0; for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm()); + if(max2Norm==RealScalar(0)) + max2Norm = RealScalar(1); pivotThreshold = 20 * (m + n) * max2Norm * NumTraits::epsilon(); } @@ -386,7 +388,7 @@ void SparseQR::factorize(const MatrixType& mat) Index nonzeroCol = 0; // Record the number of valid pivots m_Q.startVec(0); - + // Left looking rank-revealing QR factorization: compute a column of R and Q at a time for (Index col = 0; col < n; ++col) { @@ -554,7 +556,7 @@ void SparseQR::factorize(const MatrixType& mat) m_R.finalize(); m_R.makeCompressed(); m_isQSorted = false; - + m_nonzeropivots = nonzeroCol; if(nonzeroCol Date: Mon, 20 Oct 2014 10:48:40 +0200 Subject: Fix bug #894: the sign of LDLT was not re-initialized at each call of compute() --- Eigen/src/Cholesky/LDLT.h | 1 + test/cholesky.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index b4016cd6c..dfc473df1 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -433,6 +433,7 @@ LDLT& LDLT::compute(const MatrixType& a) m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); + m_sign = internal::ZeroSign; internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); diff --git a/test/cholesky.cpp b/test/cholesky.cpp index a883192ab..33e32a322 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -316,33 +316,35 @@ template void cholesky_definiteness(const MatrixType& m) { eigen_assert(m.rows() == 2 && m.cols() == 2); MatrixType mat; + LDLT ldlt(2); + { mat << 1, 0, 0, -1; - LDLT ldlt(mat); + ldlt.compute(mat); VERIFY(!ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } { mat << 1, 2, 2, 1; - LDLT ldlt(mat); + ldlt.compute(mat); VERIFY(!ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } { mat << 0, 0, 0, 0; - LDLT ldlt(mat); + ldlt.compute(mat); VERIFY(ldlt.isNegative()); VERIFY(ldlt.isPositive()); } { mat << 0, 0, 0, 1; - LDLT ldlt(mat); + ldlt.compute(mat); VERIFY(!ldlt.isNegative()); VERIFY(ldlt.isPositive()); } { mat << -1, 0, 0, 0; - LDLT ldlt(mat); + ldlt.compute(mat); VERIFY(ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } -- cgit v1.2.3 From b4a9b3f4960657bf2fc156ba5c25a3a32417b861 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 20 Oct 2014 11:04:32 +0200 Subject: Add unit tests for Rotation2D's inverse(), operator*, slerp, and fix regression wrt explicit ctor change --- Eigen/src/Geometry/Rotation2D.h | 6 +++--- test/geo_transformations.cpp | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Geometry/Rotation2D.h b/Eigen/src/Geometry/Rotation2D.h index 776c36144..4feb3d4d2 100644 --- a/Eigen/src/Geometry/Rotation2D.h +++ b/Eigen/src/Geometry/Rotation2D.h @@ -71,11 +71,11 @@ public: inline Scalar& angle() { return m_angle; } /** \returns the inverse rotation */ - inline Rotation2D inverse() const { return -m_angle; } + inline Rotation2D inverse() const { return Rotation2D(-m_angle); } /** Concatenates two rotations */ inline Rotation2D operator*(const Rotation2D& other) const - { return m_angle + other.m_angle; } + { return Rotation2D(m_angle + other.m_angle); } /** Concatenates two rotations */ inline Rotation2D& operator*=(const Rotation2D& other) @@ -93,7 +93,7 @@ public: * parameter \a t. It is in fact equivalent to a linear interpolation. */ inline Rotation2D slerp(const Scalar& t, const Rotation2D& other) const - { return m_angle * (1-t) + other.angle() * t; } + { return Rotation2D(m_angle * (1-t) + other.angle() * t); } /** \returns \c *this with scalar type casted to \a NewScalarType * diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index 1768d7b8a..e189217eb 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -98,7 +98,7 @@ template void transformations() Matrix3 matrot1, m; Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)); - Scalar s0 = internal::random(); + Scalar s0 = internal::random(), s1 = internal::random(); VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0); VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0); @@ -394,10 +394,21 @@ template void transformations() Rotation2D r2d1d = r2d1.template cast(); VERIFY_IS_APPROX(r2d1d.template cast(),r2d1); - t20 = Translation2(v20) * (Rotation2D(s0) * Eigen::Scaling(s0)); - t21 = Translation2(v20) * Rotation2D(s0) * Eigen::Scaling(s0); + Rotation2D R0(s0), R1(s1); + + t20 = Translation2(v20) * (R0 * Eigen::Scaling(s0)); + t21 = Translation2(v20) * R0 * Eigen::Scaling(s0); + VERIFY_IS_APPROX(t20,t21); + + t20 = Translation2(v20) * (R0 * R0.inverse() * Eigen::Scaling(s0)); + t21 = Translation2(v20) * Eigen::Scaling(s0); VERIFY_IS_APPROX(t20,t21); + VERIFY_IS_APPROX(s0, (R0.slerp(0, R1)).angle()); + VERIFY_IS_APPROX(s1, (R0.slerp(1, R1)).angle()); + VERIFY_IS_APPROX(s0, (R0.slerp(0.5, R0)).angle()); + VERIFY_IS_APPROX(Scalar(0), (R0.slerp(0.5, R0.inverse())).angle()); + // check basic features { Rotation2D r1; // default ctor -- cgit v1.2.3 From aa5f79206fb632d141c3555338f89f59d1bb4633 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 20 Oct 2014 11:38:51 +0200 Subject: Fix bug #859: pexp(NaN) returned Inf instead of NaN --- Eigen/src/Core/arch/SSE/MathFunctions.h | 2 +- test/main.h | 20 ++++++++++++++++++++ test/packetmath.cpp | 6 ++++++ test/stable_norm.cpp | 20 -------------------- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Eigen/src/Core/arch/SSE/MathFunctions.h b/Eigen/src/Core/arch/SSE/MathFunctions.h index 8f78b3a6c..b549e4870 100644 --- a/Eigen/src/Core/arch/SSE/MathFunctions.h +++ b/Eigen/src/Core/arch/SSE/MathFunctions.h @@ -167,7 +167,7 @@ Packet4f pexp(const Packet4f& _x) emm0 = _mm_cvttps_epi32(fx); emm0 = _mm_add_epi32(emm0, p4i_0x7f); emm0 = _mm_slli_epi32(emm0, 23); - return pmul(y, Packet4f(_mm_castsi128_ps(emm0))); + return pmax(pmul(y, Packet4f(_mm_castsi128_ps(emm0))), _x); } template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet2d pexp(const Packet2d& _x) diff --git a/test/main.h b/test/main.h index 371c7e602..adf4adb31 100644 --- a/test/main.h +++ b/test/main.h @@ -432,6 +432,26 @@ void randomPermutationVector(PermutationVectorType& v, typename PermutationVecto } } +template bool isNotNaN(const T& x) +{ + return x==x; +} + +template bool isNaN(const T& x) +{ + return x!=x; +} + +template bool isInf(const T& x) +{ + return x > NumTraits::highest(); +} + +template bool isMinusInf(const T& x) +{ + return x < NumTraits::lowest(); +} + } // end namespace Eigen template struct GetDifferentType; diff --git a/test/packetmath.cpp b/test/packetmath.cpp index e716d6d9a..a4166d868 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -297,6 +297,12 @@ template void packetmath_real() data2[i] = internal::random(-87,88); } CHECK_CWISE1_IF(internal::packet_traits::HasExp, std::exp, internal::pexp); + { + data1[0] = std::numeric_limits::quiet_NaN(); + packet_helper::HasExp,Packet> h; + h.store(data2, internal::pexp(h.load(data1))); + VERIFY(isNaN(data2[0])); + } for (int i=0; i bool isNotNaN(const T& x) -{ - return x==x; -} - -template bool isNaN(const T& x) -{ - return x!=x; -} - -template bool isInf(const T& x) -{ - return x > NumTraits::highest(); -} - -template bool isMinusInf(const T& x) -{ - return x < NumTraits::lowest(); -} - // workaround aggressive optimization in ICC template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } -- cgit v1.2.3 From 84aaa03182f6e31fa251d93730d628975c44207c Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Mon, 20 Oct 2014 13:13:43 +0200 Subject: Addendum to bug #859: pexp(NaN) for double did not return NaN, also, plog(NaN) did not return NaN. psqrt(NaN) and psqrt(-1) shall return NaN if EIGEN_FAST_MATH==0 --- Eigen/src/Core/arch/SSE/MathFunctions.h | 4 ++-- test/packetmath.cpp | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Eigen/src/Core/arch/SSE/MathFunctions.h b/Eigen/src/Core/arch/SSE/MathFunctions.h index b549e4870..9ffba5b41 100644 --- a/Eigen/src/Core/arch/SSE/MathFunctions.h +++ b/Eigen/src/Core/arch/SSE/MathFunctions.h @@ -52,7 +52,7 @@ Packet4f plog(const Packet4f& _x) Packet4i emm0; - Packet4f invalid_mask = _mm_cmplt_ps(x, _mm_setzero_ps()); + Packet4f invalid_mask = _mm_cmpnge_ps(x, _mm_setzero_ps()); // not greater equal is true if x is NaN Packet4f iszero_mask = _mm_cmpeq_ps(x, _mm_setzero_ps()); x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */ @@ -241,7 +241,7 @@ Packet2d pexp(const Packet2d& _x) emm0 = _mm_add_epi32(emm0, p4i_1023_0); emm0 = _mm_slli_epi32(emm0, 20); emm0 = _mm_shuffle_epi32(emm0, _MM_SHUFFLE(1,2,0,3)); - return pmul(x, Packet2d(_mm_castsi128_pd(emm0))); + return pmax(pmul(x, Packet2d(_mm_castsi128_pd(emm0))), _x); } /* evaluation of 4 sines at onces, using SSE2 intrinsics. diff --git a/test/packetmath.cpp b/test/packetmath.cpp index a4166d868..ee0502f69 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -311,8 +311,22 @@ template void packetmath_real() } if(internal::random(0,1)<0.1) data1[internal::random(0, PacketSize)] = 0; - CHECK_CWISE1_IF(internal::packet_traits::HasLog, std::log, internal::plog); CHECK_CWISE1_IF(internal::packet_traits::HasSqrt, std::sqrt, internal::psqrt); + CHECK_CWISE1_IF(internal::packet_traits::HasLog, std::log, internal::plog); + { + data1[0] = std::numeric_limits::quiet_NaN(); + packet_helper::HasLog,Packet> h; + h.store(data2, internal::plog(h.load(data1))); + VERIFY(isNaN(data2[0])); + data1[0] = -1.0f; + h.store(data2, internal::plog(h.load(data1))); + VERIFY(isNaN(data2[0])); +#if !EIGEN_FAST_MATH + h.store(data2, internal::psqrt(h.load(data1))); + VERIFY(isNaN(data2[0])); + VERIFY(isNaN(data2[1])); +#endif + } } template void packetmath_notcomplex() -- cgit v1.2.3 From 973e6a035f0207e47bf8face584f002ff169ced1 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 20 Oct 2014 14:07:08 +0200 Subject: bug #718: Introduce a compilation error when using the wrong InnerIterator type with a SparseVector --- Eigen/src/SparseCore/SparseVector.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h index dfbb2be2e..8b696a476 100644 --- a/Eigen/src/SparseCore/SparseVector.h +++ b/Eigen/src/SparseCore/SparseVector.h @@ -386,6 +386,11 @@ class SparseVector::InnerIterator const internal::CompressedStorage& m_data; Index m_id; const Index m_end; + private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const SparseMatrixBase&,Index outer=0); }; template -- cgit v1.2.3 From c12b7896d0ddf95e8f060c93a5cf2fcfa1e6865c Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Mon, 20 Oct 2014 14:23:11 +0200 Subject: bug #766: Check minimum CUDA version --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4132e6481..63ed2c7a4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -306,7 +306,7 @@ endif() option(EIGEN_TEST_NVCC "Enable NVCC support in unit tests" OFF) if(EIGEN_TEST_NVCC) -find_package(CUDA) +find_package(CUDA 5.0) if(CUDA_FOUND) set(CUDA_PROPAGATE_HOST_FLAGS OFF) -- cgit v1.2.3 From fe57b2f963da832d14f4d7b6d4a9554ceef26e36 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 20 Oct 2014 15:55:32 +0200 Subject: bug #701: workaround (min) and (max) blocking ADL by introducing numext::mini and numext::maxi internal functions and a EIGEN_NOT_A_MACRO macro. --- Eigen/src/Cholesky/LDLT.h | 3 +-- Eigen/src/Core/Diagonal.h | 5 ++--- Eigen/src/Core/Fuzzy.h | 3 +-- Eigen/src/Core/GenericPacketMath.h | 4 ++-- Eigen/src/Core/MathFunctions.h | 16 ++++++++++++++++ Eigen/src/Core/StableNorm.h | 10 +++------- Eigen/src/Core/functors/BinaryFunctors.h | 6 ++---- Eigen/src/Core/util/Macros.h | 5 +++++ Eigen/src/Eigenvalues/EigenSolver.h | 6 ++---- Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 3 +-- Eigen/src/Geometry/Quaternion.h | 3 +-- Eigen/src/SVD/JacobiSVD.h | 3 +-- Eigen/src/SparseCore/SparseFuzzy.h | 3 +-- Eigen/src/SparseQR/SparseQR.h | 3 +-- unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h | 1 - unsupported/Eigen/src/BDCSVD/BDCSVD.h | 8 +++----- .../Eigen/src/IterativeSolvers/IncompleteCholesky.h | 3 +-- 17 files changed, 43 insertions(+), 42 deletions(-) diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index dfc473df1..5acbf4651 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -488,11 +488,10 @@ void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) cons // dst = D^-1 (L^-1 P b) // more precisely, use pseudo-inverse of D (see bug 241) using std::abs; - EIGEN_USING_STD_MATH(max); const typename Diagonal::RealReturnType vecD(vectorD()); // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon // as motivated by LAPACK's xGELSS: - // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); + // RealScalar tolerance = numext::maxi(vectorD.array().abs().maxCoeff() *NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest // diagonal element is not well justified and to numerical issues in some cases. // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. diff --git a/Eigen/src/Core/Diagonal.h b/Eigen/src/Core/Diagonal.h index 6ffc0c762..26a58d664 100644 --- a/Eigen/src/Core/Diagonal.h +++ b/Eigen/src/Core/Diagonal.h @@ -77,9 +77,8 @@ template class Diagonal EIGEN_DEVICE_FUNC inline Index rows() const { - EIGEN_USING_STD_MATH(min); - return m_index.value()<0 ? (min)(Index(m_matrix.cols()),Index(m_matrix.rows()+m_index.value())) - : (min)(Index(m_matrix.rows()),Index(m_matrix.cols()-m_index.value())); + return m_index.value()<0 ? numext::mini(Index(m_matrix.cols()),Index(m_matrix.rows()+m_index.value())) + : numext::mini(Index(m_matrix.rows()),Index(m_matrix.cols()-m_index.value())); } EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index 8cd069a0d..3e403a09d 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -22,10 +22,9 @@ struct isApprox_selector EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { - EIGEN_USING_STD_MATH(min); typename internal::nested_eval::type nested(x); typename internal::nested_eval::type otherNested(y); - return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index a1fcb82fb..065ccf7ac 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h @@ -126,12 +126,12 @@ pdiv(const Packet& a, /** \internal \returns the min of \a a and \a b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmin(const Packet& a, - const Packet& b) { EIGEN_USING_STD_MATH(min); return (min)(a, b); } + const Packet& b) { return numext::mini(a, b); } /** \internal \returns the max of \a a and \a b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmax(const Packet& a, - const Packet& b) { EIGEN_USING_STD_MATH(max); return (max)(a, b); } + const Packet& b) { return numext::maxi(a, b); } /** \internal \returns the absolute value of \a a */ template EIGEN_DEVICE_FUNC inline Packet diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 73859b0ee..071c234c2 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -591,6 +591,22 @@ inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() ****************************************************************************/ namespace numext { + +template +EIGEN_DEVICE_FUNC +inline T mini(const T& x, const T& y) +{ + using std::min; + return min EIGEN_NOT_A_MACRO (x,y); +} + +template +EIGEN_DEVICE_FUNC +inline T maxi(const T& x, const T& y) +{ + using std::max; + return max EIGEN_NOT_A_MACRO (x,y); +} template EIGEN_DEVICE_FUNC diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index 64d43e1b1..0b7e39827 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -17,7 +17,6 @@ namespace internal { template inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& scale, Scalar& invScale) { - using std::max; Scalar maxCoeff = bl.cwiseAbs().maxCoeff(); if(maxCoeff>scale) @@ -58,8 +57,6 @@ blueNorm_impl(const EigenBase& _vec) typedef typename Derived::RealScalar RealScalar; typedef typename Derived::Index Index; using std::pow; - EIGEN_USING_STD_MATH(min); - EIGEN_USING_STD_MATH(max); using std::sqrt; using std::abs; const Derived& vec(_vec.derived()); @@ -136,8 +133,8 @@ blueNorm_impl(const EigenBase& _vec) } else return sqrt(amed); - asml = (min)(abig, amed); - abig = (max)(abig, amed); + asml = numext::mini(abig, amed); + abig = numext::maxi(abig, amed); if(asml <= abig*relerr) return abig; else @@ -160,7 +157,6 @@ template inline typename NumTraits::Scalar>::Real MatrixBase::stableNorm() const { - EIGEN_USING_STD_MATH(min); using std::sqrt; const Index blockSize = 4096; RealScalar scale(0); @@ -174,7 +170,7 @@ MatrixBase::stableNorm() const if (bi>0) internal::stable_norm_kernel(this->head(bi), ssq, scale, invScale); for (; bisegment(bi,(min)(blockSize, n - bi)).template forceAlignedAccessIf(), ssq, scale, invScale); + internal::stable_norm_kernel(this->segment(bi,numext::mini(blockSize, n - bi)).template forceAlignedAccessIf(), ssq, scale, invScale); return scale * sqrt(ssq); } diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index 157d075a7..9c96181c7 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -115,7 +115,7 @@ struct functor_traits > { */ template struct scalar_min_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { EIGEN_USING_STD_MATH(min); return (min)(a, b); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return numext::mini(a, b); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmin(a,b); } @@ -138,7 +138,7 @@ struct functor_traits > { */ template struct scalar_max_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { EIGEN_USING_STD_MATH(max); return (max)(a, b); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return numext::maxi(a, b); } template EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const { return internal::pmax(a,b); } @@ -164,8 +164,6 @@ template struct scalar_hypot_op { // typedef typename NumTraits::Real result_type; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const { - EIGEN_USING_STD_MATH(max); - EIGEN_USING_STD_MATH(min); using std::sqrt; Scalar p, qp; if(_x>_y) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index f9b908e22..c09854951 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -86,6 +86,11 @@ #define EIGEN_ALIGN 0 #endif + +// This macro can be used to prevent from macro expansion, e.g.: +// std::max EIGNE_NOT_A_MACRO(a,b) +#define EIGEN_NOT_A_MACRO + // EIGEN_ALIGN_STATICALLY is the true test whether we want to align arrays on the stack or not. It takes into account both the user choice to explicitly disable // alignment (EIGEN_DONT_ALIGN_STATICALLY) and the architecture config (EIGEN_ARCH_WANTS_STACK_ALIGNMENT). Henceforth, only EIGEN_ALIGN_STATICALLY should be used. #if EIGEN_ARCH_WANTS_STACK_ALIGNMENT && !defined(EIGEN_DONT_ALIGN_STATICALLY) diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index 8a83b85bb..9372021ff 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -368,7 +368,6 @@ EigenSolver::compute(const MatrixType& matrix, bool computeEigenvect { using std::sqrt; using std::abs; - using std::max; using numext::isfinite; eigen_assert(matrix.cols() == matrix.rows()); @@ -409,7 +408,7 @@ EigenSolver::compute(const MatrixType& matrix, bool computeEigenvect { Scalar t0 = m_matT.coeff(i+1, i); Scalar t1 = m_matT.coeff(i, i+1); - Scalar maxval = (max)(abs(p),(max)(abs(t0),abs(t1))); + Scalar maxval = numext::maxi(abs(p),numext::maxi(abs(t0),abs(t1))); t0 /= maxval; t1 /= maxval; Scalar p0 = p/maxval; @@ -600,8 +599,7 @@ void EigenSolver::doComputeEigenvectors() } // Overflow control - EIGEN_USING_STD_MATH(max); - Scalar t = (max)(abs(m_matT.coeff(i,n-1)),abs(m_matT.coeff(i,n))); + Scalar t = numext::maxi(abs(m_matT.coeff(i,n-1)),abs(m_matT.coeff(i,n))); if ((eps * t) * t > Scalar(1)) m_matT.block(i, n-1, size-i, 2) /= t; diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 1dd2ab45b..54f60b197 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -732,7 +732,6 @@ struct direct_selfadjoint_eigenvalues EIGEN_DEVICE_FUNC static inline void run(SolverType& solver, const MatrixType& mat, int options) { - EIGEN_USING_STD_MATH(max) EIGEN_USING_STD_MATH(sqrt); eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows()); @@ -746,7 +745,7 @@ struct direct_selfadjoint_eigenvalues // map the matrix coefficients to [-1:1] to avoid over- and underflow. Scalar scale = mat.cwiseAbs().maxCoeff(); - scale = (max)(scale,Scalar(1)); + scale = numext::maxi(scale,Scalar(1)); MatrixType scaledMat = mat / scale; // Compute the eigenvalues diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h index 216e5b12f..508eba767 100644 --- a/Eigen/src/Geometry/Quaternion.h +++ b/Eigen/src/Geometry/Quaternion.h @@ -571,7 +571,6 @@ template template inline Derived& QuaternionBase::setFromTwoVectors(const MatrixBase& a, const MatrixBase& b) { - EIGEN_USING_STD_MATH(max); using std::sqrt; Vector3 v0 = a.normalized(); Vector3 v1 = b.normalized(); @@ -587,7 +586,7 @@ inline Derived& QuaternionBase::setFromTwoVectors(const MatrixBase::dummy_precision()) { - c = (max)(c,Scalar(-1)); + c = numext::maxi(c,Scalar(-1)); Matrix m; m << v0.transpose(), v1.transpose(); JacobiSVD > svd(m, ComputeFullV); Vector3 axis = svd.matrixV().col(2); diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 7a8aa8d3f..0f7e5b8fe 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -723,8 +723,7 @@ JacobiSVD::compute(const MatrixType& matrix, unsig // if this 2x2 sub-matrix is not diagonal already... // notice that this comparison will evaluate to false if any NaN is involved, ensuring that NaN's don't // keep us iterating forever. Similarly, small denormal numbers are considered zero. - EIGEN_USING_STD_MATH(max); - RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), + RealScalar threshold = numext::maxi(considerAsZero, precision * numext::maxi(abs(m_workMatrix.coeff(p,p)), abs(m_workMatrix.coeff(q,q)))); // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791) if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold) diff --git a/Eigen/src/SparseCore/SparseFuzzy.h b/Eigen/src/SparseCore/SparseFuzzy.h index a76c1a5e0..7d47eb94d 100644 --- a/Eigen/src/SparseCore/SparseFuzzy.h +++ b/Eigen/src/SparseCore/SparseFuzzy.h @@ -16,13 +16,12 @@ template template bool SparseMatrixBase::isApprox(const SparseMatrixBase& other, const RealScalar &prec) const { - using std::min; const typename internal::nested_eval::type actualA(derived()); typename internal::conditional::type, const PlainObject>::type actualB(other.derived()); - return (actualA - actualB).squaredNorm() <= prec * prec * (min)(actualA.squaredNorm(), actualB.squaredNorm()); + return (actualA - actualB).squaredNorm() <= prec * prec * numext::mini(actualA.squaredNorm(), actualB.squaredNorm()); } } // end namespace Eigen diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index 879ac553d..133211488 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h @@ -325,7 +325,6 @@ template void SparseQR::factorize(const MatrixType& mat) { using std::abs; - using std::max; eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step"); Index m = mat.rows(); @@ -377,7 +376,7 @@ void SparseQR::factorize(const MatrixType& mat) if(m_useDefaultThreshold) { RealScalar max2Norm = 0.0; - for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm()); + for (int j = 0; j < n; j++) max2Norm = numext::maxi(max2Norm, m_pmat.col(j).norm()); if(max2Norm==RealScalar(0)) max2Norm = RealScalar(1); pivotThreshold = 20 * (m + n) * max2Norm * NumTraits::epsilon(); diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h index 590797973..8336c2644 100644 --- a/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h +++ b/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h @@ -593,7 +593,6 @@ inline const AutoDiffScalar::Scalar,D atan2(const AutoDiffScalar& a, const AutoDiffScalar& b) { using std::atan2; - using std::max; typedef typename internal::traits::Scalar Scalar; typedef AutoDiffScalar > PlainADS; PlainADS ret; diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index e2551cf88..ac71b0aa8 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -649,7 +649,6 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia { using std::abs; using std::swap; - using std::max; Index n = col0.size(); Index actual_n = n; @@ -728,7 +727,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia // rational interpolation: fit a function of the form a / mu + b through the two previous // iterates and use its zero to compute the next iterate bool useBisection = fPrev*fCur>0; - while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (max)(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) + while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits::epsilon() * numext::maxi(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) { ++m_numIters; @@ -779,7 +778,7 @@ void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& dia #endif eigen_internal_assert(fLeft * fRight < 0); - while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (max)(abs(leftShifted), abs(rightShifted))) + while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * numext::maxi(abs(leftShifted), abs(rightShifted))) { RealScalar midShifted = (leftShifted + rightShifted) / 2; RealScalar fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift); @@ -981,7 +980,6 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index { using std::sqrt; using std::abs; - using std::max; const Index length = lastCol + 1 - firstCol; Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); @@ -990,7 +988,7 @@ void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff(); RealScalar epsilon_strict = NumTraits::epsilon() * maxDiag; - RealScalar epsilon_coarse = 8 * NumTraits::epsilon() * (max)(col0.cwiseAbs().maxCoeff(), maxDiag); + RealScalar epsilon_coarse = 8 * NumTraits::epsilon() * numext::maxi(col0.cwiseAbs().maxCoeff(), maxDiag); #ifdef EIGEN_BDCSVD_SANITY_CHECKS assert(m_naiveU.allFinite()); diff --git a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h index dd43de6b3..35cfa315d 100644 --- a/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h +++ b/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h @@ -126,7 +126,6 @@ template void IncompleteCholesky::factorize(const _MatrixType& mat) { using std::sqrt; - using std::min; eigen_assert(m_analysisIsOk && "analyzePattern() should be called first"); // Dropping strategies : Keep only the p largest elements per column, where p is the number of elements in the column of the original matrix. Other strategies will be added @@ -160,7 +159,7 @@ void IncompleteCholesky::factorize(const _MatrixType for (int j = 0; j < n; j++){ for (int k = colPtr[j]; k < colPtr[j+1]; k++) vals[k] /= (m_scal(j) * m_scal(rowIdx[k])); - mindiag = (min)(vals[colPtr[j]], mindiag); + mindiag = numext::mini(vals[colPtr[j]], mindiag); } if(mindiag < Scalar(0.)) m_shift = m_shift - mindiag; -- cgit v1.2.3 From a303b6a733509db8c533e94e7a903ad7d28fef8d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 20 Oct 2014 16:46:47 +0200 Subject: bug #670: add unit test for mapped input in sparse solver. --- test/sparse_solver.h | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/sparse_solver.h b/test/sparse_solver.h index b10eaebcc..ee350d561 100644 --- a/test/sparse_solver.h +++ b/test/sparse_solver.h @@ -15,6 +15,7 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; + typedef typename Mat::Index Index; DenseRhs refX = dA.lu().solve(db); { @@ -35,8 +36,8 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, return; } VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!"); - VERIFY(x.isApprox(refX,test_precision())); + x.setZero(); // test the analyze/factorize API solver.analyzePattern(A); @@ -54,8 +55,31 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, return; } VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!"); - VERIFY(x.isApprox(refX,test_precision())); + + + x.setZero(); + // test with Map + MappedSparseMatrix Am(A.rows(), A.cols(), A.nonZeros(), const_cast(A.outerIndexPtr()), const_cast(A.innerIndexPtr()), const_cast(A.valuePtr())); + solver.compute(Am); + if (solver.info() != Success) + { + std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n"; + exit(0); + return; + } + DenseRhs dx(refX); + dx.setZero(); + Map xm(dx.data(), dx.rows(), dx.cols()); + Map bm(db.data(), db.rows(), db.cols()); + xm = solver.solve(bm); + if (solver.info() != Success) + { + std::cerr << "sparse solver testing: solving failed\n"; + return; + } + VERIFY(oldb.isApprox(bm) && "sparse solver testing: the rhs should not be modified!"); + VERIFY(xm.isApprox(refX,test_precision())); } // test dense Block as the result and rhs: -- cgit v1.2.3 From 87524922dcb1e23eccccdf8ff6df2a1b9bee6308 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Tue, 21 Oct 2014 18:08:50 +0000 Subject: check for __ARM_NEON instead as it's defined in arm64 as well --- Eigen/Core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/Core b/Eigen/Core index adab50b4a..2174c6bf8 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -180,7 +180,7 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON__ + #elif defined __ARM_NEON #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include -- cgit v1.2.3 From 0f65f2762de6f2da4d88d19175560a1a2788ebd7 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Tue, 21 Oct 2014 18:10:01 +0000 Subject: add EIGEN_TEST_NEON64, but it's a dummy, AArch64 implies NEON support so extra CXXFLAGS are needed --- CMakeLists.txt | 8 ++++++++ cmake/EigenTesting.cmake | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea42cc8db..05d92babe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,6 +231,14 @@ if(NOT MSVC) message(STATUS "Enabling NEON in tests/examples") endif() + option(EIGEN_TEST_NEON64 "Enable/Disable Neon in tests/examples" OFF) + if(EIGEN_TEST_NEON64) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + message(STATUS "Enabling NEON in tests/examples") + endif() + + + check_cxx_compiler_flag("-fopenmp" COMPILER_SUPPORT_OPENMP) if(COMPILER_SUPPORT_OPENMP) option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 3ed002a87..3eb4e4c07 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -294,6 +294,12 @@ macro(ei_testing_print_summary) message(STATUS "ARM NEON: Using architecture defaults") endif() + if(EIGEN_TEST_NEON64) + message(STATUS "ARMv8 NEON: ON") + else() + message(STATUS "ARMv8 NEON: Using architecture defaults") + endif() + endif() # vectorization / alignment options message(STATUS "\n${EIGEN_TESTING_SUMMARY}") @@ -424,6 +430,8 @@ macro(ei_get_cxxflags VAR) ei_is_64bit_env(IS_64BIT_ENV) if(EIGEN_TEST_NEON) set(${VAR} NEON) + elseif(EIGEN_TEST_NEON64) + set(${VAR} NEON) elseif(EIGEN_TEST_VSX) set(${VAR} VSX) elseif(EIGEN_TEST_ALTIVEC) -- cgit v1.2.3 From b50861939217d2c6c92362e2eea59866b5386b33 Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Tue, 21 Oct 2014 18:10:33 +0000 Subject: working 64-bit support in PacketMath.h, Complex.h needed --- Eigen/src/Core/arch/NEON/PacketMath.h | 174 +++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index 0504c095c..e3a13d93a 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -20,10 +20,18 @@ namespace internal { #define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 8 #endif +#ifndef EIGEN_HAS_FUSED_MADD +#define EIGEN_HAS_FUSED_MADD 1 +#endif + +#ifndef EIGEN_HAS_FUSE_CJMADD +#define EIGEN_HAS_FUSE_CJMADD 1 +#endif + // FIXME NEON has 16 quad registers, but since the current register allocator // is so bad, it is much better to reduce it to 8 #ifndef EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS -#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 8 +#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 #endif typedef float32x4_t Packet4f; @@ -71,6 +79,7 @@ template<> struct packet_traits : default_packet_traits Vectorizable = 1, AlignedOnScalar = 1, size = 4, + HasHalfPacket=0, HasDiv = 1, // FIXME check the Has* @@ -136,6 +145,7 @@ template<> EIGEN_STRONG_INLINE Packet4i pmul(const Packet4i& a, const template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const Packet4f& b) { +#ifndef __aarch64__ Packet4f inv, restep, div; // NEON does not offer a divide instruction, we have to do a reciprocal approximation @@ -154,7 +164,11 @@ template<> EIGEN_STRONG_INLINE Packet4f pdiv(const Packet4f& a, const div = vmulq_f32(a, inv); return div; +#else + return vdivq_f32(a,b); +#endif } + template<> EIGEN_STRONG_INLINE Packet4i pdiv(const Packet4i& /*a*/, const Packet4i& /*b*/) { eigen_assert(false && "packet integer division are not supported by NEON"); return pset1(0); @@ -472,6 +486,164 @@ ptranspose(PacketBlock& kernel) { kernel.packet[3] = vcombine_s32(vget_high_s32(tmp1.val[1]), vget_high_s32(tmp2.val[1])); } +//---------- double ---------- +#ifdef __aarch64__ + +typedef float64x2_t Packet2d; + +template<> struct packet_traits : default_packet_traits +{ + typedef Packet2d type; + typedef Packet2d half; + enum { + Vectorizable = 1, + AlignedOnScalar = 1, + size = 2, + HasHalfPacket=0, + + HasDiv = 1, + // FIXME check the Has* + HasSin = 0, + HasCos = 0, + HasLog = 0, + HasExp = 0, + HasSqrt = 0 + }; +}; + +template<> struct unpacket_traits { typedef double type; enum {size=2}; typedef Packet2d half; }; + +template<> EIGEN_STRONG_INLINE Packet2d pset1(const double& from) { return vdupq_n_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d plset(const double& a) +{ + Packet2d countdown = EIGEN_INIT_NEON_PACKET2(0, 1); + return vaddq_f64(pset1(a), countdown); +} +template<> EIGEN_STRONG_INLINE Packet2d padd(const Packet2d& a, const Packet2d& b) { return vaddq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d psub(const Packet2d& a, const Packet2d& b) { return vsubq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pnegate(const Packet2d& a) { return vnegq_f64(a); } + +template<> EIGEN_STRONG_INLINE Packet2d pconj(const Packet2d& a) { return a; } + +template<> EIGEN_STRONG_INLINE Packet2d pmul(const Packet2d& a, const Packet2d& b) { return vmulq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pdiv(const Packet2d& a, const Packet2d& b) { return vdivq_f64(a,b); } + +// for some weird raisons, it has to be overloaded for packet of integers +template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vmlaq_f64(c,a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pmin(const Packet2d& a, const Packet2d& b) { return vminq_f64(a,b); } + +template<> EIGEN_STRONG_INLINE Packet2d pmax(const Packet2d& a, const Packet2d& b) { return vmaxq_f64(a,b); } + +// Logical Operations are not supported for float, so we have to reinterpret casts using NEON intrinsics +template<> EIGEN_STRONG_INLINE Packet2d pand(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d por(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pxor(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pandnot(const Packet2d& a, const Packet2d& b) +{ + return vreinterpretq_f64_u64(vbicq_u64(vreinterpretq_u64_f64(a),vreinterpretq_u64_f64(b))); +} + +template<> EIGEN_STRONG_INLINE Packet2d pload(const double* from) { EIGEN_DEBUG_ALIGNED_LOAD return vld1q_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return vld1q_f64(from); } + +template<> EIGEN_STRONG_INLINE Packet2d ploaddup(const double* from) +{ + return vld1q_dup_f64(from); +} +template<> EIGEN_STRONG_INLINE void pstore(double* to, const Packet2d& from) { EIGEN_DEBUG_ALIGNED_STORE vst1q_f64(to, from); } + +template<> EIGEN_STRONG_INLINE void pstoreu(double* to, const Packet2d& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f64(to, from); } + +template<> EIGEN_DEVICE_FUNC inline Packet2d pgather(const double* from, DenseIndex stride) +{ + Packet2d res; + res = vsetq_lane_f64(from[0*stride], res, 0); + res = vsetq_lane_f64(from[1*stride], res, 1); + return res; +} +template<> EIGEN_DEVICE_FUNC inline void pscatter(double* to, const Packet2d& from, DenseIndex stride) +{ + to[stride*0] = vgetq_lane_f64(from, 0); + to[stride*1] = vgetq_lane_f64(from, 1); +} +template<> EIGEN_STRONG_INLINE void prefetch(const double* addr) { EIGEN_ARM_PREFETCH(addr); } + +// FIXME only store the 2 first elements ? +template<> EIGEN_STRONG_INLINE double pfirst(const Packet2d& a) { return vgetq_lane_f64(a, 0); } + +template<> EIGEN_STRONG_INLINE Packet2d preverse(const Packet2d& a) { return vcombine_f64(vget_high_f64(a), vget_low_f64(a)); } + +template<> EIGEN_STRONG_INLINE Packet2d pabs(const Packet2d& a) { return vabsq_f64(a); } + +template<> EIGEN_STRONG_INLINE double predux(const Packet2d& a) { return vget_low_f64(a) + vget_high_f64(a); } + +template<> EIGEN_STRONG_INLINE Packet2d preduxp(const Packet2d* vecs) +{ + float64x2_t trn1, trn2; + + // NEON zip performs interleaving of the supplied vectors. + // We perform two interleaves in a row to acquire the transposed vector + trn1 = vzip1q_f64(vecs[0], vecs[1]); + trn2 = vzip2q_f64(vecs[0], vecs[1]); + + // Do the addition of the resulting vectors + return vaddq_f64(trn1, trn2); +} +// Other reduction functions: +// mul +template<> EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) { return vget_low_f64(a) * vget_high_f64(a); } + +// min +template<> EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) { return vgetq_lane_f64(vpminq_f64(a, a), 0); } + +// max +template<> EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) { return vgetq_lane_f64(vpmaxq_f64(a, a), 0); } + +// this PALIGN_NEON business is to work around a bug in LLVM Clang 3.0 causing incorrect compilation errors, +// see bug 347 and this LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=11074 +#define PALIGN_NEON(Offset,Type,Command) \ +template<>\ +struct palign_impl\ +{\ + EIGEN_STRONG_INLINE static void run(Type& first, const Type& second)\ + {\ + if (Offset!=0)\ + first = Command(first, second, Offset);\ + }\ +};\ + +PALIGN_NEON(0,Packet2d,vextq_f64) +PALIGN_NEON(1,Packet2d,vextq_f64) +#undef PALIGN_NEON + +EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& kernel) { + float64x2_t trn1 = vzip1q_f64(kernel.packet[0], kernel.packet[1]); + float64x2_t trn2 = vzip2q_f64(kernel.packet[0], kernel.packet[1]); + + kernel.packet[0] = trn1; + kernel.packet[1] = trn2; +} +#endif // __aarch64__ + } // end namespace internal } // end namespace Eigen -- cgit v1.2.3 From cf09c5f687c171d2e8b760358a4d48da1c010ce0 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 21 Oct 2014 20:40:09 +0200 Subject: Prevent CUDA `calling a __host__ function from a __host__ __device__ function is not allowed` error. --- Eigen/src/Core/MathFunctions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 071c234c2..4c5fc1cae 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -596,7 +596,7 @@ template EIGEN_DEVICE_FUNC inline T mini(const T& x, const T& y) { - using std::min; + EIGEN_USING_STD_MATH(min); return min EIGEN_NOT_A_MACRO (x,y); } @@ -604,7 +604,7 @@ template EIGEN_DEVICE_FUNC inline T maxi(const T& x, const T& y) { - using std::max; + EIGEN_USING_STD_MATH(max); return max EIGEN_NOT_A_MACRO (x,y); } -- cgit v1.2.3 From fae4fd7a26ee31fbf1eaa5d3581916ccee3c004f Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Wed, 22 Oct 2014 07:39:49 +0000 Subject: Added ARMv8 support --- Eigen/src/Core/arch/NEON/Complex.h | 194 +++++++++++++++++++++++++++++++++- Eigen/src/Core/arch/NEON/PacketMath.h | 16 +-- 2 files changed, 201 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/arch/NEON/Complex.h b/Eigen/src/Core/arch/NEON/Complex.h index 42e7733d7..57de400e5 100644 --- a/Eigen/src/Core/arch/NEON/Complex.h +++ b/Eigen/src/Core/arch/NEON/Complex.h @@ -33,6 +33,7 @@ template<> struct packet_traits > : default_packet_traits Vectorizable = 1, AlignedOnScalar = 1, size = 2, + HasHalfPacket = 0, HasAdd = 1, HasSub = 1, @@ -88,7 +89,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& a, con template<> EIGEN_STRONG_INLINE Packet2cf pand (const Packet2cf& a, const Packet2cf& b) { - return Packet2cf(vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); + return Packet2cf(vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.v),vreinterpretq_u32_f32(b.v)))); } template<> EIGEN_STRONG_INLINE Packet2cf por (const Packet2cf& a, const Packet2cf& b) { @@ -252,7 +253,7 @@ template<> struct conj_helper template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, const Packet2cf& b) { - // TODO optimize it for AltiVec + // TODO optimize it for NEON Packet2cf res = conj_helper().pmul(a,b); Packet4f s, rev_s; @@ -265,11 +266,198 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv(const Packet2cf& a, con EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { - float32x4_t tmp = vcombine_f32(vget_high_f32(kernel.packet[0].v), vget_high_f32(kernel.packet[1].v)); + Packet4f tmp = vcombine_f32(vget_high_f32(kernel.packet[0].v), vget_high_f32(kernel.packet[1].v)); kernel.packet[0].v = vcombine_f32(vget_low_f32(kernel.packet[0].v), vget_low_f32(kernel.packet[1].v)); kernel.packet[1].v = tmp; } +//---------- double ---------- +#ifdef __aarch64__ + +static uint64x2_t p2ul_CONJ_XOR = EIGEN_INIT_NEON_PACKET2(0x0, 0x8000000000000000); + +struct Packet1cd +{ + EIGEN_STRONG_INLINE Packet1cd() {} + EIGEN_STRONG_INLINE explicit Packet1cd(const Packet2d& a) : v(a) {} + Packet2d v; +}; + +template<> struct packet_traits > : default_packet_traits +{ + typedef Packet1cd type; + typedef Packet1cd half; + enum { + Vectorizable = 1, + AlignedOnScalar = 0, + size = 1, + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasDiv = 1, + HasNegate = 1, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasSetLinear = 0 + }; +}; + +template<> struct unpacket_traits { typedef std::complex type; enum {size=1}; typedef Packet1cd half; }; + +template<> EIGEN_STRONG_INLINE Packet1cd pload(const std::complex* from) { EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload((const double*)from)); } +template<> EIGEN_STRONG_INLINE Packet1cd ploadu(const std::complex* from) { EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu((const double*)from)); } + +template<> EIGEN_STRONG_INLINE Packet1cd pset1(const std::complex& from) +{ /* here we really have to use unaligned loads :( */ return ploadu(&from); } + +template<> EIGEN_STRONG_INLINE Packet1cd padd(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(padd(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd psub(const Packet1cd& a, const Packet1cd& b) { return Packet1cd(psub(a.v,b.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) { return Packet1cd(pnegate(a.v)); } +template<> EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) { return Packet1cd(vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a.v), p2ul_CONJ_XOR))); } + +template<> EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) +{ + Packet2d v1, v2; + + // Get the real values of a + v1 = vdupq_lane_f64(vget_low_f64(a.v), 0); + // Get the real values of a + v2 = vdupq_lane_f64(vget_high_f64(a.v), 1); + // Multiply the real a with b + v1 = vmulq_f64(v1, b.v); + // Multiply the imag a with b + v2 = vmulq_f64(v2, b.v); + // Conjugate v2 + v2 = vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(v2), p2ul_CONJ_XOR)); + // Swap real/imag elements in v2. + v2 = preverse(v2); + // Add and return the result + return Packet1cd(vaddq_f64(v1, v2)); +} + +template<> EIGEN_STRONG_INLINE Packet1cd pand (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vandq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd por (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vorrq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd pxor (const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(veorq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} +template<> EIGEN_STRONG_INLINE Packet1cd pandnot(const Packet1cd& a, const Packet1cd& b) +{ + return Packet1cd(vreinterpretq_f64_u64(vbicq_u64(vreinterpretq_u64_f64(a.v),vreinterpretq_u64_f64(b.v)))); +} + +template<> EIGEN_STRONG_INLINE Packet1cd ploaddup(const std::complex* from) { return pset1(*from); } + +template<> EIGEN_STRONG_INLINE void pstore >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); } +template<> EIGEN_STRONG_INLINE void pstoreu >(std::complex * to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); } + +template<> EIGEN_STRONG_INLINE void prefetch >(const std::complex * addr) { EIGEN_ARM_PREFETCH((double *)addr); } + +template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather, Packet1cd>(const std::complex* from, DenseIndex stride) +{ + Packet2d res; + res = vsetq_lane_f64(std::real(from[0*stride]), res, 0); + res = vsetq_lane_f64(std::imag(from[0*stride]), res, 1); + return Packet1cd(res); +} + +template<> EIGEN_DEVICE_FUNC inline void pscatter, Packet1cd>(std::complex* to, const Packet1cd& from, DenseIndex stride) +{ + to[stride*0] = std::complex(vgetq_lane_f64(from.v, 0), vgetq_lane_f64(from.v, 1)); +} + + +template<> EIGEN_STRONG_INLINE std::complex pfirst(const Packet1cd& a) +{ + std::complex EIGEN_ALIGN16 res; + pstore >(&res, a); + + return res; +} + +template<> EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) { return a; } + +template<> EIGEN_STRONG_INLINE std::complex predux(const Packet1cd& a) { return pfirst(a); } + +template<> EIGEN_STRONG_INLINE Packet1cd preduxp(const Packet1cd* vecs) { return vecs[0]; } + +template<> EIGEN_STRONG_INLINE std::complex predux_mul(const Packet1cd& a) { return pfirst(a); } + +template +struct palign_impl +{ + static EIGEN_STRONG_INLINE void run(Packet1cd& /*first*/, const Packet1cd& /*second*/) + { + // FIXME is it sure we never have to align a Packet1cd? + // Even though a std::complex has 16 bytes, it is not necessarily aligned on a 16 bytes boundary... + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(a, pconj(b)); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return internal::pmul(pconj(a), b); + } +}; + +template<> struct conj_helper +{ + EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet1cd& y, const Packet1cd& c) const + { return padd(pmul(x,y),c); } + + EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& a, const Packet1cd& b) const + { + return pconj(internal::pmul(a, b)); + } +}; + +template<> EIGEN_STRONG_INLINE Packet1cd pdiv(const Packet1cd& a, const Packet1cd& b) +{ + // TODO optimize it for NEON + Packet1cd res = conj_helper().pmul(a,b); + Packet2d s = pmul(b.v, b.v); + Packet2d rev_s = preverse(s); + + return Packet1cd(pdiv(res.v, padd(s,rev_s))); +} + +EIGEN_STRONG_INLINE Packet1cd pcplxflip/**/(const Packet1cd& x) +{ + return Packet1cd(preverse(Packet2d(x.v))); +} + +EIGEN_STRONG_INLINE void ptranspose(PacketBlock& kernel) +{ + Packet2d tmp = vcombine_f64(vget_high_f64(kernel.packet[0].v), vget_high_f64(kernel.packet[1].v)); + kernel.packet[0].v = vcombine_f64(vget_low_f64(kernel.packet[0].v), vget_low_f64(kernel.packet[1].v)); + kernel.packet[1].v = tmp; +} +#endif // __aarch64__ } // end namespace internal diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index e3a13d93a..472f7c0fe 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -34,8 +34,10 @@ namespace internal { #define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 16 #endif +typedef float32x2_t Packet2f; typedef float32x4_t Packet4f; typedef int32x4_t Packet4i; +typedef int32x2_t Packet2i; typedef uint32x4_t Packet4ui; #define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \ @@ -74,12 +76,12 @@ typedef uint32x4_t Packet4ui; template<> struct packet_traits : default_packet_traits { typedef Packet4f type; - typedef Packet4f half; + typedef Packet2f half; enum { Vectorizable = 1, AlignedOnScalar = 1, size = 4, - HasHalfPacket=0, + HasHalfPacket=1, HasDiv = 1, // FIXME check the Has* @@ -93,11 +95,12 @@ template<> struct packet_traits : default_packet_traits template<> struct packet_traits : default_packet_traits { typedef Packet4i type; - typedef Packet4i half; + typedef Packet2i half; enum { Vectorizable = 1, AlignedOnScalar = 1, - size=4 + size=4, + HasHalfPacket=1 // FIXME check the Has* }; }; @@ -490,16 +493,17 @@ ptranspose(PacketBlock& kernel) { #ifdef __aarch64__ typedef float64x2_t Packet2d; +typedef float64x1_t Packet1d; template<> struct packet_traits : default_packet_traits { typedef Packet2d type; - typedef Packet2d half; + typedef Packet1d half; enum { Vectorizable = 1, AlignedOnScalar = 1, size = 2, - HasHalfPacket=0, + HasHalfPacket=1, HasDiv = 1, // FIXME check the Has* -- cgit v1.2.3 From 94ed7c81e6c20ea069cfc37adce7b45dad91691c Mon Sep 17 00:00:00 2001 From: Konstantinos Margaritis Date: Wed, 22 Oct 2014 06:15:18 -0400 Subject: Bug #896: Swap order of checking __VSX__/__ALTIVEC__ --- Eigen/Core | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/Core b/Eigen/Core index adab50b4a..748e20f8e 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -162,18 +162,18 @@ #endif #endif } // end extern "C" - #elif defined __ALTIVEC__ + #elif defined __VSX__ #define EIGEN_VECTORIZE - #define EIGEN_VECTORIZE_ALTIVEC + #define EIGEN_VECTORIZE_VSX #include // We need to #undef all these ugly tokens defined in // => use __vector instead of vector #undef bool #undef vector #undef pixel - #elif defined __VSX__ + #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE - #define EIGEN_VECTORIZE_VSX + #define EIGEN_VECTORIZE_ALTIVEC #include // We need to #undef all these ugly tokens defined in // => use __vector instead of vector -- cgit v1.2.3 From 04ffb9956eb75fbab8f4926235ba011ae7a79d39 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Fri, 24 Oct 2014 13:18:23 +0200 Subject: Replace TEST_SET_BUT_UNUSED_VARIABLE by already defined EIGEN_UNUSED_VARIABLE --- test/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main.h b/test/main.h index adf4adb31..b3fa68476 100644 --- a/test/main.h +++ b/test/main.h @@ -61,7 +61,7 @@ #endif // shuts down ICC's remark #593: variable "XXX" was set but never used -#define TEST_SET_BUT_UNUSED_VARIABLE(X) X = X + 0; +#define TEST_SET_BUT_UNUSED_VARIABLE(X) EIGEN_UNUSED_VARIABLE(X) // the following file is automatically generated by cmake #include "split_test_helper.h" -- cgit v1.2.3 From 1fa793cb978adace700417a16d2ee54c28f42862 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Fri, 24 Oct 2014 13:19:19 +0200 Subject: Removed weird self assignment. --- unsupported/Eigen/src/BDCSVD/BDCSVD.h | 2 +- unsupported/test/bdcsvd.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h index ac71b0aa8..94bc03aac 100644 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -824,7 +824,7 @@ void BDCSVD::perturbCol0 zhat.setZero(); return; } - Index last = last = perm(m-1); + Index last = perm(m-1); // The offset permits to skip deflated entries while computing zhat for (Index k = 0; k < n; ++k) { diff --git a/unsupported/test/bdcsvd.cpp b/unsupported/test/bdcsvd.cpp index 9e5c29a8c..97d7880bb 100644 --- a/unsupported/test/bdcsvd.cpp +++ b/unsupported/test/bdcsvd.cpp @@ -90,8 +90,6 @@ void test_bdcsvd() CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) )); CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) )); - (void) r; - (void) c; // Test on inf/nan matrix CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); -- cgit v1.2.3 From c42605476755652b84643472d48e2e978c5d6f77 Mon Sep 17 00:00:00 2001 From: Benjamin Chrétien Date: Fri, 24 Oct 2014 15:10:56 +0200 Subject: BDCSVD: fix CMake install (missing separator). --- unsupported/Eigen/src/BDCSVD/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/BDCSVD/CMakeLists.txt b/unsupported/Eigen/src/BDCSVD/CMakeLists.txt index 73b89ea18..1045512f9 100644 --- a/unsupported/Eigen/src/BDCSVD/CMakeLists.txt +++ b/unsupported/Eigen/src/BDCSVD/CMakeLists.txt @@ -2,5 +2,5 @@ FILE(GLOB Eigen_BDCSVD_SRCS "*.h") INSTALL(FILES ${Eigen_BDCSVD_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}unsupported/Eigen/src/BDCSVD COMPONENT Devel + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/BDCSVD COMPONENT Devel ) -- cgit v1.2.3 From bd2d330b25f4f57b64ddc125c70dadd42e1e3349 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 28 Oct 2014 13:31:00 +0100 Subject: Temporary workaround for bug #875: Let TriangularView::nonZeros() return nonZeros() of the nested expression --- Eigen/src/SparseCore/SparseTriangularView.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Eigen/src/SparseCore/SparseTriangularView.h b/Eigen/src/SparseCore/SparseTriangularView.h index 1f5e53155..e051f4486 100644 --- a/Eigen/src/SparseCore/SparseTriangularView.h +++ b/Eigen/src/SparseCore/SparseTriangularView.h @@ -50,6 +50,13 @@ protected: template void solveInPlace(MatrixBase& other) const; template void solveInPlace(SparseMatrixBase& other) const; + + inline Index nonZeros() const { + // FIXME HACK number of nonZeros is required for product logic + // this returns only an upper bound (but should be OK for most purposes) + return derived().nestedExpression().nonZeros(); + } + }; -- cgit v1.2.3 From e2e7ba9f8511e9394b1823e14b40a727352c95be Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Tue, 28 Oct 2014 14:49:44 +0100 Subject: bug #898: add inline hint to const_cast_ptr --- 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 f2536714e..463ef85b4 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -371,7 +371,7 @@ template::type> struc template EIGEN_DEVICE_FUNC -T* const_cast_ptr(const T* ptr) +inline T* const_cast_ptr(const T* ptr) { return const_cast(ptr); } -- cgit v1.2.3 From 21c0a2ce0c317fa258380c92bea4e9e16e0840f2 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 29 Oct 2014 11:29:33 +0100 Subject: Move D&C SVD to official SVD module. --- Eigen/SVD | 9 +- Eigen/src/Core/MatrixBase.h | 1 + Eigen/src/Core/util/ForwardDeclarations.h | 1 + Eigen/src/SVD/BDCSVD.h | 1171 +++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/bdcsvd.cpp | 111 +++ unsupported/Eigen/BDCSVD | 26 - unsupported/Eigen/src/BDCSVD/BDCSVD.h | 1170 ------------------------ unsupported/Eigen/src/BDCSVD/CMakeLists.txt | 6 - unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt | 13 - unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt | 8 - unsupported/Eigen/src/CMakeLists.txt | 1 - unsupported/test/CMakeLists.txt | 1 - unsupported/test/bdcsvd.cpp | 111 --- 14 files changed, 1292 insertions(+), 1338 deletions(-) create mode 100644 Eigen/src/SVD/BDCSVD.h create mode 100644 test/bdcsvd.cpp delete mode 100644 unsupported/Eigen/BDCSVD delete mode 100644 unsupported/Eigen/src/BDCSVD/BDCSVD.h delete mode 100644 unsupported/Eigen/src/BDCSVD/CMakeLists.txt delete mode 100644 unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt delete mode 100644 unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt delete mode 100644 unsupported/test/bdcsvd.cpp diff --git a/Eigen/SVD b/Eigen/SVD index c13472e82..dbd37b17a 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -12,20 +12,25 @@ * * * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: + * Two decomposition algorithms are provided: + * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. + * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. + * These decompositions are accessible via the respective classes and following MatrixBase methods: * - MatrixBase::jacobiSvd() + * - MatrixBase::bdcSvd() * * \code * #include * \endcode */ +#include "src/SVD/UpperBidiagonalization.h" #include "src/SVD/SVDBase.h" #include "src/SVD/JacobiSVD.h" +#include "src/SVD/BDCSVD.h" #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) #include "src/SVD/JacobiSVD_MKL.h" #endif -#include "src/SVD/UpperBidiagonalization.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 001513187..135d8dfc8 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -390,6 +390,7 @@ template class MatrixBase /////////// SVD module /////////// JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + BDCSVD bdcSvd(unsigned int computationOptions = 0) const; /////////// Geometry module /////////// diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index be156a44a..1f7503dfa 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -251,6 +251,7 @@ template class HouseholderQR; template class ColPivHouseholderQR; template class FullPivHouseholderQR; template class JacobiSVD; +template class BDCSVD; template class LLT; template class LDLT; template class HouseholderSequence; diff --git a/Eigen/src/SVD/BDCSVD.h b/Eigen/src/SVD/BDCSVD.h new file mode 100644 index 000000000..498541050 --- /dev/null +++ b/Eigen/src/SVD/BDCSVD.h @@ -0,0 +1,1171 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// We used the "A Divide-And-Conquer Algorithm for the Bidiagonal SVD" +// research report written by Ming Gu and Stanley C.Eisenstat +// The code variable names correspond to the names they used in their +// report +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// Copyright (C) 2013 Jitse Niesen +// Copyright (C) 2014 Gael Guennebaud +// +// Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BDCSVD_H +#define EIGEN_BDCSVD_H +// #define EIGEN_BDCSVD_DEBUG_VERBOSE +// #define EIGEN_BDCSVD_SANITY_CHECKS +namespace Eigen { + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE +IOFormat bdcsvdfmt(8, 0, ", ", "\n", " [", "]"); +#endif + +template class BDCSVD; + +namespace internal { + +template +struct traits > +{ + typedef _MatrixType MatrixType; +}; + +} // end namespace internal + + +/** \ingroup SVD_Module + * + * + * \class BDCSVD + * + * \brief class Bidiagonal Divide and Conquer SVD + * + * \param MatrixType the type of the matrix of which we are computing the SVD decomposition + * We plan to have a very similar interface to JacobiSVD on this class. + * It should be used to speed up the calcul of SVD for big matrices. + */ +template +class BDCSVD : public SVDBase > +{ + typedef SVDBase Base; + +public: + using Base::rows; + using Base::cols; + using Base::computeU; + using Base::computeV; + + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef typename MatrixType::Index Index; + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime), + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime, MaxColsAtCompileTime), + MatrixOptions = MatrixType::Options + }; + + typedef typename Base::MatrixUType MatrixUType; + typedef typename Base::MatrixVType MatrixVType; + typedef typename Base::SingularValuesType SingularValuesType; + + typedef Matrix MatrixX; + typedef Matrix MatrixXr; + typedef Matrix VectorType; + typedef Array ArrayXr; + typedef Array ArrayXi; + + /** \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via BDCSVD::compute(const MatrixType&). + */ + BDCSVD() : m_algoswap(16), m_numIters(0) + {} + + + /** \brief Default Constructor with memory preallocation + * + * Like the default constructor but with preallocation of the internal data + * according to the specified problem size. + * \sa BDCSVD() + */ + BDCSVD(Index rows, Index cols, unsigned int computationOptions = 0) + : m_algoswap(16), m_numIters(0) + { + allocate(rows, cols, computationOptions); + } + + /** \brief Constructor performing the decomposition of given matrix. + * + * \param matrix the matrix to decompose + * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. + * By default, none is computed. This is a bit - field, the possible bits are #ComputeFullU, #ComputeThinU, + * #ComputeFullV, #ComputeThinV. + * + * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not + * available with the (non - default) FullPivHouseholderQR preconditioner. + */ + BDCSVD(const MatrixType& matrix, unsigned int computationOptions = 0) + : m_algoswap(16), m_numIters(0) + { + compute(matrix, computationOptions); + } + + ~BDCSVD() + { + } + + /** \brief Method performing the decomposition of given matrix using custom options. + * + * \param matrix the matrix to decompose + * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. + * By default, none is computed. This is a bit - field, the possible bits are #ComputeFullU, #ComputeThinU, + * #ComputeFullV, #ComputeThinV. + * + * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not + * available with the (non - default) FullPivHouseholderQR preconditioner. + */ + BDCSVD& compute(const MatrixType& matrix, unsigned int computationOptions); + + /** \brief Method performing the decomposition of given matrix using current options. + * + * \param matrix the matrix to decompose + * + * This method uses the current \a computationOptions, as already passed to the constructor or to compute(const MatrixType&, unsigned int). + */ + BDCSVD& compute(const MatrixType& matrix) + { + return compute(matrix, this->m_computationOptions); + } + + void setSwitchSize(int s) + { + eigen_assert(s>3 && "BDCSVD the size of the algo switch has to be greater than 3"); + m_algoswap = s; + } + +private: + void allocate(Index rows, Index cols, unsigned int computationOptions); + void divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift); + void computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V); + void computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, VectorType& singVals, ArrayXr& shifts, ArrayXr& mus); + void perturbCol0(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat); + void computeSingVecs(const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V); + void deflation43(Index firstCol, Index shift, Index i, Index size); + void deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size); + void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift); + template + void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); + static void structured_update(Block A, const MatrixXr &B, Index n1); + static RealScalar secularEq(RealScalar x, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift); + +protected: + MatrixXr m_naiveU, m_naiveV; + MatrixXr m_computed; + Index m_nRec; + int m_algoswap; + bool m_isTranspose, m_compU, m_compV; + + using Base::m_singularValues; + using Base::m_diagSize; + using Base::m_computeFullU; + using Base::m_computeFullV; + using Base::m_computeThinU; + using Base::m_computeThinV; + using Base::m_matrixU; + using Base::m_matrixV; + using Base::m_isInitialized; + using Base::m_nonzeroSingularValues; + +public: + int m_numIters; +}; //end class BDCSVD + + +// Method to allocate and initialize matrix and attributes +template +void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) +{ + m_isTranspose = (cols > rows); + + if (Base::allocate(rows, cols, computationOptions)) + return; + + m_computed = MatrixXr::Zero(m_diagSize + 1, m_diagSize ); + m_compU = computeV(); + m_compV = computeU(); + if (m_isTranspose) + std::swap(m_compU, m_compV); + + if (m_compU) m_naiveU = MatrixXr::Zero(m_diagSize + 1, m_diagSize + 1 ); + else m_naiveU = MatrixXr::Zero(2, m_diagSize + 1 ); + + if (m_compV) m_naiveV = MatrixXr::Zero(m_diagSize, m_diagSize); +}// end allocate + +template +BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) +{ +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "\n\n\n======================================================================================================================\n\n\n"; +#endif + allocate(matrix.rows(), matrix.cols(), computationOptions); + using std::abs; + + //**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows + RealScalar scale = matrix.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + MatrixX copy; + if (m_isTranspose) copy = matrix.adjoint()/scale; + else copy = matrix/scale; + + //**** step 1 - Bidiagonalization + internal::UpperBidiagonalization bid(copy); + + //**** step 2 - Divide & Conquer + m_naiveU.setZero(); + m_naiveV.setZero(); + m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); + m_computed.template bottomRows<1>().setZero(); + divide(0, m_diagSize - 1, 0, 0, 0); + + //**** step 3 - Copy singular values and vectors + for (int i=0; i +template +void BDCSVD::copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naiveV) +{ + // Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa + if (computeU()) + { + Index Ucols = m_computeThinU ? m_diagSize : householderU.cols(); + m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); + m_matrixU.topLeftCorner(m_diagSize, m_diagSize) = naiveV.template cast().topLeftCorner(m_diagSize, m_diagSize); + householderU.applyThisOnTheLeft(m_matrixU); + } + if (computeV()) + { + Index Vcols = m_computeThinV ? m_diagSize : householderV.cols(); + m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); + m_matrixV.topLeftCorner(m_diagSize, m_diagSize) = naiveU.template cast().topLeftCorner(m_diagSize, m_diagSize); + householderV.applyThisOnTheLeft(m_matrixV); + } +} + +/** \internal + * Performs A = A * B exploiting the special structure of the matrix A. Splitting A as: + * A = [A1] + * [A2] + * such that A1.rows()==n1, then we assume that at least half of the columns of A1 and A2 are zeros. + * We can thus pack them prior to the the matrix product. However, this is only worth the effort if the matrix is large + * enough. + */ +template +void BDCSVD::structured_update(Block A, const MatrixXr &B, Index n1) +{ + Index n = A.rows(); + if(n>100) + { + // If the matrices are large enough, let's exploit the sparse structure of A by + // splitting it in half (wrt n1), and packing the non-zero columns. + DenseIndex n2 = n - n1; + MatrixXr A1(n1,n), A2(n2,n), B1(n,n), B2(n,n); + Index k1=0, k2=0; + for(Index j=0; j +void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift) +{ + // requires nbRows = nbCols + 1; + using std::pow; + using std::sqrt; + using std::abs; + const Index n = lastCol - firstCol + 1; + const Index k = n/2; + RealScalar alphaK; + RealScalar betaK; + RealScalar r0; + RealScalar lambda, phi, c0, s0; + VectorType l, f; + // We use the other algorithm which is more efficient for small + // matrices. + if (n < m_algoswap) + { + JacobiSVD b(m_computed.block(firstCol, firstCol, n + 1, n), ComputeFullU | (m_compV ? ComputeFullV : 0)) ; + if (m_compU) + m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = b.matrixU(); + else + { + m_naiveU.row(0).segment(firstCol, n + 1).real() = b.matrixU().row(0); + m_naiveU.row(1).segment(firstCol, n + 1).real() = b.matrixU().row(n); + } + if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = b.matrixV(); + m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero(); + m_computed.diagonal().segment(firstCol + shift, n) = b.singularValues().head(n); + return; + } + // We use the divide and conquer algorithm + alphaK = m_computed(firstCol + k, firstCol + k); + betaK = m_computed(firstCol + k + 1, firstCol + k); + // The divide must be done in that order in order to have good results. Divide change the data inside the submatrices + // and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the + // right submatrix before the left one. + divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift); + divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1); + + if (m_compU) + { + lambda = m_naiveU(firstCol + k, firstCol + k); + phi = m_naiveU(firstCol + k + 1, lastCol + 1); + } + else + { + lambda = m_naiveU(1, firstCol + k); + phi = m_naiveU(0, lastCol + 1); + } + r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) + abs(betaK * phi) * abs(betaK * phi)); + if (m_compU) + { + l = m_naiveU.row(firstCol + k).segment(firstCol, k); + f = m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1); + } + else + { + l = m_naiveU.row(1).segment(firstCol, k); + f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1); + } + if (m_compV) m_naiveV(firstRowW+k, firstColW) = 1; + if (r0 == 0) + { + c0 = 1; + s0 = 0; + } + else + { + c0 = alphaK * lambda / r0; + s0 = betaK * phi / r0; + } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + + if (m_compU) + { + MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1)); + // we shiftW Q1 to the right + for (Index i = firstCol + k - 1; i >= firstCol; i--) + m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1); + // we shift q1 at the left with a factor c0 + m_naiveU.col(firstCol).segment( firstCol, k + 1) = (q1 * c0); + // last column = q1 * - s0 + m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * ( - s0)); + // first column = q2 * s0 + m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) = m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0; + // q2 *= c0 + m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0; + } + else + { + RealScalar q1 = (m_naiveU(0, firstCol + k)); + // we shift Q1 to the right + for (Index i = firstCol + k - 1; i >= firstCol; i--) + m_naiveU(0, i + 1) = m_naiveU(0, i); + // we shift q1 at the left with a factor c0 + m_naiveU(0, firstCol) = (q1 * c0); + // last column = q1 * - s0 + m_naiveU(0, lastCol + 1) = (q1 * ( - s0)); + // first column = q2 * s0 + m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) *s0; + // q2 *= c0 + m_naiveU(1, lastCol + 1) *= c0; + m_naiveU.row(1).segment(firstCol + 1, k).setZero(); + m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero(); + } + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + + m_computed(firstCol + shift, firstCol + shift) = r0; + m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); + m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + ArrayXr tmp1 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); +#endif + // Second part: try to deflate singular values in combined matrix + deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + ArrayXr tmp2 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); + std::cout << "\n\nj1 = " << tmp1.transpose().format(bdcsvdfmt) << "\n"; + std::cout << "j2 = " << tmp2.transpose().format(bdcsvdfmt) << "\n\n"; + std::cout << "err: " << ((tmp1-tmp2).abs()>1e-12*tmp2.abs()).transpose() << "\n"; + static int count = 0; + std::cout << "# " << ++count << "\n\n"; + assert((tmp1-tmp2).matrix().norm() < 1e-14*tmp2.matrix().norm()); +// assert(count<681); +// assert(((tmp1-tmp2).abs()<1e-13*tmp2.abs()).all()); +#endif + + // Third part: compute SVD of combined matrix + MatrixXr UofSVD, VofSVD; + VectorType singVals; + computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(UofSVD.allFinite()); + assert(VofSVD.allFinite()); +#endif + + if (m_compU) structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2); + else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time + + if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n+1)/2); + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + + m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); + m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; +}// end divide + +// Compute SVD of m_computed.block(firstCol, firstCol, n + 1, n); this block only has non-zeros in +// the first column and on the diagonal and has undergone deflation, so diagonal is in increasing +// order except for possibly the (0,0) entry. The computed SVD is stored U, singVals and V, except +// that if m_compV is false, then V is not computed. Singular values are sorted in decreasing order. +// +// TODO Opportunities for optimization: better root finding algo, better stopping criterion, better +// handling of round-off errors, be consistent in ordering +// For instance, to solve the secular equation using FMM, see http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf +template +void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V) +{ + // TODO Get rid of these copies (?) + // FIXME at least preallocate them + ArrayXr col0 = m_computed.col(firstCol).segment(firstCol, n); + ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); + diag(0) = 0; + + // Allocate space for singular values and vectors + singVals.resize(n); + U.resize(n+1, n+1); + if (m_compV) V.resize(n, n); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + if (col0.hasNaN() || diag.hasNaN()) + std::cout << "\n\nHAS NAN\n\n"; +#endif + + // Many singular values might have been deflated, the zero ones have been moved to the end, + // but others are interleaved and we must ignore them at this stage. + // To this end, let's compute a permutation skipping them: + Index actual_n = n; + while(actual_n>1 && diag(actual_n-1)==0) --actual_n; + Index m = 0; // size of the deflated problem + ArrayXi perm(actual_n); + for(Index k=0;k1 && col0(actual_n-1)==0) --actual_n; + std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n"; + std::cout << " check1 (expect0) : " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check2 (>0) : " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() << "\n\n"; + std::cout << " check3 (>0) : " << ((diag.segment(1,actual_n-1)-singVals.head(actual_n-1).array()) / singVals.head(actual_n-1).array()).transpose() << "\n\n\n"; + std::cout << " check4 (>0) : " << ((singVals.segment(1,actual_n-1)-singVals.head(actual_n-1))).transpose() << "\n\n\n"; + } +#endif + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(singVals.allFinite()); + assert(mus.allFinite()); + assert(shifts.allFinite()); +#endif + + // Compute zhat + perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << " zhat: " << zhat.transpose() << "\n"; +#endif + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(zhat.allFinite()); +#endif + + computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() << "\n"; + std::cout << "V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() << "\n"; +#endif + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(U.allFinite()); + assert(V.allFinite()); + assert((U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); + assert((V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + + // Because of deflation, the singular values might not be completely sorted. + // Fortunately, reordering them is a O(n) problem + for(Index i=0; isingVals(i+1)) + { + using std::swap; + swap(singVals(i),singVals(i+1)); + U.col(i).swap(U.col(i+1)); + if(m_compV) V.col(i).swap(V.col(i+1)); + } + } + + // Reverse order so that singular values in increased order + // Because of deflation, the zeros singular-values are already at the end + singVals.head(actual_n).reverseInPlace(); + U.leftCols(actual_n) = U.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary + if (m_compV) V.leftCols(actual_n) = V.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + JacobiSVD jsvd(m_computed.block(firstCol, firstCol, n, n) ); + std::cout << " * j: " << jsvd.singularValues().transpose() << "\n\n"; + std::cout << " * sing-val: " << singVals.transpose() << "\n"; +// std::cout << " * err: " << ((jsvd.singularValues()-singVals)>1e-13*singVals.norm()).transpose() << "\n"; +#endif +} + +template +typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift) +{ + Index m = perm.size(); + RealScalar res = 1; + for(Index i=0; i +void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, + VectorType& singVals, ArrayXr& shifts, ArrayXr& mus) +{ + using std::abs; + using std::swap; + + Index n = col0.size(); + Index actual_n = n; + while(actual_n>1 && col0(actual_n-1)==0) --actual_n; + + for (Index k = 0; k < n; ++k) + { + if (col0(k) == 0 || actual_n==1) + { + // if col0(k) == 0, then entry is deflated, so singular value is on diagonal + // if actual_n==1, then the deflated problem is already diagonalized + singVals(k) = k==0 ? col0(0) : diag(k); + mus(k) = 0; + shifts(k) = k==0 ? col0(0) : diag(k); + continue; + } + + // otherwise, use secular equation to find singular value + RealScalar left = diag(k); + RealScalar right; // was: = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm()); + if(k==actual_n-1) + right = (diag(actual_n-1) + col0.matrix().norm()); + else + { + // Skip deflated singular values + Index l = k+1; + while(col0(l)==0) { ++l; eigen_internal_assert(l 0) ? left : right; + + // measure everything relative to shift + ArrayXr diagShifted = diag - shift; + + // initial guess + RealScalar muPrev, muCur; + if (shift == left) + { + muPrev = (right - left) * 0.1; + if (k == actual_n-1) muCur = right - left; + else muCur = (right - left) * 0.5; + } + else + { + muPrev = -(right - left) * 0.1; + muCur = -(right - left) * 0.5; + } + + RealScalar fPrev = secularEq(muPrev, col0, diag, perm, diagShifted, shift); + RealScalar fCur = secularEq(muCur, col0, diag, perm, diagShifted, shift); + if (abs(fPrev) < abs(fCur)) + { + swap(fPrev, fCur); + swap(muPrev, muCur); + } + + // rational interpolation: fit a function of the form a / mu + b through the two previous + // iterates and use its zero to compute the next iterate + bool useBisection = fPrev*fCur>0; + while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits::epsilon() * numext::maxi(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) + { + ++m_numIters; + + // Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples. + RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); + RealScalar b = fCur - a / muCur; + // And find mu such that f(mu)==0: + RealScalar muZero = -a/b; + RealScalar fZero = secularEq(muZero, col0, diag, perm, diagShifted, shift); + + muPrev = muCur; + fPrev = fCur; + muCur = muZero; + fCur = fZero; + + + if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; + if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true; + if (abs(fCur)>abs(fPrev)) useBisection = true; + } + + // fall back on bisection method if rational interpolation did not work + if (useBisection) + { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "useBisection for k = " << k << ", actual_n = " << actual_n << "\n"; +#endif + RealScalar leftShifted, rightShifted; + if (shift == left) + { + leftShifted = RealScalar(1)/NumTraits::highest(); + // I don't understand why the case k==0 would be special there: + // if (k == 0) rightShifted = right - left; else + rightShifted = (k==actual_n-1) ? right : ((right - left) * 0.6); // theoretically we can take 0.5, but let's be safe + } + else + { + leftShifted = -(right - left) * 0.6; + rightShifted = -RealScalar(1)/NumTraits::highest(); + } + + RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift); + RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift); + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + if(!(fLeft * fRight<0)) + std::cout << k << " : " << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; +#endif + eigen_internal_assert(fLeft * fRight < 0); + + while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * numext::maxi(abs(leftShifted), abs(rightShifted))) + { + RealScalar midShifted = (leftShifted + rightShifted) / 2; + RealScalar fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift); + if (fLeft * fMid < 0) + { + rightShifted = midShifted; + fRight = fMid; + } + else + { + leftShifted = midShifted; + fLeft = fMid; + } + } + + muCur = (leftShifted + rightShifted) / 2; + } + + singVals[k] = shift + muCur; + shifts[k] = shift; + mus[k] = muCur; + + // perturb singular value slightly if it equals diagonal entry to avoid division by zero later + // (deflation is supposed to avoid this from happening) + // - this does no seem to be necessary anymore - +// if (singVals[k] == left) singVals[k] *= 1 + NumTraits::epsilon(); +// if (singVals[k] == right) singVals[k] *= 1 - NumTraits::epsilon(); + } +} + + +// zhat is perturbation of col0 for which singular vectors can be computed stably (see Section 3.1) +template +void BDCSVD::perturbCol0 + (const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, + const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) +{ + using std::sqrt; + Index n = col0.size(); + Index m = perm.size(); + if(m==0) + { + zhat.setZero(); + return; + } + Index last = perm(m-1); + // The offset permits to skip deflated entries while computing zhat + for (Index k = 0; k < n; ++k) + { + if (col0(k) == 0) // deflated + zhat(k) = 0; + else + { + // see equation (3.6) + RealScalar dk = diag(k); + RealScalar prod = (singVals(last) + dk) * (mus(last) + (shifts(last) - dk)); + + for(Index l = 0; l 0.9 ) + std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk)) + << ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n"; +#endif + } + } +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(last) + dk) << " * " << mus(last) + shifts(last) << " - " << dk << "\n"; +#endif + RealScalar tmp = sqrt(prod); + zhat(k) = col0(k) > 0 ? tmp : -tmp; + } + } +} + +// compute singular vectors +template +void BDCSVD::computeSingVecs + (const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, + const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V) +{ + Index n = zhat.size(); + Index m = perm.size(); + + for (Index k = 0; k < n; ++k) + { + if (zhat(k) == 0) + { + U.col(k) = VectorType::Unit(n+1, k); + if (m_compV) V.col(k) = VectorType::Unit(n, k); + } + else + { + U.col(k).setZero(); + for(Index l=0;l= 1, di almost null and zi non null. +// We use a rotation to zero out zi applied to the left of M +template +void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index size) +{ + using std::abs; + using std::sqrt; + using std::pow; + Index start = firstCol + shift; + RealScalar c = m_computed(start, start); + RealScalar s = m_computed(start+i, start); + RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); + if (r == 0) + { + m_computed(start+i, start+i) = 0; + return; + } + m_computed(start,start) = r; + m_computed(start+i, start) = 0; + m_computed(start+i, start+i) = 0; + + JacobiRotation J(c/r,-s/r); + if (m_compU) m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J); + else m_naiveU.applyOnTheRight(firstCol, firstCol+i, J); +}// end deflation 43 + + +// page 13 +// i,j >= 1, i!=j and |di - dj| < epsilon * norm2(M) +// We apply two rotations to have zj = 0; +// TODO deflation44 is still broken and not properly tested +template +void BDCSVD::deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size) +{ + using std::abs; + using std::sqrt; + using std::conj; + using std::pow; + RealScalar c = m_computed(firstColm+i, firstColm); + RealScalar s = m_computed(firstColm+j, firstColm); + RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; " + << m_computed(firstColm + i-1, firstColm) << " " + << m_computed(firstColm + i, firstColm) << " " + << m_computed(firstColm + i+1, firstColm) << " " + << m_computed(firstColm + i+2, firstColm) << "\n"; + std::cout << m_computed(firstColm + i-1, firstColm + i-1) << " " + << m_computed(firstColm + i, firstColm+i) << " " + << m_computed(firstColm + i+1, firstColm+i+1) << " " + << m_computed(firstColm + i+2, firstColm+i+2) << "\n"; +#endif + if (r==0) + { + m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); + return; + } + c/=r; + s/=r; + m_computed(firstColm + i, firstColm) = r; + m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i); + m_computed(firstColm + j, firstColm) = 0; + + JacobiRotation J(c,-s); + if (m_compU) m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J); + else m_naiveU.applyOnTheRight(firstColu+i, firstColu+j, J); + if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J); +}// end deflation 44 + + +// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive] +template +void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift) +{ + using std::sqrt; + using std::abs; + const Index length = lastCol + 1 - firstCol; + + Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); + Diagonal fulldiag(m_computed); + VectorBlock,Dynamic> diag(fulldiag, firstCol+shift, length); + + RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff(); + RealScalar epsilon_strict = NumTraits::epsilon() * maxDiag; + RealScalar epsilon_coarse = 8 * NumTraits::epsilon() * numext::maxi(col0.cwiseAbs().maxCoeff(), maxDiag); + +#ifdef EIGEN_BDCSVD_SANITY_CHECKS + assert(m_naiveU.allFinite()); + assert(m_naiveV.allFinite()); + assert(m_computed.allFinite()); +#endif + +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "\ndeflate:" << diag.head(k+1).transpose() << " | " << diag.segment(k+1,length-k-1).transpose() << "\n"; +#endif + + //condition 4.1 + if (diag(0) < epsilon_coarse) + { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon_coarse << "\n"; +#endif + diag(0) = epsilon_coarse; + } + + //condition 4.2 + for (Index i=1;i k) permutation[p] = j++; + else if (j >= length) permutation[p] = i++; + else if (diag(i) < diag(j)) permutation[p] = j++; + else permutation[p] = i++; + } + } + + // If we have a total deflation, then we have to insert diag(0) at the right place + if(total_deflation) + { + for(Index i=1; i0 && (diag(i)==0 || col0(i)==0)) --i; + for(; i>1;--i) + if( (diag(i) - diag(i-1)) < NumTraits::epsilon()*maxDiag ) + { +#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE + std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i) - diag(i-1)) << " < " << NumTraits::epsilon()*diag(i) << "\n"; +#endif + eigen_internal_assert(abs(diag(i) - diag(i-1)) +BDCSVD::PlainObject> +MatrixBase::bdcSvd(unsigned int computationOptions) const +{ + return BDCSVD(*this, computationOptions); +} + +} // end namespace Eigen + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 63ed2c7a4..f57d8ce36 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -211,6 +211,7 @@ ei_add_test(real_qz) ei_add_test(eigensolver_generalized_real) ei_add_test(jacobi) ei_add_test(jacobisvd) +ei_add_test(bdcsvd) ei_add_test(householder) ei_add_test(geo_orthomethods) ei_add_test(geo_quaternion) diff --git a/test/bdcsvd.cpp b/test/bdcsvd.cpp new file mode 100644 index 000000000..d58d259d6 --- /dev/null +++ b/test/bdcsvd.cpp @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/ + +// discard stack allocation as that too bypasses malloc +#define EIGEN_STACK_ALLOCATION_LIMIT 0 +#define EIGEN_RUNTIME_NO_MALLOC + +#include "main.h" +#include +#include +#include + + +#define SVD_DEFAULT(M) BDCSVD +#define SVD_FOR_MIN_NORM(M) BDCSVD +#include "../../test/svd_common.h" + +// Check all variants of JacobiSVD +template +void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = a; + if(pickrandom) + svd_fill_random(m); + + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); +} + +template +void bdcsvd_method() +{ + enum { Size = MatrixType::RowsAtCompileTime }; + typedef typename MatrixType::RealScalar RealScalar; + typedef Matrix RealVecType; + MatrixType m = MatrixType::Identity(); + VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones()); + VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU()); + VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV()); + VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m); +} + +// compare the Singular values returned with Jacobi and Bdc +template +void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0) +{ + MatrixType m = MatrixType::Random(a.rows(), a.cols()); + BDCSVD bdc_svd(m); + JacobiSVD jacobi_svd(m); + VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues()); + if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); + if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); +} + +void test_bdcsvd() +{ + CALL_SUBTEST_3(( svd_verify_assert >(Matrix3f()) )); + CALL_SUBTEST_4(( svd_verify_assert >(Matrix4d()) )); + CALL_SUBTEST_7(( svd_verify_assert >(MatrixXf(10,12)) )); + CALL_SUBTEST_8(( svd_verify_assert >(MatrixXcd(7,5)) )); + + CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); + CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); + + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_3(( bdcsvd() )); + CALL_SUBTEST_4(( bdcsvd() )); + CALL_SUBTEST_5(( bdcsvd >() )); + + int r = internal::random(1, EIGEN_TEST_MAX_SIZE/2), + c = internal::random(1, EIGEN_TEST_MAX_SIZE/2); + + TEST_SET_BUT_UNUSED_VARIABLE(r) + TEST_SET_BUT_UNUSED_VARIABLE(c) + + CALL_SUBTEST_6(( bdcsvd(Matrix(r,2)) )); + CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); + CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) )); + CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) )); + CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) )); + CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); + CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) )); + + // Test on inf/nan matrix + CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); + CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); + } + + // test matrixbase method + CALL_SUBTEST_1(( bdcsvd_method() )); + CALL_SUBTEST_3(( bdcsvd_method() )); + + // Test problem size constructors + CALL_SUBTEST_7( BDCSVD(10,10) ); + + // Check that preallocation avoids subsequent mallocs + CALL_SUBTEST_9( svd_preallocate() ); + + CALL_SUBTEST_2( svd_underoverflow() ); +} + diff --git a/unsupported/Eigen/BDCSVD b/unsupported/Eigen/BDCSVD deleted file mode 100644 index 44649dbd0..000000000 --- a/unsupported/Eigen/BDCSVD +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef EIGEN_BDCSVD_MODULE_H -#define EIGEN_BDCSVD_MODULE_H - -#include - -#include "../../Eigen/src/Core/util/DisableStupidWarnings.h" - -/** \defgroup BDCSVD_Module BDCSVD module - * - * - * - * This module provides Divide & Conquer SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: - * - MatrixBase::bdcSvd() - * - * \code - * #include - * \endcode - */ - -#include "src/BDCSVD/BDCSVD.h" - -#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_BDCSVD_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/unsupported/Eigen/src/BDCSVD/BDCSVD.h b/unsupported/Eigen/src/BDCSVD/BDCSVD.h deleted file mode 100644 index 94bc03aac..000000000 --- a/unsupported/Eigen/src/BDCSVD/BDCSVD.h +++ /dev/null @@ -1,1170 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// We used the "A Divide-And-Conquer Algorithm for the Bidiagonal SVD" -// research report written by Ming Gu and Stanley C.Eisenstat -// The code variable names correspond to the names they used in their -// report -// -// Copyright (C) 2013 Gauthier Brun -// Copyright (C) 2013 Nicolas Carre -// Copyright (C) 2013 Jean Ceccato -// Copyright (C) 2013 Pierre Zoppitelli -// Copyright (C) 2013 Jitse Niesen -// Copyright (C) 2014 Gael Guennebaud -// -// Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_BDCSVD_H -#define EIGEN_BDCSVD_H -// #define EIGEN_BDCSVD_DEBUG_VERBOSE -// #define EIGEN_BDCSVD_SANITY_CHECKS -namespace Eigen { - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE -IOFormat bdcsvdfmt(8, 0, ", ", "\n", " [", "]"); -#endif - -template class BDCSVD; - -namespace internal { - -template -struct traits > -{ - typedef _MatrixType MatrixType; -}; - -} // end namespace internal - - -/** \ingroup SVD_Module - * - * - * \class BDCSVD - * - * \brief class Bidiagonal Divide and Conquer SVD - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * We plan to have a very similar interface to JacobiSVD on this class. - * It should be used to speed up the calcul of SVD for big matrices. - */ -template -class BDCSVD : public SVDBase > -{ - typedef SVDBase Base; - -public: - using Base::rows; - using Base::cols; - using Base::computeU; - using Base::computeV; - - typedef _MatrixType MatrixType; - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime), - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime, MaxColsAtCompileTime), - MatrixOptions = MatrixType::Options - }; - - typedef typename Base::MatrixUType MatrixUType; - typedef typename Base::MatrixVType MatrixVType; - typedef typename Base::SingularValuesType SingularValuesType; - - typedef Matrix MatrixX; - typedef Matrix MatrixXr; - typedef Matrix VectorType; - typedef Array ArrayXr; - typedef Array ArrayXi; - - /** \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via BDCSVD::compute(const MatrixType&). - */ - BDCSVD() : m_algoswap(16), m_numIters(0) - {} - - - /** \brief Default Constructor with memory preallocation - * - * Like the default constructor but with preallocation of the internal data - * according to the specified problem size. - * \sa BDCSVD() - */ - BDCSVD(Index rows, Index cols, unsigned int computationOptions = 0) - : m_algoswap(16), m_numIters(0) - { - allocate(rows, cols, computationOptions); - } - - /** \brief Constructor performing the decomposition of given matrix. - * - * \param matrix the matrix to decompose - * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. - * By default, none is computed. This is a bit - field, the possible bits are #ComputeFullU, #ComputeThinU, - * #ComputeFullV, #ComputeThinV. - * - * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not - * available with the (non - default) FullPivHouseholderQR preconditioner. - */ - BDCSVD(const MatrixType& matrix, unsigned int computationOptions = 0) - : m_algoswap(16), m_numIters(0) - { - compute(matrix, computationOptions); - } - - ~BDCSVD() - { - } - - /** \brief Method performing the decomposition of given matrix using custom options. - * - * \param matrix the matrix to decompose - * \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed. - * By default, none is computed. This is a bit - field, the possible bits are #ComputeFullU, #ComputeThinU, - * #ComputeFullV, #ComputeThinV. - * - * Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not - * available with the (non - default) FullPivHouseholderQR preconditioner. - */ - BDCSVD& compute(const MatrixType& matrix, unsigned int computationOptions); - - /** \brief Method performing the decomposition of given matrix using current options. - * - * \param matrix the matrix to decompose - * - * This method uses the current \a computationOptions, as already passed to the constructor or to compute(const MatrixType&, unsigned int). - */ - BDCSVD& compute(const MatrixType& matrix) - { - return compute(matrix, this->m_computationOptions); - } - - void setSwitchSize(int s) - { - eigen_assert(s>3 && "BDCSVD the size of the algo switch has to be greater than 3"); - m_algoswap = s; - } - -private: - void allocate(Index rows, Index cols, unsigned int computationOptions); - void divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift); - void computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V); - void computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, VectorType& singVals, ArrayXr& shifts, ArrayXr& mus); - void perturbCol0(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat); - void computeSingVecs(const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi& perm, const VectorType& singVals, const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V); - void deflation43(Index firstCol, Index shift, Index i, Index size); - void deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size); - void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift); - template - void copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naivev); - static void structured_update(Block A, const MatrixXr &B, Index n1); - static RealScalar secularEq(RealScalar x, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift); - -protected: - MatrixXr m_naiveU, m_naiveV; - MatrixXr m_computed; - Index m_nRec; - int m_algoswap; - bool m_isTranspose, m_compU, m_compV; - - using Base::m_singularValues; - using Base::m_diagSize; - using Base::m_computeFullU; - using Base::m_computeFullV; - using Base::m_computeThinU; - using Base::m_computeThinV; - using Base::m_matrixU; - using Base::m_matrixV; - using Base::m_isInitialized; - using Base::m_nonzeroSingularValues; - -public: - int m_numIters; -}; //end class BDCSVD - - -// Method to allocate and initialize matrix and attributes -template -void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) -{ - m_isTranspose = (cols > rows); - - if (Base::allocate(rows, cols, computationOptions)) - return; - - m_computed = MatrixXr::Zero(m_diagSize + 1, m_diagSize ); - m_compU = computeV(); - m_compV = computeU(); - if (m_isTranspose) - std::swap(m_compU, m_compV); - - if (m_compU) m_naiveU = MatrixXr::Zero(m_diagSize + 1, m_diagSize + 1 ); - else m_naiveU = MatrixXr::Zero(2, m_diagSize + 1 ); - - if (m_compV) m_naiveV = MatrixXr::Zero(m_diagSize, m_diagSize); -}// end allocate - -template -BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) -{ -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "\n\n\n======================================================================================================================\n\n\n"; -#endif - allocate(matrix.rows(), matrix.cols(), computationOptions); - using std::abs; - - //**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows - RealScalar scale = matrix.cwiseAbs().maxCoeff(); - if(scale==RealScalar(0)) scale = RealScalar(1); - MatrixX copy; - if (m_isTranspose) copy = matrix.adjoint()/scale; - else copy = matrix/scale; - - //**** step 1 - Bidiagonalization - internal::UpperBidiagonalization bid(copy); - - //**** step 2 - Divide & Conquer - m_naiveU.setZero(); - m_naiveV.setZero(); - m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose(); - m_computed.template bottomRows<1>().setZero(); - divide(0, m_diagSize - 1, 0, 0, 0); - - //**** step 3 - Copy singular values and vectors - for (int i=0; i -template -void BDCSVD::copyUV(const HouseholderU &householderU, const HouseholderV &householderV, const NaiveU &naiveU, const NaiveV &naiveV) -{ - // Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa - if (computeU()) - { - Index Ucols = m_computeThinU ? m_diagSize : householderU.cols(); - m_matrixU = MatrixX::Identity(householderU.cols(), Ucols); - m_matrixU.topLeftCorner(m_diagSize, m_diagSize) = naiveV.template cast().topLeftCorner(m_diagSize, m_diagSize); - householderU.applyThisOnTheLeft(m_matrixU); - } - if (computeV()) - { - Index Vcols = m_computeThinV ? m_diagSize : householderV.cols(); - m_matrixV = MatrixX::Identity(householderV.cols(), Vcols); - m_matrixV.topLeftCorner(m_diagSize, m_diagSize) = naiveU.template cast().topLeftCorner(m_diagSize, m_diagSize); - householderV.applyThisOnTheLeft(m_matrixV); - } -} - -/** \internal - * Performs A = A * B exploiting the special structure of the matrix A. Splitting A as: - * A = [A1] - * [A2] - * such that A1.rows()==n1, then we assume that at least half of the columns of A1 and A2 are zeros. - * We can thus pack them prior to the the matrix product. However, this is only worth the effort if the matrix is large - * enough. - */ -template -void BDCSVD::structured_update(Block A, const MatrixXr &B, Index n1) -{ - Index n = A.rows(); - if(n>100) - { - // If the matrices are large enough, let's exploit the sparse structure of A by - // splitting it in half (wrt n1), and packing the non-zero columns. - DenseIndex n2 = n - n1; - MatrixXr A1(n1,n), A2(n2,n), B1(n,n), B2(n,n); - Index k1=0, k2=0; - for(Index j=0; j -void BDCSVD::divide (Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift) -{ - // requires nbRows = nbCols + 1; - using std::pow; - using std::sqrt; - using std::abs; - const Index n = lastCol - firstCol + 1; - const Index k = n/2; - RealScalar alphaK; - RealScalar betaK; - RealScalar r0; - RealScalar lambda, phi, c0, s0; - VectorType l, f; - // We use the other algorithm which is more efficient for small - // matrices. - if (n < m_algoswap) - { - JacobiSVD b(m_computed.block(firstCol, firstCol, n + 1, n), ComputeFullU | (m_compV ? ComputeFullV : 0)) ; - if (m_compU) - m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = b.matrixU(); - else - { - m_naiveU.row(0).segment(firstCol, n + 1).real() = b.matrixU().row(0); - m_naiveU.row(1).segment(firstCol, n + 1).real() = b.matrixU().row(n); - } - if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = b.matrixV(); - m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero(); - m_computed.diagonal().segment(firstCol + shift, n) = b.singularValues().head(n); - return; - } - // We use the divide and conquer algorithm - alphaK = m_computed(firstCol + k, firstCol + k); - betaK = m_computed(firstCol + k + 1, firstCol + k); - // The divide must be done in that order in order to have good results. Divide change the data inside the submatrices - // and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the - // right submatrix before the left one. - divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift); - divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1); - - if (m_compU) - { - lambda = m_naiveU(firstCol + k, firstCol + k); - phi = m_naiveU(firstCol + k + 1, lastCol + 1); - } - else - { - lambda = m_naiveU(1, firstCol + k); - phi = m_naiveU(0, lastCol + 1); - } - r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) + abs(betaK * phi) * abs(betaK * phi)); - if (m_compU) - { - l = m_naiveU.row(firstCol + k).segment(firstCol, k); - f = m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1); - } - else - { - l = m_naiveU.row(1).segment(firstCol, k); - f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1); - } - if (m_compV) m_naiveV(firstRowW+k, firstColW) = 1; - if (r0 == 0) - { - c0 = 1; - s0 = 0; - } - else - { - c0 = alphaK * lambda / r0; - s0 = betaK * phi / r0; - } - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(m_naiveU.allFinite()); - assert(m_naiveV.allFinite()); - assert(m_computed.allFinite()); -#endif - - if (m_compU) - { - MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1)); - // we shiftW Q1 to the right - for (Index i = firstCol + k - 1; i >= firstCol; i--) - m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1); - // we shift q1 at the left with a factor c0 - m_naiveU.col(firstCol).segment( firstCol, k + 1) = (q1 * c0); - // last column = q1 * - s0 - m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * ( - s0)); - // first column = q2 * s0 - m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) = m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0; - // q2 *= c0 - m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0; - } - else - { - RealScalar q1 = (m_naiveU(0, firstCol + k)); - // we shift Q1 to the right - for (Index i = firstCol + k - 1; i >= firstCol; i--) - m_naiveU(0, i + 1) = m_naiveU(0, i); - // we shift q1 at the left with a factor c0 - m_naiveU(0, firstCol) = (q1 * c0); - // last column = q1 * - s0 - m_naiveU(0, lastCol + 1) = (q1 * ( - s0)); - // first column = q2 * s0 - m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) *s0; - // q2 *= c0 - m_naiveU(1, lastCol + 1) *= c0; - m_naiveU.row(1).segment(firstCol + 1, k).setZero(); - m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero(); - } - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(m_naiveU.allFinite()); - assert(m_naiveV.allFinite()); - assert(m_computed.allFinite()); -#endif - - m_computed(firstCol + shift, firstCol + shift) = r0; - m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real(); - m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real(); - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - ArrayXr tmp1 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); -#endif - // Second part: try to deflate singular values in combined matrix - deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - ArrayXr tmp2 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues(); - std::cout << "\n\nj1 = " << tmp1.transpose().format(bdcsvdfmt) << "\n"; - std::cout << "j2 = " << tmp2.transpose().format(bdcsvdfmt) << "\n\n"; - std::cout << "err: " << ((tmp1-tmp2).abs()>1e-12*tmp2.abs()).transpose() << "\n"; - static int count = 0; - std::cout << "# " << ++count << "\n\n"; - assert((tmp1-tmp2).matrix().norm() < 1e-14*tmp2.matrix().norm()); -// assert(count<681); -// assert(((tmp1-tmp2).abs()<1e-13*tmp2.abs()).all()); -#endif - - // Third part: compute SVD of combined matrix - MatrixXr UofSVD, VofSVD; - VectorType singVals; - computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD); - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(UofSVD.allFinite()); - assert(VofSVD.allFinite()); -#endif - - if (m_compU) structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2); - else m_naiveU.middleCols(firstCol, n + 1) *= UofSVD; // FIXME this requires a temporary, and exploit that there are 2 rows at compile time - - if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n+1)/2); - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(m_naiveU.allFinite()); - assert(m_naiveV.allFinite()); - assert(m_computed.allFinite()); -#endif - - m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero(); - m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals; -}// end divide - -// Compute SVD of m_computed.block(firstCol, firstCol, n + 1, n); this block only has non-zeros in -// the first column and on the diagonal and has undergone deflation, so diagonal is in increasing -// order except for possibly the (0,0) entry. The computed SVD is stored U, singVals and V, except -// that if m_compV is false, then V is not computed. Singular values are sorted in decreasing order. -// -// TODO Opportunities for optimization: better root finding algo, better stopping criterion, better -// handling of round-off errors, be consistent in ordering -template -void BDCSVD::computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V) -{ - // TODO Get rid of these copies (?) - // FIXME at least preallocate them - ArrayXr col0 = m_computed.col(firstCol).segment(firstCol, n); - ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); - diag(0) = 0; - - // Allocate space for singular values and vectors - singVals.resize(n); - U.resize(n+1, n+1); - if (m_compV) V.resize(n, n); - - if (col0.hasNaN() || diag.hasNaN()) { std::cout << "\n\nHAS NAN\n\n"; return; } - - // Many singular values might have been deflated, the zero ones have been moved to the end, - // but others are interleaved and we must ignore them at this stage. - // To this end, let's compute a permutation skipping them: - Index actual_n = n; - while(actual_n>1 && diag(actual_n-1)==0) --actual_n; - Index m = 0; // size of the deflated problem - ArrayXi perm(actual_n); - for(Index k=0;k1 && col0(actual_n-1)==0) --actual_n; - std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n"; - std::cout << " check1 (expect0) : " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() << "\n\n"; - std::cout << " check2 (>0) : " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() << "\n\n"; - std::cout << " check3 (>0) : " << ((diag.segment(1,actual_n-1)-singVals.head(actual_n-1).array()) / singVals.head(actual_n-1).array()).transpose() << "\n\n\n"; - std::cout << " check4 (>0) : " << ((singVals.segment(1,actual_n-1)-singVals.head(actual_n-1))).transpose() << "\n\n\n"; - } -#endif - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(singVals.allFinite()); - assert(mus.allFinite()); - assert(shifts.allFinite()); -#endif - - // Compute zhat - perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat); -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << " zhat: " << zhat.transpose() << "\n"; -#endif - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(zhat.allFinite()); -#endif - - computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V); - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() << "\n"; - std::cout << "V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() << "\n"; -#endif - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(U.allFinite()); - assert(V.allFinite()); - assert((U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() < 1e-14 * n); - assert((V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() < 1e-14 * n); - assert(m_naiveU.allFinite()); - assert(m_naiveV.allFinite()); - assert(m_computed.allFinite()); -#endif - - // Because of deflation, the singular values might not be completely sorted. - // Fortunately, reordering them is a O(n) problem - for(Index i=0; isingVals(i+1)) - { - using std::swap; - swap(singVals(i),singVals(i+1)); - U.col(i).swap(U.col(i+1)); - if(m_compV) V.col(i).swap(V.col(i+1)); - } - } - - // Reverse order so that singular values in increased order - // Because of deflation, the zeros singular-values are already at the end - singVals.head(actual_n).reverseInPlace(); - U.leftCols(actual_n) = U.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary - if (m_compV) V.leftCols(actual_n) = V.leftCols(actual_n).rowwise().reverse().eval(); // FIXME this requires a temporary - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - JacobiSVD jsvd(m_computed.block(firstCol, firstCol, n, n) ); - std::cout << " * j: " << jsvd.singularValues().transpose() << "\n\n"; - std::cout << " * sing-val: " << singVals.transpose() << "\n"; -// std::cout << " * err: " << ((jsvd.singularValues()-singVals)>1e-13*singVals.norm()).transpose() << "\n"; -#endif -} - -template -typename BDCSVD::RealScalar BDCSVD::secularEq(RealScalar mu, const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const ArrayXr& diagShifted, RealScalar shift) -{ - Index m = perm.size(); - RealScalar res = 1; - for(Index i=0; i -void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, - VectorType& singVals, ArrayXr& shifts, ArrayXr& mus) -{ - using std::abs; - using std::swap; - - Index n = col0.size(); - Index actual_n = n; - while(actual_n>1 && col0(actual_n-1)==0) --actual_n; - - for (Index k = 0; k < n; ++k) - { - if (col0(k) == 0 || actual_n==1) - { - // if col0(k) == 0, then entry is deflated, so singular value is on diagonal - // if actual_n==1, then the deflated problem is already diagonalized - singVals(k) = k==0 ? col0(0) : diag(k); - mus(k) = 0; - shifts(k) = k==0 ? col0(0) : diag(k); - continue; - } - - // otherwise, use secular equation to find singular value - RealScalar left = diag(k); - RealScalar right; // was: = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm()); - if(k==actual_n-1) - right = (diag(actual_n-1) + col0.matrix().norm()); - else - { - // Skip deflated singular values - Index l = k+1; - while(col0(l)==0) { ++l; eigen_internal_assert(l 0) ? left : right; - - // measure everything relative to shift - ArrayXr diagShifted = diag - shift; - - // initial guess - RealScalar muPrev, muCur; - if (shift == left) - { - muPrev = (right - left) * 0.1; - if (k == actual_n-1) muCur = right - left; - else muCur = (right - left) * 0.5; - } - else - { - muPrev = -(right - left) * 0.1; - muCur = -(right - left) * 0.5; - } - - RealScalar fPrev = secularEq(muPrev, col0, diag, perm, diagShifted, shift); - RealScalar fCur = secularEq(muCur, col0, diag, perm, diagShifted, shift); - if (abs(fPrev) < abs(fCur)) - { - swap(fPrev, fCur); - swap(muPrev, muCur); - } - - // rational interpolation: fit a function of the form a / mu + b through the two previous - // iterates and use its zero to compute the next iterate - bool useBisection = fPrev*fCur>0; - while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits::epsilon() * numext::maxi(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits::epsilon() && !useBisection) - { - ++m_numIters; - - // Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples. - RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); - RealScalar b = fCur - a / muCur; - // And find mu such that f(mu)==0: - RealScalar muZero = -a/b; - RealScalar fZero = secularEq(muZero, col0, diag, perm, diagShifted, shift); - - muPrev = muCur; - fPrev = fCur; - muCur = muZero; - fCur = fZero; - - - if (shift == left && (muCur < 0 || muCur > right - left)) useBisection = true; - if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true; - if (abs(fCur)>abs(fPrev)) useBisection = true; - } - - // fall back on bisection method if rational interpolation did not work - if (useBisection) - { -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "useBisection for k = " << k << ", actual_n = " << actual_n << "\n"; -#endif - RealScalar leftShifted, rightShifted; - if (shift == left) - { - leftShifted = RealScalar(1)/NumTraits::highest(); - // I don't understand why the case k==0 would be special there: - // if (k == 0) rightShifted = right - left; else - rightShifted = (k==actual_n-1) ? right : ((right - left) * 0.6); // theoretically we can take 0.5, but let's be safe - } - else - { - leftShifted = -(right - left) * 0.6; - rightShifted = -RealScalar(1)/NumTraits::highest(); - } - - RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift); - RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift); - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - if(!(fLeft * fRight<0)) - std::cout << k << " : " << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; " << left << " - " << right << " -> " << leftShifted << " " << rightShifted << " shift=" << shift << "\n"; -#endif - eigen_internal_assert(fLeft * fRight < 0); - - while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * numext::maxi(abs(leftShifted), abs(rightShifted))) - { - RealScalar midShifted = (leftShifted + rightShifted) / 2; - RealScalar fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift); - if (fLeft * fMid < 0) - { - rightShifted = midShifted; - fRight = fMid; - } - else - { - leftShifted = midShifted; - fLeft = fMid; - } - } - - muCur = (leftShifted + rightShifted) / 2; - } - - singVals[k] = shift + muCur; - shifts[k] = shift; - mus[k] = muCur; - - // perturb singular value slightly if it equals diagonal entry to avoid division by zero later - // (deflation is supposed to avoid this from happening) - // - this does no seem to be necessary anymore - -// if (singVals[k] == left) singVals[k] *= 1 + NumTraits::epsilon(); -// if (singVals[k] == right) singVals[k] *= 1 - NumTraits::epsilon(); - } -} - - -// zhat is perturbation of col0 for which singular vectors can be computed stably (see Section 3.1) -template -void BDCSVD::perturbCol0 - (const ArrayXr& col0, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, - const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) -{ - using std::sqrt; - Index n = col0.size(); - Index m = perm.size(); - if(m==0) - { - zhat.setZero(); - return; - } - Index last = perm(m-1); - // The offset permits to skip deflated entries while computing zhat - for (Index k = 0; k < n; ++k) - { - if (col0(k) == 0) // deflated - zhat(k) = 0; - else - { - // see equation (3.6) - RealScalar dk = diag(k); - RealScalar prod = (singVals(last) + dk) * (mus(last) + (shifts(last) - dk)); - - for(Index l = 0; l 0.9 ) - std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk)) - << ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n"; -#endif - } - } -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(last) + dk) << " * " << mus(last) + shifts(last) << " - " << dk << "\n"; -#endif - RealScalar tmp = sqrt(prod); - zhat(k) = col0(k) > 0 ? tmp : -tmp; - } - } -} - -// compute singular vectors -template -void BDCSVD::computeSingVecs - (const ArrayXr& zhat, const ArrayXr& diag, const ArrayXi &perm, const VectorType& singVals, - const ArrayXr& shifts, const ArrayXr& mus, MatrixXr& U, MatrixXr& V) -{ - Index n = zhat.size(); - Index m = perm.size(); - - for (Index k = 0; k < n; ++k) - { - if (zhat(k) == 0) - { - U.col(k) = VectorType::Unit(n+1, k); - if (m_compV) V.col(k) = VectorType::Unit(n, k); - } - else - { - U.col(k).setZero(); - for(Index l=0;l= 1, di almost null and zi non null. -// We use a rotation to zero out zi applied to the left of M -template -void BDCSVD::deflation43(Index firstCol, Index shift, Index i, Index size) -{ - using std::abs; - using std::sqrt; - using std::pow; - Index start = firstCol + shift; - RealScalar c = m_computed(start, start); - RealScalar s = m_computed(start+i, start); - RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); - if (r == 0) - { - m_computed(start+i, start+i) = 0; - return; - } - m_computed(start,start) = r; - m_computed(start+i, start) = 0; - m_computed(start+i, start+i) = 0; - - JacobiRotation J(c/r,-s/r); - if (m_compU) m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J); - else m_naiveU.applyOnTheRight(firstCol, firstCol+i, J); -}// end deflation 43 - - -// page 13 -// i,j >= 1, i!=j and |di - dj| < epsilon * norm2(M) -// We apply two rotations to have zj = 0; -// TODO deflation44 is still broken and not properly tested -template -void BDCSVD::deflation44(Index firstColu , Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size) -{ - using std::abs; - using std::sqrt; - using std::conj; - using std::pow; - RealScalar c = m_computed(firstColm+i, firstColm); - RealScalar s = m_computed(firstColm+j, firstColm); - RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s)); -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; " - << m_computed(firstColm + i-1, firstColm) << " " - << m_computed(firstColm + i, firstColm) << " " - << m_computed(firstColm + i+1, firstColm) << " " - << m_computed(firstColm + i+2, firstColm) << "\n"; - std::cout << m_computed(firstColm + i-1, firstColm + i-1) << " " - << m_computed(firstColm + i, firstColm+i) << " " - << m_computed(firstColm + i+1, firstColm+i+1) << " " - << m_computed(firstColm + i+2, firstColm+i+2) << "\n"; -#endif - if (r==0) - { - m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); - return; - } - c/=r; - s/=r; - m_computed(firstColm + i, firstColm) = r; - m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i); - m_computed(firstColm + j, firstColm) = 0; - - JacobiRotation J(c,-s); - if (m_compU) m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J); - else m_naiveU.applyOnTheRight(firstColu+i, firstColu+j, J); - if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J); -}// end deflation 44 - - -// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive] -template -void BDCSVD::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift) -{ - using std::sqrt; - using std::abs; - const Index length = lastCol + 1 - firstCol; - - Block col0(m_computed, firstCol+shift, firstCol+shift, length, 1); - Diagonal fulldiag(m_computed); - VectorBlock,Dynamic> diag(fulldiag, firstCol+shift, length); - - RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff(); - RealScalar epsilon_strict = NumTraits::epsilon() * maxDiag; - RealScalar epsilon_coarse = 8 * NumTraits::epsilon() * numext::maxi(col0.cwiseAbs().maxCoeff(), maxDiag); - -#ifdef EIGEN_BDCSVD_SANITY_CHECKS - assert(m_naiveU.allFinite()); - assert(m_naiveV.allFinite()); - assert(m_computed.allFinite()); -#endif - -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "\ndeflate:" << diag.head(k+1).transpose() << " | " << diag.segment(k+1,length-k-1).transpose() << "\n"; -#endif - - //condition 4.1 - if (diag(0) < epsilon_coarse) - { -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon_coarse << "\n"; -#endif - diag(0) = epsilon_coarse; - } - - //condition 4.2 - for (Index i=1;i k) permutation[p] = j++; - else if (j >= length) permutation[p] = i++; - else if (diag(i) < diag(j)) permutation[p] = j++; - else permutation[p] = i++; - } - } - - // If we have a total deflation, then we have to insert diag(0) at the right place - if(total_deflation) - { - for(Index i=1; i0 && (diag(i)==0 || col0(i)==0)) --i; - for(; i>1;--i) - if( (diag(i) - diag(i-1)) < NumTraits::epsilon()*maxDiag ) - { -#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE - std::cout << "deflation 4.4 with i = " << i << " because " << (diag(i) - diag(i-1)) << " < " << NumTraits::epsilon()*diag(i) << "\n"; -#endif - eigen_internal_assert(abs(diag(i) - diag(i-1)) -BDCSVD::PlainObject> -MatrixBase::bdcSvd(unsigned int computationOptions) const -{ - return BDCSVD(*this, computationOptions); -} -*/ - -} // end namespace Eigen - -#endif diff --git a/unsupported/Eigen/src/BDCSVD/CMakeLists.txt b/unsupported/Eigen/src/BDCSVD/CMakeLists.txt deleted file mode 100644 index 1045512f9..000000000 --- a/unsupported/Eigen/src/BDCSVD/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_BDCSVD_SRCS "*.h") - -INSTALL(FILES - ${Eigen_BDCSVD_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/BDCSVD COMPONENT Devel - ) diff --git a/unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt b/unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt deleted file mode 100644 index 9b7bf9314..000000000 --- a/unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt +++ /dev/null @@ -1,13 +0,0 @@ -TO DO LIST - -- check more carefully single precision -- check with duplicated singularvalues -- no-malloc mode - -(optional optimization) -- do all the allocations in the allocate part -- support static matrices -- return a error at compilation time when using integer matrices (int, long, std::complex, ...) -- To solve the secular equation using FMM: -http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf - diff --git a/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt b/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt deleted file mode 100644 index 29ab9cd40..000000000 --- a/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt +++ /dev/null @@ -1,8 +0,0 @@ -This unsupported package is about a divide and conquer algorithm to compute SVD. - -The implementation follows as closely as possible the following reference paper : -http://www.cs.yale.edu/publications/techreports/tr933.pdf - -To solve the secular equation using FMM: -http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf - diff --git a/unsupported/Eigen/src/CMakeLists.txt b/unsupported/Eigen/src/CMakeLists.txt index 654a2327f..8eb2808e3 100644 --- a/unsupported/Eigen/src/CMakeLists.txt +++ b/unsupported/Eigen/src/CMakeLists.txt @@ -12,4 +12,3 @@ ADD_SUBDIRECTORY(Skyline) ADD_SUBDIRECTORY(SparseExtra) ADD_SUBDIRECTORY(KroneckerProduct) ADD_SUBDIRECTORY(Splines) -ADD_SUBDIRECTORY(BDCSVD) diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 48b61cde0..97849a25a 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -92,7 +92,6 @@ ei_add_test(splines) ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) -ei_add_test(bdcsvd) ei_add_test(kronecker_product) option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF) diff --git a/unsupported/test/bdcsvd.cpp b/unsupported/test/bdcsvd.cpp deleted file mode 100644 index 97d7880bb..000000000 --- a/unsupported/test/bdcsvd.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2013 Gauthier Brun -// Copyright (C) 2013 Nicolas Carre -// Copyright (C) 2013 Jean Ceccato -// Copyright (C) 2013 Pierre Zoppitelli -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/ - -// discard stack allocation as that too bypasses malloc -#define EIGEN_STACK_ALLOCATION_LIMIT 0 -#define EIGEN_RUNTIME_NO_MALLOC - -#include "main.h" -#include -#include -#include - - -#define SVD_DEFAULT(M) BDCSVD -#define SVD_FOR_MIN_NORM(M) BDCSVD -#include "../../test/svd_common.h" - -// Check all variants of JacobiSVD -template -void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) -{ - MatrixType m = a; - if(pickrandom) - svd_fill_random(m); - - CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); -} - -// template -// void bdcsvd_method() -// { -// enum { Size = MatrixType::RowsAtCompileTime }; -// typedef typename MatrixType::RealScalar RealScalar; -// typedef Matrix RealVecType; -// MatrixType m = MatrixType::Identity(); -// VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones()); -// VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU()); -// VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV()); -// VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m); -// } - -// compare the Singular values returned with Jacobi and Bdc -template -void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0) -{ - MatrixType m = MatrixType::Random(a.rows(), a.cols()); - BDCSVD bdc_svd(m); - JacobiSVD jacobi_svd(m); - VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues()); - if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); - if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); - if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); - if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); -} - -void test_bdcsvd() -{ - CALL_SUBTEST_3(( svd_verify_assert >(Matrix3f()) )); - CALL_SUBTEST_4(( svd_verify_assert >(Matrix4d()) )); - CALL_SUBTEST_7(( svd_verify_assert >(MatrixXf(10,12)) )); - CALL_SUBTEST_8(( svd_verify_assert >(MatrixXcd(7,5)) )); - - CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); - CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd) )); - - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_3(( bdcsvd() )); - CALL_SUBTEST_4(( bdcsvd() )); - CALL_SUBTEST_5(( bdcsvd >() )); - - int r = internal::random(1, EIGEN_TEST_MAX_SIZE/2), - c = internal::random(1, EIGEN_TEST_MAX_SIZE/2); - - TEST_SET_BUT_UNUSED_VARIABLE(r) - TEST_SET_BUT_UNUSED_VARIABLE(c) - - CALL_SUBTEST_6(( bdcsvd(Matrix(r,2)) )); - CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); - CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) )); - CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) )); - CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) )); - CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); - CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) )); - - // Test on inf/nan matrix - CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); - CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); - } - - // test matrixbase method -// CALL_SUBTEST_1(( bdcsvd_method() )); -// CALL_SUBTEST_3(( bdcsvd_method() )); - - // Test problem size constructors - CALL_SUBTEST_7( BDCSVD(10,10) ); - - // Check that preallocation avoids subsequent mallocs - CALL_SUBTEST_9( svd_preallocate() ); - - CALL_SUBTEST_2( svd_underoverflow() ); -} - -- cgit v1.2.3 From acecb7b09f36d8a073ebf399d9c9f038dd6fe3c2 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Wed, 29 Oct 2014 17:46:33 +0100 Subject: Fixed include in bdcsvd.cpp --- test/bdcsvd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bdcsvd.cpp b/test/bdcsvd.cpp index d58d259d6..52a02b697 100644 --- a/test/bdcsvd.cpp +++ b/test/bdcsvd.cpp @@ -22,7 +22,7 @@ #define SVD_DEFAULT(M) BDCSVD #define SVD_FOR_MIN_NORM(M) BDCSVD -#include "../../test/svd_common.h" +#include "svd_common.h" // Check all variants of JacobiSVD template -- cgit v1.2.3 From 3d25b1f5b8694638659217cf67d86534afd8db28 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Wed, 29 Oct 2014 17:46:54 +0100 Subject: Split up some test cases --- test/eigensolver_selfadjoint.cpp | 11 +++++++---- test/jacobisvd.cpp | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 8ff48462e..935736328 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -145,11 +145,14 @@ void test_eigensolver_selfadjoint() { int s = 0; for(int i = 0; i < g_repeat; i++) { + // trivial test for 1x1 matrices: + CALL_SUBTEST_1( selfadjointeigensolver(Matrix())); + CALL_SUBTEST_1( selfadjointeigensolver(Matrix())); // very important to test 3x3 and 2x2 matrices since we provide special paths for them - CALL_SUBTEST_1( selfadjointeigensolver(Matrix2f()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix3d()) ); + CALL_SUBTEST_12( selfadjointeigensolver(Matrix2f()) ); + CALL_SUBTEST_12( selfadjointeigensolver(Matrix2d()) ); + CALL_SUBTEST_13( selfadjointeigensolver(Matrix3f()) ); + CALL_SUBTEST_13( selfadjointeigensolver(Matrix3d()) ); CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) ); s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) ); diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index bfcadce95..f9de6b708 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -77,8 +77,8 @@ void test_jacobisvd() CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) )); CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) )); - svd_all_trivial_2x2(jacobisvd); - svd_all_trivial_2x2(jacobisvd); + CALL_SUBTEST_11(svd_all_trivial_2x2(jacobisvd)); + CALL_SUBTEST_12(svd_all_trivial_2x2(jacobisvd)); for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_3(( jacobisvd() )); -- cgit v1.2.3 From d2fc597d5b05aaa4531ff6daede9a47c739eb70e Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Wed, 29 Oct 2014 17:51:14 +0100 Subject: Removed deprecated header (unsupported/Eigen/BDCSVD is included in Eigen/SVD now) --- lapack/svd.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lapack/svd.cpp b/lapack/svd.cpp index ecac3bab1..df77a371c 100644 --- a/lapack/svd.cpp +++ b/lapack/svd.cpp @@ -9,7 +9,6 @@ #include "lapack_common.h" #include -#include // computes the singular values/vectors a general M-by-N matrix A using divide-and-conquer EIGEN_LAPACK_FUNC(gesdd,(char *jobz, int *m, int* n, Scalar* a, int *lda, RealScalar *s, Scalar *u, int *ldu, Scalar *vt, int *ldvt, Scalar* /*work*/, int* lwork, -- cgit v1.2.3 From e5f134006b431d7d307c8ce7706c5aa1df09895c Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Thu, 30 Oct 2014 19:59:09 +0100 Subject: EIGEN_UNUSED_VARIABLE works better than casting to void. Make this also usable from CUDA code --- Eigen/src/Core/util/Macros.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index c09854951..61d7be752 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -251,7 +251,7 @@ #endif #ifdef EIGEN_NO_DEBUG -#define EIGEN_ONLY_USED_FOR_DEBUG(x) (void)x +#define EIGEN_ONLY_USED_FOR_DEBUG(x) EIGEN_UNUSED_VARIABLE(x) #else #define EIGEN_ONLY_USED_FOR_DEBUG(x) #endif @@ -277,7 +277,7 @@ // Suppresses 'unused variable' warnings. namespace Eigen { namespace internal { - template void ignore_unused_variable(const T&) {} + template EIGEN_DEVICE_FUNC void ignore_unused_variable(const T&) {} } } #define EIGEN_UNUSED_VARIABLE(var) Eigen::internal::ignore_unused_variable(var); -- cgit v1.2.3 From 883168ed94ca2559231861957558a9ded13e4831 Mon Sep 17 00:00:00 2001 From: Christoph Hertzberg Date: Thu, 30 Oct 2014 20:16:16 +0100 Subject: Make select CUDA compatible (comparison operators aren't yet, so no test case yet) --- Eigen/src/Core/CoreEvaluators.h | 6 +++--- Eigen/src/Core/Select.h | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 836d25b3b..a0dc72c4d 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -859,7 +859,7 @@ struct evaluator > Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits }; - EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) + inline EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), m_thenImpl(select.thenMatrix()), m_elseImpl(select.elseMatrix()) @@ -868,7 +868,7 @@ struct evaluator > typedef typename XprType::Index Index; typedef typename XprType::CoeffReturnType CoeffReturnType; - EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const + inline EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { if (m_conditionImpl.coeff(row, col)) return m_thenImpl.coeff(row, col); @@ -876,7 +876,7 @@ struct evaluator > return m_elseImpl.coeff(row, col); } - EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + inline EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { if (m_conditionImpl.coeff(index)) return m_thenImpl.coeff(index); diff --git a/Eigen/src/Core/Select.h b/Eigen/src/Core/Select.h index 0cb85a4ad..0c09a4ff4 100644 --- a/Eigen/src/Core/Select.h +++ b/Eigen/src/Core/Select.h @@ -57,6 +57,7 @@ class Select : internal::no_assignment_operator, typedef typename internal::dense_xpr_base