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 305aa1f9c570db60a92e49020f21e70311bbed36 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 10:47:40 +0200 Subject: Add examples for hnormalized and homogenous (fix bug #846) --- Eigen/src/Geometry/Homogeneous.h | 4 ++-- doc/snippets/DirectionWise_hnormalized.cpp | 7 +++++++ doc/snippets/MatrixBase_hnormalized.cpp | 6 ++++++ doc/snippets/MatrixBase_homogeneous.cpp | 6 ++++++ doc/snippets/VectorwiseOp_homogeneous.cpp | 7 +++++++ 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 doc/snippets/DirectionWise_hnormalized.cpp create mode 100644 doc/snippets/MatrixBase_hnormalized.cpp create mode 100644 doc/snippets/MatrixBase_homogeneous.cpp create mode 100644 doc/snippets/VectorwiseOp_homogeneous.cpp diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 00e71d190..97dd21d15 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -120,7 +120,7 @@ template class Homogeneous * Example: \include MatrixBase_homogeneous.cpp * Output: \verbinclude MatrixBase_homogeneous.out * - * \sa class Homogeneous + * \sa VectorwiseOp::homogeneous(), class Homogeneous */ template inline typename MatrixBase::HomogeneousReturnType @@ -137,7 +137,7 @@ MatrixBase::homogeneous() const * Example: \include VectorwiseOp_homogeneous.cpp * Output: \verbinclude VectorwiseOp_homogeneous.out * - * \sa MatrixBase::homogeneous() */ + * \sa MatrixBase::homogeneous(), class Homogeneous */ template inline Homogeneous VectorwiseOp::homogeneous() const diff --git a/doc/snippets/DirectionWise_hnormalized.cpp b/doc/snippets/DirectionWise_hnormalized.cpp new file mode 100644 index 000000000..3410790a8 --- /dev/null +++ b/doc/snippets/DirectionWise_hnormalized.cpp @@ -0,0 +1,7 @@ +typedef Matrix Matrix4Xd; +Matrix4Xd M = Matrix4Xd::Random(4,5); +Projective3d P(Matrix4d::Random()); +cout << "The matrix M is:" << endl << M << endl << endl; +cout << "M.colwise().hnormalized():" << endl << M.colwise().hnormalized() << endl << endl; +cout << "P*M:" << endl << P*M << endl << endl; +cout << "(P*M).colwise().hnormalized():" << endl << (P*M).colwise().hnormalized() << endl << endl; \ No newline at end of file diff --git a/doc/snippets/MatrixBase_hnormalized.cpp b/doc/snippets/MatrixBase_hnormalized.cpp new file mode 100644 index 000000000..652cd77c0 --- /dev/null +++ b/doc/snippets/MatrixBase_hnormalized.cpp @@ -0,0 +1,6 @@ +Vector4d v = Vector4d::Random(); +Projective3d P(Matrix4d::Random()); +cout << "v = " << v.transpose() << "]^T" << endl; +cout << "v.hnormalized() = " << v.hnormalized().transpose() << "]^T" << endl; +cout << "P*v = " << (P*v).transpose() << "]^T" << endl; +cout << "(P*v).hnormalized() = " << (P*v).hnormalized().transpose() << "]^T" << endl; \ No newline at end of file diff --git a/doc/snippets/MatrixBase_homogeneous.cpp b/doc/snippets/MatrixBase_homogeneous.cpp new file mode 100644 index 000000000..457c28f91 --- /dev/null +++ b/doc/snippets/MatrixBase_homogeneous.cpp @@ -0,0 +1,6 @@ +Vector3d v = Vector3d::Random(), w; +Projective3d P(Matrix4d::Random()); +cout << "v = [" << v.transpose() << "]^T" << endl; +cout << "h.homogeneous() = [" << v.homogeneous().transpose() << "]^T" << endl; +cout << "(P * v.homogeneous()) = [" << (P * v.homogeneous()).transpose() << "]^T" << endl; +cout << "(P * v.homogeneous()).hnormalized() = [" << (P * v.homogeneous()).eval().hnormalized().transpose() << "]^T" << endl; \ No newline at end of file diff --git a/doc/snippets/VectorwiseOp_homogeneous.cpp b/doc/snippets/VectorwiseOp_homogeneous.cpp new file mode 100644 index 000000000..aba4fed0e --- /dev/null +++ b/doc/snippets/VectorwiseOp_homogeneous.cpp @@ -0,0 +1,7 @@ +typedef Matrix Matrix3Xd; +Matrix3Xd M = Matrix3Xd::Random(3,5); +Projective3d P(Matrix4d::Random()); +cout << "The matrix M is:" << endl << M << endl << endl; +cout << "M.colwise().homogeneous():" << endl << M.colwise().homogeneous() << endl << endl; +cout << "P * M.colwise().homogeneous():" << endl << P * M.colwise().homogeneous() << endl << endl; +cout << "P * M.colwise().homogeneous().hnormalized(): " << endl << (P * M.colwise().homogeneous()).colwise().hnormalized() << endl << endl; \ No newline at end of file -- cgit v1.2.3 From 3eb5253ca1352391f4ea31c4a2dd06c34c4a33e7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 14:41:14 +0200 Subject: Optimization: "matrix * real" did not call the special path and the real was converted to a complex. Add respective unit test to avoid future regression. --- Eigen/src/Core/MatrixBase.h | 1 + Eigen/src/Core/util/XprHelper.h | 10 +++++++++- test/linearstructure.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index f5987d194..3cb5e04fd 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -81,6 +81,7 @@ template class MatrixBase using Base::operator-=; using Base::operator*=; using Base::operator/=; + using Base::operator*; typedef typename Base::CoeffReturnType CoeffReturnType; typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index 1b3e122e1..7c77b2263 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -383,13 +383,21 @@ struct special_scalar_op_base : public DenseCo const CwiseUnaryOp, Derived> operator*(const OtherScalar& scalar) const { +#ifdef EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN + EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN +#endif return CwiseUnaryOp, Derived> (*static_cast(this), scalar_multiple2_op(scalar)); } inline friend const CwiseUnaryOp, Derived> operator*(const OtherScalar& scalar, const Derived& matrix) - { return static_cast(matrix).operator*(scalar); } + { +#ifdef EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN + EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN +#endif + return static_cast(matrix).operator*(scalar); + } }; template struct cast_return_type diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp index 618984d5c..b627915ce 100644 --- a/test/linearstructure.cpp +++ b/test/linearstructure.cpp @@ -2,11 +2,16 @@ // for linear algebra. // // Copyright (C) 2006-2008 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/. +static bool g_called; + +#define EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN { g_called = true; } + #include "main.h" template void linearStructure(const MatrixType& m) @@ -68,6 +73,24 @@ template void linearStructure(const MatrixType& m) VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1); } +// Make sure that complex * real and real * complex are properly optimized +template void real_complex(DenseIndex rows = MatrixType::RowsAtCompileTime, DenseIndex cols = MatrixType::ColsAtCompileTime) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + RealScalar s = internal::random(); + MatrixType m1 = MatrixType::Random(rows, cols); + + g_called = false; + VERIFY_IS_APPROX(s*m1, Scalar(s)*m1); + VERIFY(g_called && "real * matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1*s, m1*Scalar(s)); + VERIFY(g_called && "matrix * real not properly optimized"); +} + void test_linearstructure() { for(int i = 0; i < g_repeat; i++) { @@ -80,5 +103,8 @@ void test_linearstructure() CALL_SUBTEST_7( linearStructure(MatrixXi (internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_8( linearStructure(MatrixXcd(internal::random(1,EIGEN_TEST_MAX_SIZE/2), internal::random(1,EIGEN_TEST_MAX_SIZE/2))) ); CALL_SUBTEST_9( linearStructure(ArrayXXf (internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + + CALL_SUBTEST_10( real_complex() ); + CALL_SUBTEST_10( real_complex(10,10) ); } } -- cgit v1.2.3 From 18fbe7e7d4cdb737ef5775bbb32fe62b6f8ef70e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 14:49:23 +0200 Subject: Fix stableNorm() with respect to NaN and inf, and add respective unit tests. blueNorm() and hypotNorm() are broken wrt to NaN/inf --- Eigen/src/Core/StableNorm.h | 11 +++++++- test/stable_norm.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index 525620bad..07a021505 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -20,7 +20,7 @@ inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& sc using std::max; Scalar maxCoeff = bl.cwiseAbs().maxCoeff(); - if (maxCoeff>scale) + if(maxCoeff>scale) { ssq = ssq * numext::abs2(scale/maxCoeff); Scalar tmp = Scalar(1)/maxCoeff; @@ -29,12 +29,21 @@ inline void stable_norm_kernel(const ExpressionType& bl, Scalar& ssq, Scalar& sc invScale = NumTraits::highest(); scale = Scalar(1)/invScale; } + else if(maxCoeff>NumTraits::highest()) // we got a INF + { + invScale = Scalar(1); + scale = maxCoeff; + } else { scale = maxCoeff; invScale = tmp; } } + else if(maxCoeff!=maxCoeff) // we got a NaN + { + scale = maxCoeff; + } // TODO if the maxCoeff is much much smaller than the current scale, // then we can neglect this sub vector diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 549f91fbf..88cab7aa3 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -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 @@ -14,6 +14,21 @@ 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(); +} + // workaround aggressive optimization in ICC template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } @@ -106,6 +121,58 @@ template void stable_norm(const MatrixType& m) VERIFY_IS_APPROX(vrand.rowwise().stableNorm(), vrand.rowwise().norm()); VERIFY_IS_APPROX(vrand.rowwise().blueNorm(), vrand.rowwise().norm()); VERIFY_IS_APPROX(vrand.rowwise().hypotNorm(), vrand.rowwise().norm()); + + // test NaN, +inf, -inf + MatrixType v; + Index i = internal::random(0,rows-1); + Index j = internal::random(0,cols-1); + + // NaN + { + v = vrand; + v(i,j) = RealScalar(0)/RealScalar(0); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); +// VERIFY(!isFinite(v.hypotNorm())); //VERIFY(isNaN(v.hypotNorm())); + } + + // +inf + { + v = vrand; + v(i,j) = RealScalar(1)/RealScalar(0); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); +// VERIFY(!isFinite(v.blueNorm())); //VERIFY(isInf(v.blueNorm())); +// VERIFY(!isFinite(v.hypotNorm())); //VERIFY(isInf(v.hypotNorm())); + } + + // -inf + { + v = vrand; + v(i,j) = RealScalar(-1)/RealScalar(0); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); +// VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); +// VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); + } + + // mix + { + 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); + VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); + VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); + VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); +// VERIFY(!isFinite(v.blueNorm())); //VERIFY(isNaN(v.blueNorm())); +// VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); + } } void test_stable_norm() -- cgit v1.2.3 From a44a343f034eb915f9ad6dcd69e4be534d48bbe5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 15:06:24 +0200 Subject: Fix blueNorm wrt NaN/INF. --- Eigen/src/Core/StableNorm.h | 11 +++++------ test/stable_norm.cpp | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index 07a021505..64d43e1b1 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -64,7 +64,7 @@ blueNorm_impl(const EigenBase& _vec) using std::abs; const Derived& vec(_vec.derived()); static bool initialized = false; - static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr; + static RealScalar b1, b2, s1m, s2m, rbig, relerr; if(!initialized) { int ibeta, it, iemin, iemax, iexp; @@ -93,7 +93,6 @@ blueNorm_impl(const EigenBase& _vec) iexp = - ((iemax+it)/2); s2m = RealScalar(pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for upper range - overfl = rbig*s2m; // overflow boundary for abig eps = RealScalar(pow(double(ibeta), 1-it)); relerr = sqrt(eps); // tolerance for neglecting asml initialized = true; @@ -110,13 +109,13 @@ blueNorm_impl(const EigenBase& _vec) else if(ax < b1) asml += numext::abs2(ax*s1m); else amed += numext::abs2(ax); } + if(amed!=amed) + return amed; // we got a NaN if(abig > RealScalar(0)) { abig = sqrt(abig); - if(abig > overfl) - { - return rbig; - } + if(abig > rbig) // overflow, or *this contains INF values + return abig; // return INF if(amed > RealScalar(0)) { abig = abig/s2m; diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 88cab7aa3..119b5b424 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -145,7 +145,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); -// VERIFY(!isFinite(v.blueNorm())); //VERIFY(isInf(v.blueNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); // VERIFY(!isFinite(v.hypotNorm())); //VERIFY(isInf(v.hypotNorm())); } @@ -156,7 +156,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); -// VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); // VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); } @@ -170,7 +170,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm())); VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); -// VERIFY(!isFinite(v.blueNorm())); //VERIFY(isNaN(v.blueNorm())); + VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); // VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); } } -- cgit v1.2.3 From 42e27d41a2014043799b44b68b0d5644629279ba Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 16:09:39 +0200 Subject: Fix hypot() and hypotNorm() wrt NaN and INF values. --- Eigen/src/Core/MathFunctions.h | 15 +++++++++++---- Eigen/src/Core/functors/BinaryFunctors.h | 14 +++++++++++--- test/stable_norm.cpp | 8 ++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 20fc2be74..5df1fbfec 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -308,10 +308,17 @@ struct hypot_impl using std::sqrt; RealScalar _x = abs(x); RealScalar _y = abs(y); - RealScalar p = (max)(_x, _y); - if(p==RealScalar(0)) return 0; - RealScalar q = (min)(_x, _y); - RealScalar qp = q/p; + Scalar p, qp; + if(_x>_y) + { + p = _x; + qp = _y / p; + } + else + { + p = _y; + qp = _x / p; + } return p * sqrt(RealScalar(1) + qp*qp); } }; diff --git a/Eigen/src/Core/functors/BinaryFunctors.h b/Eigen/src/Core/functors/BinaryFunctors.h index ba094f5d1..157d075a7 100644 --- a/Eigen/src/Core/functors/BinaryFunctors.h +++ b/Eigen/src/Core/functors/BinaryFunctors.h @@ -167,9 +167,17 @@ template struct scalar_hypot_op { EIGEN_USING_STD_MATH(max); EIGEN_USING_STD_MATH(min); using std::sqrt; - Scalar p = (max)(_x, _y); - Scalar q = (min)(_x, _y); - Scalar qp = q/p; + Scalar p, qp; + if(_x>_y) + { + p = _x; + qp = _y / p; + } + else + { + p = _y; + qp = _x / p; + } return p * sqrt(Scalar(1) + qp*qp); } }; diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 119b5b424..f76919af4 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -135,7 +135,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); -// VERIFY(!isFinite(v.hypotNorm())); //VERIFY(isNaN(v.hypotNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); } // +inf @@ -146,7 +146,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); -// VERIFY(!isFinite(v.hypotNorm())); //VERIFY(isInf(v.hypotNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); } // -inf @@ -157,7 +157,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm())); VERIFY(!isFinite(v.blueNorm())); VERIFY(isInf(v.blueNorm())); -// VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isInf(v.hypotNorm())); } // mix @@ -171,7 +171,7 @@ template void stable_norm(const MatrixType& m) VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm())); VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm())); VERIFY(!isFinite(v.blueNorm())); VERIFY(isNaN(v.blueNorm())); -// VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); + VERIFY(!isFinite(v.hypotNorm())); VERIFY(isNaN(v.hypotNorm())); } } -- cgit v1.2.3 From ff9bfc45f74249a8aabf10df6be8ac1bfcc9ee5e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 17:10:17 +0200 Subject: relax some LM unit tests --- unsupported/test/NonLinearOptimization.cpp | 17 ++++++------ unsupported/test/levenberg_marquardt.cpp | 44 ++++++++++++++++-------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index d7376b0f5..702bb7c60 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -1262,8 +1262,8 @@ void testNistBoxBOD(void) // check return value VERIFY_IS_EQUAL(info, 1); - VERIFY_IS_EQUAL(lm.nfev, 31); - VERIFY_IS_EQUAL(lm.njev, 25); + VERIFY(lm.nfev < 31); // 31 + VERIFY(lm.njev < 25); // 25 // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03); // check x @@ -1342,10 +1342,6 @@ void testNistMGH17(void) lm.parameters.maxfev = 1000; info = lm.minimize(x); - // check return value - VERIFY_IS_EQUAL(info, 2); - VERIFY_IS_EQUAL(lm.nfev, 602 ); - VERIFY_IS_EQUAL(lm.njev, 545 ); // check norm^2 VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05); // check x @@ -1354,6 +1350,11 @@ void testNistMGH17(void) VERIFY_IS_APPROX(x[2], -1.4646871366E+00); VERIFY_IS_APPROX(x[3], 1.2867534640E-02); VERIFY_IS_APPROX(x[4], 2.2122699662E-02); + + // check return value + VERIFY_IS_EQUAL(info, 2); + VERIFY(lm.nfev < 650); // 602 + VERIFY(lm.njev < 600); // 545 /* * Second try @@ -1832,8 +1833,8 @@ void test_NonLinearOptimization() // NIST tests, level of difficulty = "Average" CALL_SUBTEST/*_5*/(testNistHahn1()); CALL_SUBTEST/*_6*/(testNistMisra1d()); -// CALL_SUBTEST/*_7*/(testNistMGH17()); -// CALL_SUBTEST/*_8*/(testNistLanczos1()); + CALL_SUBTEST/*_7*/(testNistMGH17()); + CALL_SUBTEST/*_8*/(testNistLanczos1()); // // NIST tests, level of difficulty = "Higher" CALL_SUBTEST/*_9*/(testNistRat42()); diff --git a/unsupported/test/levenberg_marquardt.cpp b/unsupported/test/levenberg_marquardt.cpp index 04464727d..1fa1c3c22 100644 --- a/unsupported/test/levenberg_marquardt.cpp +++ b/unsupported/test/levenberg_marquardt.cpp @@ -787,16 +787,17 @@ void testNistMGH10(void) LevenbergMarquardt lm(functor); info = lm.minimize(x); - // check return value - VERIFY_IS_EQUAL(info, 1); - VERIFY_IS_EQUAL(lm.nfev(), 284 ); - VERIFY_IS_EQUAL(lm.njev(), 249 ); // check norm^2 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); // check x VERIFY_IS_APPROX(x[0], 5.6096364710E-03); VERIFY_IS_APPROX(x[1], 6.1813463463E+03); VERIFY_IS_APPROX(x[2], 3.4522363462E+02); + + // check return value + //VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 284 ); + VERIFY_IS_EQUAL(lm.njev(), 249 ); /* * Second try @@ -805,16 +806,17 @@ void testNistMGH10(void) // do the computation info = lm.minimize(x); - // check return value - VERIFY_IS_EQUAL(info, 1); - VERIFY_IS_EQUAL(lm.nfev(), 126); - VERIFY_IS_EQUAL(lm.njev(), 116); // check norm^2 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); // check x VERIFY_IS_APPROX(x[0], 5.6096364710E-03); VERIFY_IS_APPROX(x[1], 6.1813463463E+03); VERIFY_IS_APPROX(x[2], 3.4522363462E+02); + + // check return value + //VERIFY_IS_EQUAL(info, 1); + VERIFY_IS_EQUAL(lm.nfev(), 126); + VERIFY_IS_EQUAL(lm.njev(), 116); } @@ -866,15 +868,16 @@ void testNistBoxBOD(void) lm.setFactor(10); info = lm.minimize(x); - // check return value - VERIFY_IS_EQUAL(info, 1); - VERIFY_IS_EQUAL(lm.nfev(), 31); - VERIFY_IS_EQUAL(lm.njev(), 25); // check norm^2 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.1680088766E+03); // check x VERIFY_IS_APPROX(x[0], 2.1380940889E+02); VERIFY_IS_APPROX(x[1], 5.4723748542E-01); + + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY(lm.nfev() < 31); // 31 + VERIFY(lm.njev() < 25); // 25 /* * Second try @@ -948,10 +951,6 @@ void testNistMGH17(void) lm.setMaxfev(1000); info = lm.minimize(x); - // check return value -// VERIFY_IS_EQUAL(info, 2); //FIXME Use (lm.info() == Success) -// VERIFY_IS_EQUAL(lm.nfev(), 602 ); - VERIFY_IS_EQUAL(lm.njev(), 545 ); // check norm^2 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.4648946975E-05); // check x @@ -960,6 +959,11 @@ void testNistMGH17(void) VERIFY_IS_APPROX(x[2], -1.4646871366E+00); VERIFY_IS_APPROX(x[3], 1.2867534640E-02); VERIFY_IS_APPROX(x[4], 2.2122699662E-02); + + // check return value +// VERIFY_IS_EQUAL(info, 2); //FIXME Use (lm.info() == Success) + VERIFY(lm.nfev() < 700 ); // 602 + VERIFY(lm.njev() < 600 ); // 545 /* * Second try @@ -1035,10 +1039,6 @@ void testNistMGH09(void) lm.setMaxfev(1000); info = lm.minimize(x); - // check return value - VERIFY_IS_EQUAL(info, 1); - VERIFY_IS_EQUAL(lm.nfev(), 490 ); - VERIFY_IS_EQUAL(lm.njev(), 376 ); // check norm^2 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 3.0750560385E-04); // check x @@ -1046,6 +1046,10 @@ void testNistMGH09(void) VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01 VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01 VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01 + // check return value + VERIFY_IS_EQUAL(info, 1); + VERIFY(lm.nfev() < 510 ); // 490 + VERIFY(lm.njev() < 400 ); // 376 /* * Second try -- cgit v1.2.3 From 280661e67d053b4e7f3358b160bcc11f76704be9 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 17:29:06 +0200 Subject: Remove LM::sqrt_() member function in favor of a shortcut for sqrt(epsilon()) --- .../src/NonLinearOptimization/LevenbergMarquardt.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index ecb8dccf4..69106ddc5 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -45,18 +45,24 @@ namespace LevenbergMarquardtSpace { template class LevenbergMarquardt { + static Scalar sqrt_epsilon() + { + using std::sqrt; + return sqrt(NumTraits::epsilon()); + } + public: LevenbergMarquardt(FunctorType &_functor) : functor(_functor) { nfev = njev = iter = 0; fnorm = gnorm = 0.; useExternalScaling=false; } typedef DenseIndex Index; - + struct Parameters { Parameters() : factor(Scalar(100.)) , maxfev(400) - , ftol(sqrt_(NumTraits::epsilon())) - , xtol(sqrt_(NumTraits::epsilon())) + , ftol(sqrt_epsilon()) + , xtol(sqrt_epsilon()) , gtol(Scalar(0.)) , epsfcn(Scalar(0.)) {} Scalar factor; @@ -72,7 +78,7 @@ public: LevenbergMarquardtSpace::Status lmder1( FVectorType &x, - const Scalar tol = sqrt_(NumTraits::epsilon()) + const Scalar tol = sqrt_epsilon() ); LevenbergMarquardtSpace::Status minimize(FVectorType &x); @@ -83,12 +89,12 @@ public: FunctorType &functor, FVectorType &x, Index *nfev, - const Scalar tol = sqrt_(NumTraits::epsilon()) + const Scalar tol = sqrt_epsilon() ); LevenbergMarquardtSpace::Status lmstr1( FVectorType &x, - const Scalar tol = sqrt_(NumTraits::epsilon()) + const Scalar tol = sqrt_epsilon() ); LevenbergMarquardtSpace::Status minimizeOptimumStorage(FVectorType &x); @@ -109,7 +115,6 @@ public: Scalar lm_param(void) { return par; } private: - static Scalar sqrt_(const Scalar& x) { using std::sqrt; return sqrt(x); } FunctorType &functor; Index n; -- cgit v1.2.3 From 60314beb38919a87b2b605784a5c3a33dec3b895 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 2 Sep 2014 17:35:11 +0200 Subject: Update reference value for testNistLanczos1 test --- unsupported/test/NonLinearOptimization.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index 702bb7c60..75974f84f 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -1022,7 +1022,8 @@ void testNistLanczos1(void) VERIFY_IS_EQUAL(lm.nfev, 79); VERIFY_IS_EQUAL(lm.njev, 72); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.430899764097e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + std::cout.precision(30); + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4290986055242372e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02); VERIFY_IS_APPROX(x[1], 1.0000000001E+00); @@ -1043,7 +1044,7 @@ void testNistLanczos1(void) VERIFY_IS_EQUAL(lm.nfev, 9); VERIFY_IS_EQUAL(lm.njev, 8); // check norm^2 - VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.428595533845e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats + VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.430571737783119393e-25); // should be 1.4307867721E-25, but nist results are on 128-bit floats // check x VERIFY_IS_APPROX(x[0], 9.5100000027E-02); VERIFY_IS_APPROX(x[1], 1.0000000001E+00); -- cgit v1.2.3 From 25bceefb4e64123af88bb8ec6c74b5436fa4130b Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 6 Sep 2014 11:47:24 +0100 Subject: Replace asm by __asm__ (bug #873) --- Eigen/src/Core/arch/AVX/PacketMath.h | 4 ++-- Eigen/src/Core/arch/NEON/PacketMath.h | 2 +- Eigen/src/Core/util/Macros.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/arch/AVX/PacketMath.h b/Eigen/src/Core/arch/AVX/PacketMath.h index 66b97bd69..01730c5ee 100644 --- a/Eigen/src/Core/arch/AVX/PacketMath.h +++ b/Eigen/src/Core/arch/AVX/PacketMath.h @@ -141,7 +141,7 @@ template<> EIGEN_STRONG_INLINE Packet8f pmadd(const Packet8f& a, const Packet8f& // so let's enforce it to generate a vfmadd231ps instruction since the most common use case is to accumulate // the result of the product. Packet8f res = c; - asm("vfmadd231ps %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); + __asm__("vfmadd231ps %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); return res; #else return _mm256_fmadd_ps(a,b,c); @@ -151,7 +151,7 @@ template<> EIGEN_STRONG_INLINE Packet4d pmadd(const Packet4d& a, const Packet4d& #if defined(__clang__) || defined(__GNUC__) // see above Packet4d res = c; - asm("vfmadd231pd %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); + __asm__("vfmadd231pd %[a], %[b], %[c]" : [c] "+x" (res) : [a] "x" (a), [b] "x" (b)); return res; #else return _mm256_fmadd_pd(a,b,c); diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index 7c4509585..0504c095c 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -57,7 +57,7 @@ typedef uint32x4_t Packet4ui; #elif defined __pld #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR) #elif !defined(__aarch64__) - #define EIGEN_ARM_PREFETCH(ADDR) asm volatile ( " pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); + #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ( " pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); #else // by default no explicit prefetching #define EIGEN_ARM_PREFETCH(ADDR) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 99e682653..197288e09 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -279,7 +279,7 @@ namespace Eigen { #if !defined(EIGEN_ASM_COMMENT) #if (defined __GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) - #define EIGEN_ASM_COMMENT(X) asm("#" X) + #define EIGEN_ASM_COMMENT(X) __asm__("#" X) #else #define EIGEN_ASM_COMMENT(X) #endif -- cgit v1.2.3 From abb33258ce52a8cc3b540fb7cafb1812d9b71dd9 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Sat, 6 Sep 2014 14:59:44 +0100 Subject: Doc: difference between array and matrix cosine etc (bug #830) --- Eigen/src/plugins/ArrayCwiseUnaryOps.h | 18 ++++++++++++++++++ unsupported/Eigen/MatrixFunctions | 21 +++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/Eigen/src/plugins/ArrayCwiseUnaryOps.h index ce462e951..f6d7d8944 100644 --- a/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -29,6 +29,9 @@ abs2() const } /** \returns an expression of the coefficient-wise exponential of *this. + * + * This function computes the coefficient-wise exponential. The function MatrixBase::exp() in the + * unsupported module MatrixFunctions computes the matrix exponential. * * Example: \include Cwise_exp.cpp * Output: \verbinclude Cwise_exp.out @@ -43,6 +46,9 @@ exp() const } /** \returns an expression of the coefficient-wise logarithm of *this. + * + * This function computes the coefficient-wise logarithm. The function MatrixBase::log() in the + * unsupported module MatrixFunctions computes the matrix logarithm. * * Example: \include Cwise_log.cpp * Output: \verbinclude Cwise_log.out @@ -57,6 +63,9 @@ log() const } /** \returns an expression of the coefficient-wise square root of *this. + * + * This function computes the coefficient-wise square root. The function MatrixBase::sqrt() in the + * unsupported module MatrixFunctions computes the matrix square root. * * Example: \include Cwise_sqrt.cpp * Output: \verbinclude Cwise_sqrt.out @@ -71,6 +80,9 @@ sqrt() const } /** \returns an expression of the coefficient-wise cosine of *this. + * + * This function computes the coefficient-wise cosine. The function MatrixBase::cos() in the + * unsupported module MatrixFunctions computes the matrix cosine. * * Example: \include Cwise_cos.cpp * Output: \verbinclude Cwise_cos.out @@ -86,6 +98,9 @@ cos() const /** \returns an expression of the coefficient-wise sine of *this. + * + * This function computes the coefficient-wise sine. The function MatrixBase::sin() in the + * unsupported module MatrixFunctions computes the matrix sine. * * Example: \include Cwise_sin.cpp * Output: \verbinclude Cwise_sin.out @@ -155,6 +170,9 @@ atan() const } /** \returns an expression of the coefficient-wise power of *this to the given exponent. + * + * This function computes the coefficient-wise power. The function MatrixBase::pow() in the + * unsupported module MatrixFunctions computes the matrix power. * * Example: \include Cwise_pow.cpp * Output: \verbinclude Cwise_pow.out diff --git a/unsupported/Eigen/MatrixFunctions b/unsupported/Eigen/MatrixFunctions index 0b12aaffb..0320606c1 100644 --- a/unsupported/Eigen/MatrixFunctions +++ b/unsupported/Eigen/MatrixFunctions @@ -82,7 +82,9 @@ const MatrixFunctionReturnValue MatrixBase::cos() const \param[in] M a square matrix. \returns expression representing \f$ \cos(M) \f$. -This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::cos(). +This function computes the matrix cosine. Use ArrayBase::cos() for computing the entry-wise cosine. + +The implementation calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::cos(). \sa \ref matrixbase_sin "sin()" for an example. @@ -123,6 +125,9 @@ differential equations: the solution of \f$ y' = My \f$ with the initial condition \f$ y(0) = y_0 \f$ is given by \f$ y(t) = \exp(M) y_0 \f$. +The matrix exponential is different from applying the exp function to all the entries in the matrix. +Use ArrayBase::exp() if you want to do the latter. + The cost of the computation is approximately \f$ 20 n^3 \f$ for matrices of size \f$ n \f$. The number 20 depends weakly on the norm of the matrix. @@ -177,6 +182,9 @@ the scalar logarithm, the equation \f$ \exp(X) = M \f$ may have multiple solutions; this function returns a matrix whose eigenvalues have imaginary part in the interval \f$ (-\pi,\pi] \f$. +The matrix logarithm is different from applying the log function to all the entries in the matrix. +Use ArrayBase::log() if you want to do the latter. + In the real case, the matrix \f$ M \f$ should be invertible and it should have no eigenvalues which are real and negative (pairs of complex conjugate eigenvalues are allowed). In the complex case, it @@ -232,7 +240,8 @@ const MatrixPowerReturnValue MatrixBase::pow(RealScalar p) con The matrix power \f$ M^p \f$ is defined as \f$ \exp(p \log(M)) \f$, where exp denotes the matrix exponential, and log denotes the matrix -logarithm. +logarithm. This is different from raising all the entries in the matrix +to the p-th power. Use ArrayBase::pow() if you want to do the latter. If \p p is complex, the scalar type of \p M should be the type of \p p . \f$ M^p \f$ simply evaluates into \f$ \exp(p \log(M)) \f$. @@ -391,7 +400,9 @@ const MatrixFunctionReturnValue MatrixBase::sin() const \param[in] M a square matrix. \returns expression representing \f$ \sin(M) \f$. -This function calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::sin(). +This function computes the matrix sine. Use ArrayBase::sin() for computing the entry-wise sine. + +The implementation calls \ref matrixbase_matrixfunction "matrixFunction()" with StdStemFunctions::sin(). Example: \include MatrixSine.cpp Output: \verbinclude MatrixSine.out @@ -428,7 +439,9 @@ const MatrixSquareRootReturnValue MatrixBase::sqrt() const The matrix square root of \f$ M \f$ is the matrix \f$ M^{1/2} \f$ whose square is the original matrix; so if \f$ S = M^{1/2} \f$ then -\f$ S^2 = M \f$. +\f$ S^2 = M \f$. This is different from taking the square root of all +the entries in the matrix; use ArrayBase::sqrt() if you want to do the +latter. In the real case, the matrix \f$ M \f$ should be invertible and it should have no eigenvalues which are real and negative (pairs of -- cgit v1.2.3 From fafc829424894d8cbb88f52e56cf074a351d92a5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 7 Sep 2014 22:38:09 +0200 Subject: bug #804: copy group__TopicUnalignedArrayAssert.html to TopicUnalignedArrayAssert.html as the second is linked to by old Eigen versions. --- doc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1b8aaf9aa..46e5fc9d7 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -97,6 +97,7 @@ add_dependencies(doc-unsupported-prerequisites unsupported_snippets unsupported_ add_custom_target(doc ALL COMMAND doxygen COMMAND doxygen Doxyfile-unsupported + COMMAND ${CMAKE_COMMAND} -E copy ${Eigen_BINARY_DIR}/doc/html/group__TopicUnalignedArrayAssert.html ${Eigen_BINARY_DIR}/doc/html/TopicUnalignedArrayAssert.html COMMAND ${CMAKE_COMMAND} -E rename html eigen-doc COMMAND ${CMAKE_COMMAND} -E remove eigen-doc/eigen-doc.tgz COMMAND ${CMAKE_COMMAND} -E tar cfz eigen-doc/eigen-doc.tgz eigen-doc -- cgit v1.2.3 From e54898f53e73b0cb3cc0d993f7816d14efe59fa6 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Sun, 7 Sep 2014 23:02:30 +0200 Subject: bug #619: workaround MSVC 2008 implementing std::abs for int only on WINCE --- Eigen/src/Core/MathFunctions.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 5df1fbfec..e9fed2e52 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -12,6 +12,15 @@ namespace Eigen { +// On WINCE, std::abs is defined for int only, so let's defined our own overloads: +// This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. +#if defined(_WIN32_WCE) && defined(_MSC_VER) && _MSC_VER<=1500 +long abs(long x) { return (labs(x)); } +double abs(double x) { return (fabs(x)); } +float abs(float x) { return (fabsf(x)); } +long double abs(long double x) { return (fabsl(x)); } +#endif + namespace internal { /** \internal \struct global_math_functions_filtering_base -- cgit v1.2.3 From 6162672dc55dc891a1e2ab1c93d503d7f41cfdac Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 8 Sep 2014 10:04:26 +0200 Subject: Runtime alignement is not possible if AlignedOnScalar is not true (e.g., for complex) --- Eigen/src/Core/Redux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index 5b82c9a65..c626946ba 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -207,7 +207,7 @@ struct redux_impl const Index packetSize = packet_traits::size; const Index alignedStart = internal::first_aligned(mat); enum { - alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) + alignment = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) || bool(Derived::Flags & AlignedBit) ? Aligned : Unaligned }; const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); -- cgit v1.2.3 From 51b3f558bb76c11149fc64971db786798f1b692c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 8 Sep 2014 10:21:22 +0200 Subject: Fix bug #822: outer products needed linear access, and add respective unit tests --- Eigen/src/Core/GeneralProduct.h | 4 ++-- test/product.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/GeneralProduct.h b/Eigen/src/Core/GeneralProduct.h index 624b8b6e8..7179eb124 100644 --- a/Eigen/src/Core/GeneralProduct.h +++ b/Eigen/src/Core/GeneralProduct.h @@ -231,7 +231,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& // 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 diff --git a/test/product.h b/test/product.h index 856b234ac..0b3abe402 100644 --- a/test/product.h +++ b/test/product.h @@ -139,4 +139,12 @@ template void product(const MatrixType& m) // inner product Scalar x = square2.row(c) * square2.col(c2); VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum()); + + // outer product + VERIFY_IS_APPROX(m1.col(c) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.row(r).transpose() * m1.col(c).transpose(), m1.block(r,0,1,cols).transpose() * m1.block(0,c,rows,1).transpose()); + VERIFY_IS_APPROX(m1.block(0,c,rows,1) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.col(c) * m1.block(r,0,1,cols), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.leftCols(1) * m1.row(r), m1.block(0,0,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.col(c) * m1.topRows(1), m1.block(0,c,rows,1) * m1.block(0,0,1,cols)); } -- cgit v1.2.3 From 4b678b96eb6cacf59ed19940bcafa1fa4e6f55c0 Mon Sep 17 00:00:00 2001 From: Yan Zhou Date: Mon, 8 Sep 2014 17:37:58 +0800 Subject: fix for MKL_BLAS not defined in MKL 11.2 --- .../src/Core/products/TriangularMatrixMatrix_MKL.h | 4 +-- Eigen/src/Core/util/MKL_support.h | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h index ba41a1c99..4cc56a42f 100644 --- a/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +++ b/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h @@ -109,7 +109,7 @@ struct product_triangular_matrix_matrix_trmm #define EIGEN_MKL_VML_THRESHOLD 128 +/* MKL_DOMAIN_BLAS, etc are defined only in 10.3 update 7 */ +/* MKL_BLAS, etc are not defined in 11.2 */ +#ifdef MKL_DOMAIN_ALL +#define EIGEN_MKL_DOMAIN_ALL MKL_DOMAIN_ALL +#else +#define EIGEN_MKL_DOMAIN_ALL MKL_ALL +#endif + +#ifdef MKL_DOMAIN_BLAS +#define EIGEN_MKL_DOMAIN_BLAS MKL_DOMAIN_BLAS +#else +#define EIGEN_MKL_DOMAIN_BLAS MKL_BLAS +#endif + +#ifdef MKL_DOMAIN_FFT +#define EIGEN_MKL_DOMAIN_FFT MKL_DOMAIN_FFT +#else +#define EIGEN_MKL_DOMAIN_FFT MKL_FFT +#endif + +#ifdef MKL_DOMAIN_VML +#define EIGEN_MKL_DOMAIN_VML MKL_DOMAIN_VML +#else +#define EIGEN_MKL_DOMAIN_VML MKL_VML +#endif + +#ifdef MKL_DOMAIN_PARDISO +#define EIGEN_MKL_DOMAIN_PARDISO MKL_DOMAIN_PARDISO +#else +#define EIGEN_MKL_DOMAIN_PARDISO MKL_PARDISO +#endif + namespace Eigen { typedef std::complex dcomplex; -- cgit v1.2.3 From 921a645481aa8825549960c19db2c1bee8375f8f Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Sep 2014 10:33:19 +0200 Subject: ArrayWrapper and MatrixWrapper classes should not be nested by reference. --- Eigen/src/Core/ArrayWrapper.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Eigen/src/Core/ArrayWrapper.h b/Eigen/src/Core/ArrayWrapper.h index 4bb648024..28d7b7bd5 100644 --- a/Eigen/src/Core/ArrayWrapper.h +++ b/Eigen/src/Core/ArrayWrapper.h @@ -29,6 +29,11 @@ struct traits > : public traits::type > { typedef ArrayXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } @@ -166,6 +171,11 @@ struct traits > : public traits::type > { typedef MatrixXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } -- cgit v1.2.3 From d6236d3b26f6b652c452d884c440099892fdcdba Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Sep 2014 11:54:20 +0200 Subject: Fix bug #791: infinite loop in JacobiSVD in the presence of NaN. --- Eigen/src/SVD/JacobiSVD.h | 3 ++- test/jacobisvd.cpp | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 6f3907f5d..6ff689de3 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -741,7 +741,8 @@ JacobiSVD::compute(const MatrixType& matrix, unsig EIGEN_USING_STD_MATH(max); RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), abs(m_workMatrix.coeff(q,q)))); - if((max)(abs(m_workMatrix.coeff(p,q)),abs(m_workMatrix.coeff(q,p))) > threshold) + // 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) { finished = false; diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 36721b496..422d46695 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -315,16 +315,23 @@ void jacobisvd_inf_nan() 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); + 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)) = some_nan; + 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); } @@ -437,6 +444,7 @@ void test_jacobisvd() // Test on inf/nan matrix CALL_SUBTEST_7( jacobisvd_inf_nan() ); + CALL_SUBTEST_10( 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))) )); -- cgit v1.2.3 From 84a7ead059917964cc8719f372d7d153bb2cad53 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Sep 2014 11:59:45 +0200 Subject: Add one more regression test for bug #791. --- test/jacobisvd.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 422d46695..7dbb29c59 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -333,6 +333,13 @@ void jacobisvd_inf_nan() 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 -- cgit v1.2.3 From 2d90484450f3934db3f5db39ef37967fb9444263 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Sep 2014 23:10:01 +0200 Subject: mat/=scalar was transformed into mat*=(1/scalar) thus laking accuracy. This was also inconsistent with mat = mat/scalar. --- Eigen/src/Core/SelfCwiseBinaryOp.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 65864adf8..8abdca4a5 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -209,15 +209,9 @@ inline Derived& ArrayBase::operator-=(const Scalar& other) template inline Derived& DenseBase::operator/=(const Scalar& other) { - typedef typename internal::conditional::IsInteger, - internal::scalar_quotient_op, - internal::scalar_product_op >::type BinOp; typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp tmp(derived()); - Scalar actual_other; - if(NumTraits::IsInteger) actual_other = other; - else actual_other = Scalar(1)/other; - tmp = PlainObject::Constant(rows(),cols(), actual_other); + SelfCwiseBinaryOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); + tmp = PlainObject::Constant(rows(),cols(), other); return derived(); } -- cgit v1.2.3 From 5e890d3ad78a7e5c491a43202993d617fffb964a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 10 Sep 2014 23:11:58 +0200 Subject: Improve further the accuracy of JacobiSVD wrt under/overflow while improving speed for small matrices (hypot is very slow). --- Eigen/src/SVD/JacobiSVD.h | 17 +++++++++-------- test/jacobisvd.cpp | 29 ++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 6ff689de3..3ab8a4c8a 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -425,18 +425,19 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, JacobiRotation rot1; RealScalar t = m.coeff(0,0) + m.coeff(1,1); RealScalar d = m.coeff(1,0) - m.coeff(0,1); - if(t == RealScalar(0)) + + if(d == RealScalar(0)) { - rot1.c() = RealScalar(0); - rot1.s() = d > RealScalar(0) ? RealScalar(1) : RealScalar(-1); + rot1.s() = RealScalar(0); + rot1.c() = RealScalar(1); } else { - RealScalar t2d2 = numext::hypot(t,d); - rot1.c() = abs(t)/t2d2; - rot1.s() = d/t2d2; - if(tmakeJacobi(m,0,1); diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 7dbb29c59..cd04db5be 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -354,11 +354,33 @@ void jacobisvd_underoverflow() 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 svd; - svd.compute(M); // just check we don't loop indefinitely // Check for overflow: Matrix3d M3; @@ -367,7 +389,8 @@ void jacobisvd_underoverflow() -8.7190887618028355e+307, -7.3453213709232193e+307, -2.4367363684472105e+307; JacobiSVD svd3; - svd3.compute(M3); // just check we don't loop indefinitely + svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely + jacobisvd_check_full(M3,svd3); } void jacobisvd_preallocate() -- cgit v1.2.3 From 57f71a5552025320f64e330b8e67326097bbce92 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 11 Sep 2014 10:27:46 +0200 Subject: Update bench_norm utility --- bench/bench_norm.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/bench/bench_norm.cpp b/bench/bench_norm.cpp index 398fef835..129afcfb2 100644 --- a/bench/bench_norm.cpp +++ b/bench/bench_norm.cpp @@ -6,19 +6,25 @@ using namespace Eigen; using namespace std; template -EIGEN_DONT_INLINE typename T::Scalar sqsumNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar sqsumNorm(T& v) { return v.norm(); } template -EIGEN_DONT_INLINE typename T::Scalar hypotNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar stableNorm(T& v) +{ + return v.stableNorm(); +} + +template +EIGEN_DONT_INLINE typename T::Scalar hypotNorm(T& v) { return v.hypotNorm(); } template -EIGEN_DONT_INLINE typename T::Scalar blueNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar blueNorm(T& v) { return v.blueNorm(); } @@ -217,20 +223,21 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) } #define BENCH_PERF(NRM) { \ + float af = 0; double ad = 0; std::complex ac = 0; \ Eigen::BenchTimer tf, td, tcf; tf.reset(); td.reset(); tcf.reset();\ for (int k=0; k Date: Fri, 8 Aug 2014 04:05:28 -0400 Subject: Fix bug #852: define Traits type in general_matrix_matrix_product when EIGEN_USE_BLAS is defined --- Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h b/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h index 060af328e..b6ae729b2 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h @@ -53,6 +53,8 @@ template< \ int RhsStorageOrder, bool ConjugateRhs> \ struct general_matrix_matrix_product \ { \ +typedef gebp_traits Traits; \ +\ static void run(Index rows, Index cols, Index depth, \ const EIGTYPE* _lhs, Index lhsStride, \ const EIGTYPE* _rhs, Index rhsStride, \ -- 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 0369db12af70fe5e63416a18c8236d419b0597c4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 10:52:58 +0200 Subject: bug #871: fix compilation on ARM/Neon regarding __has_builtin usage --- Eigen/src/Core/arch/NEON/PacketMath.h | 2 +- Eigen/src/Core/util/Macros.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index 380b76ae9..7c4509585 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -52,7 +52,7 @@ typedef uint32x4_t Packet4ui; // arm64 does have the pld instruction. If available, let's trust the __builtin_prefetch built-in function // which available on LLVM and GCC (at least) -#if (defined(__has_builtin) && __has_builtin(__builtin_prefetch)) || defined(__GNUC__) +#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || defined(__GNUC__) #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR); #elif defined __pld #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 5e9b0a112..99e682653 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -107,6 +107,13 @@ #define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t #endif +// Cross compiler wrapper around LLVM's __has_builtin +#ifdef __has_builtin +# define EIGEN_HAS_BUILTIN(x) __has_builtin(x) +#else +# define EIGEN_HAS_BUILTIN(x) 0 +#endif + // A Clang feature extension to determine compiler features. // We use it to determine 'cxx_rvalue_references' #ifndef __has_feature -- 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 b121eecf606b584d72d264d2864460e963050687 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 17:34:55 +0200 Subject: Fix regression is sparse-sparse product --- Eigen/src/SparseCore/ConservativeSparseSparseProduct.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index 8067565f9..67bc33a93 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 @@ -136,20 +138,21 @@ 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.swap(resCol); + 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; + res = resRow.markAsRValue(); } } }; -- 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 eb392960285c2645d45118d424786a73768ff50a Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 1 Sep 2014 18:16:20 +0200 Subject: Reafctoring in D&C SVD unsupported module: clean and merge the SVDBase class to Eigen/SVD, rm copy/pasted JacobiSVD.h file --- Eigen/SVD | 1 + Eigen/src/SVD/JacobiSVD.h | 182 +---- Eigen/src/SVD/SVDBase.h | 263 +++++++ Eigen/src/SVD/UpperBidiagonalization.h | 1 + unsupported/Eigen/BDCSVD | 26 + unsupported/Eigen/SVD | 35 - unsupported/Eigen/src/BDCSVD/BDCSVD.h | 949 ++++++++++++++++++++++++++ unsupported/Eigen/src/BDCSVD/CMakeLists.txt | 6 + unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt | 29 + unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt | 21 + unsupported/Eigen/src/CMakeLists.txt | 1 + unsupported/Eigen/src/SVD/BDCSVD.h | 937 ------------------------- unsupported/Eigen/src/SVD/CMakeLists.txt | 6 - unsupported/Eigen/src/SVD/JacobiSVD.h | 782 --------------------- unsupported/Eigen/src/SVD/SVDBase.h | 236 ------- unsupported/Eigen/src/SVD/TODOBdcsvd.txt | 29 - unsupported/Eigen/src/SVD/doneInBDCSVD.txt | 21 - unsupported/test/svd_common.h | 2 +- 18 files changed, 1329 insertions(+), 2198 deletions(-) create mode 100644 Eigen/src/SVD/SVDBase.h create mode 100644 unsupported/Eigen/BDCSVD delete mode 100644 unsupported/Eigen/SVD create mode 100644 unsupported/Eigen/src/BDCSVD/BDCSVD.h create mode 100644 unsupported/Eigen/src/BDCSVD/CMakeLists.txt create mode 100644 unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt create mode 100644 unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt delete mode 100644 unsupported/Eigen/src/SVD/BDCSVD.h delete mode 100644 unsupported/Eigen/src/SVD/CMakeLists.txt delete mode 100644 unsupported/Eigen/src/SVD/JacobiSVD.h delete mode 100644 unsupported/Eigen/src/SVD/SVDBase.h delete mode 100644 unsupported/Eigen/src/SVD/TODOBdcsvd.txt delete mode 100644 unsupported/Eigen/src/SVD/doneInBDCSVD.txt diff --git a/Eigen/SVD b/Eigen/SVD index 5eee46df5..c3d24286c 100644 --- a/Eigen/SVD +++ b/Eigen/SVD @@ -21,6 +21,7 @@ */ #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) #include "src/SVD/JacobiSVD_MKL.h" diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 412daa746..6f3907f5d 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2009-2010 Benoit Jacob +// Copyright (C) 2013-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 @@ -442,6 +443,12 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, *j_left = rot1 * j_right->transpose(); } +template +struct traits > +{ + typedef _MatrixType MatrixType; +}; + } // end namespace internal /** \ingroup SVD_Module @@ -498,7 +505,9 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, * \sa MatrixBase::jacobiSvd() */ template class JacobiSVD + : public SVDBase > { + typedef SVDBase Base; public: typedef _MatrixType MatrixType; @@ -515,13 +524,10 @@ template class JacobiSVD MatrixOptions = MatrixType::Options }; - typedef Matrix - MatrixUType; - typedef Matrix - MatrixVType; - typedef typename internal::plain_diag_type::type SingularValuesType; + typedef typename Base::MatrixUType MatrixUType; + typedef typename Base::MatrixVType MatrixVType; + typedef typename Base::SingularValuesType SingularValuesType; + typedef typename internal::plain_row_type::type RowType; typedef typename internal::plain_col_type::type ColType; typedef Matrix class JacobiSVD * perform decompositions via JacobiSVD::compute(const MatrixType&). */ JacobiSVD() - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1), m_diagSize(0) {} @@ -549,11 +550,6 @@ template class JacobiSVD * \sa JacobiSVD() */ JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1) { allocate(rows, cols, computationOptions); } @@ -569,11 +565,6 @@ template class JacobiSVD * available with the (non-default) FullPivHouseholderQR preconditioner. */ JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) - : m_isInitialized(false), - m_isAllocated(false), - m_usePrescribedThreshold(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1) { compute(matrix, computationOptions); } @@ -601,54 +592,6 @@ template class JacobiSVD return compute(matrix, m_computationOptions); } - /** \returns the \a U matrix. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU. - * - * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a U to be computed. - */ - const MatrixUType& matrixU() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeU() && "This JacobiSVD decomposition didn't compute U. Did you ask for it?"); - return m_matrixU; - } - - /** \returns the \a V matrix. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV. - * - * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a V to be computed. - */ - const MatrixVType& matrixV() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(computeV() && "This JacobiSVD decomposition didn't compute V. Did you ask for it?"); - return m_matrixV; - } - - /** \returns the vector of singular values. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the - * returned vector has size \a m. Singular values are always sorted in decreasing order. - */ - const SingularValuesType& singularValues() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - return m_singularValues; - } - - /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */ - inline bool computeU() const { return m_computeFullU || m_computeThinU; } - /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */ - inline bool computeV() const { return m_computeFullV || m_computeThinV; } - /** \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. @@ -666,94 +609,31 @@ 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()); } - - /** \returns the number of singular values that are not exactly 0 */ - Index nonzeroSingularValues() const - { - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - return m_nonzeroSingularValues; - } - /** \returns the rank of the matrix of which \c *this is the SVD. - * - * \note This method has to determine which singular values should be considered nonzero. - * For that, it uses the threshold value that you can control by calling - * setThreshold(const RealScalar&). - */ - inline Index rank() const - { - using std::abs; - eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); - if(m_singularValues.size()==0) return 0; - RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold(); - Index i = m_nonzeroSingularValues-1; - while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i; - return i+1; - } + using Base::computeU; + using Base::computeV; - /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(), - * which need to determine when singular values are to be considered nonzero. - * This is not used for the SVD decomposition itself. - * - * When it needs to get the threshold value, Eigen calls threshold(). - * The default is \c NumTraits::epsilon() - * - * \param threshold The new value to use as the threshold. - * - * A singular value will be considered nonzero if its value is strictly greater than - * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$. - * - * If you want to come back to the default behavior, call setThreshold(Default_t) - */ - JacobiSVD& setThreshold(const RealScalar& threshold) - { - m_usePrescribedThreshold = true; - m_prescribedThreshold = threshold; - return *this; - } - - /** Allows to come back to the default behavior, letting Eigen use its default formula for - * determining the threshold. - * - * You should pass the special object Eigen::Default as parameter here. - * \code svd.setThreshold(Eigen::Default); \endcode - * - * See the documentation of setThreshold(const RealScalar&). - */ - JacobiSVD& setThreshold(Default_t) - { - m_usePrescribedThreshold = false; - return *this; - } - - /** Returns the threshold that will be used by certain methods such as rank(). - * - * See the documentation of setThreshold(const RealScalar&). - */ - RealScalar threshold() const - { - eigen_assert(m_isInitialized || m_usePrescribedThreshold); - return m_usePrescribedThreshold ? m_prescribedThreshold - : (std::max)(1,m_diagSize)*NumTraits::epsilon(); - } - - inline Index rows() const { return m_rows; } - inline Index cols() const { return m_cols; } - private: void allocate(Index rows, Index cols, unsigned int computationOptions); protected: - MatrixUType m_matrixU; - MatrixVType m_matrixV; - SingularValuesType m_singularValues; + using Base::m_matrixU; + using Base::m_matrixV; + using Base::m_singularValues; + using Base::m_isInitialized; + using Base::m_isAllocated; + using Base::m_usePrescribedThreshold; + using Base::m_computeFullU; + using Base::m_computeThinU; + using Base::m_computeFullV; + using Base::m_computeThinV; + using Base::m_computationOptions; + using Base::m_nonzeroSingularValues; + using Base::m_rows; + using Base::m_cols; + using Base::m_diagSize; + using Base::m_prescribedThreshold; WorkMatrixType m_workMatrix; - bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold; - bool m_computeFullU, m_computeThinU; - bool m_computeFullV, m_computeThinV; - unsigned int m_computationOptions; - Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; - RealScalar m_prescribedThreshold; template friend struct internal::svd_precondition_2x2_block_to_be_real; diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h new file mode 100644 index 000000000..61b01fb8a --- /dev/null +++ b/Eigen/src/SVD/SVDBase.h @@ -0,0 +1,263 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Benoit Jacob +// Copyright (C) 2014 Gael Guennebaud +// +// 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/. + +#ifndef EIGEN_SVDBASE_H +#define EIGEN_SVDBASE_H + +namespace Eigen { +/** \ingroup SVD_Module + * + * + * \class SVDBase + * + * \brief Base class of SVD algorithms + * + * \tparam Derived the type of the actual SVD decomposition + * + * SVD decomposition consists in decomposing any n-by-p matrix \a A as a product + * \f[ A = U S V^* \f] + * where \a U is a n-by-n unitary, \a V is a p-by-p unitary, and \a S is a n-by-p real positive matrix which is zero outside of its main diagonal; + * the diagonal entries of S are known as the \em singular \em values of \a A and the columns of \a U and \a V are known as the left + * and right \em singular \em vectors of \a A respectively. + * + * Singular values are always sorted in decreasing order. + * + * + * You can ask for only \em thin \a U or \a V to be computed, meaning the following. In case of a rectangular n-by-p matrix, letting \a m be the + * smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual + * singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix, + * and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving. + * + * If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to + * terminate in finite (and reasonable) time. + * \sa MatrixBase::genericSvd() + */ +template +class SVDBase +{ + +public: + typedef typename internal::traits::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 Matrix MatrixUType; + typedef Matrix MatrixVType; + typedef typename internal::plain_diag_type::type SingularValuesType; + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + /** \returns the \a U matrix. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, + * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU. + * + * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed. + * + * This method asserts that you asked for \a U to be computed. + */ + const MatrixUType& matrixU() const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + eigen_assert(computeU() && "This SVD decomposition didn't compute U. Did you ask for it?"); + return m_matrixU; + } + + /** \returns the \a V matrix. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, + * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV. + * + * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed. + * + * This method asserts that you asked for \a V to be computed. + */ + const MatrixVType& matrixV() const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + eigen_assert(computeV() && "This SVD decomposition didn't compute V. Did you ask for it?"); + return m_matrixV; + } + + /** \returns the vector of singular values. + * + * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the + * returned vector has size \a m. Singular values are always sorted in decreasing order. + */ + const SingularValuesType& singularValues() const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + return m_singularValues; + } + + /** \returns the number of singular values that are not exactly 0 */ + Index nonzeroSingularValues() const + { + eigen_assert(m_isInitialized && "SVD is not initialized."); + return m_nonzeroSingularValues; + } + + /** \returns the rank of the matrix of which \c *this is the SVD. + * + * \note This method has to determine which singular values should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline Index rank() const + { + using std::abs; + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + if(m_singularValues.size()==0) return 0; + RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold(); + Index i = m_nonzeroSingularValues-1; + while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i; + return i+1; + } + + /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(), + * which need to determine when singular values are to be considered nonzero. + * This is not used for the SVD decomposition itself. + * + * When it needs to get the threshold value, Eigen calls threshold(). + * The default is \c NumTraits::epsilon() + * + * \param threshold The new value to use as the threshold. + * + * A singular value will be considered nonzero if its value is strictly greater than + * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$. + * + * If you want to come back to the default behavior, call setThreshold(Default_t) + */ + Derived& setThreshold(const RealScalar& threshold) + { + m_usePrescribedThreshold = true; + m_prescribedThreshold = threshold; + return derived(); + } + + /** Allows to come back to the default behavior, letting Eigen use its default formula for + * determining the threshold. + * + * You should pass the special object Eigen::Default as parameter here. + * \code svd.setThreshold(Eigen::Default); \endcode + * + * See the documentation of setThreshold(const RealScalar&). + */ + Derived& setThreshold(Default_t) + { + m_usePrescribedThreshold = false; + return derived(); + } + + /** Returns the threshold that will be used by certain methods such as rank(). + * + * See the documentation of setThreshold(const RealScalar&). + */ + RealScalar threshold() const + { + eigen_assert(m_isInitialized || m_usePrescribedThreshold); + return m_usePrescribedThreshold ? m_prescribedThreshold + : (std::max)(1,m_diagSize)*NumTraits::epsilon(); + } + + /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */ + inline bool computeU() const { return m_computeFullU || m_computeThinU; } + /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */ + inline bool computeV() const { return m_computeFullV || m_computeThinV; } + + inline Index rows() const { return m_rows; } + inline Index cols() const { return m_cols; } + +protected: + // return true if already allocated + bool allocate(Index rows, Index cols, unsigned int computationOptions) ; + + MatrixUType m_matrixU; + MatrixVType m_matrixV; + SingularValuesType m_singularValues; + bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold; + bool m_computeFullU, m_computeThinU; + bool m_computeFullV, m_computeThinV; + unsigned int m_computationOptions; + Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; + RealScalar m_prescribedThreshold; + + /** \brief Default Constructor. + * + * Default constructor of SVDBase + */ + SVDBase() + : m_isInitialized(false), + m_isAllocated(false), + m_usePrescribedThreshold(false), + m_computationOptions(0), + m_rows(-1), m_cols(-1), m_diagSize(0) + {} + + +}; + + +template +bool SVDBase::allocate(Index rows, Index cols, unsigned int computationOptions) +{ + eigen_assert(rows >= 0 && cols >= 0); + + if (m_isAllocated && + rows == m_rows && + cols == m_cols && + computationOptions == m_computationOptions) + { + return true; + } + + m_rows = rows; + m_cols = cols; + m_isInitialized = false; + m_isAllocated = true; + m_computationOptions = computationOptions; + m_computeFullU = (computationOptions & ComputeFullU) != 0; + m_computeThinU = (computationOptions & ComputeThinU) != 0; + m_computeFullV = (computationOptions & ComputeFullV) != 0; + m_computeThinV = (computationOptions & ComputeThinV) != 0; + eigen_assert(!(m_computeFullU && m_computeThinU) && "SVDBase: you can't ask for both full and thin U"); + eigen_assert(!(m_computeFullV && m_computeThinV) && "SVDBase: you can't ask for both full and thin V"); + eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) && + "SVDBase: thin U and V are only available when your matrix has a dynamic number of columns."); + + m_diagSize = (std::min)(m_rows, m_cols); + m_singularValues.resize(m_diagSize); + if(RowsAtCompileTime==Dynamic) + m_matrixU.resize(m_rows, m_computeFullU ? m_rows : m_computeThinU ? m_diagSize : 0); + if(ColsAtCompileTime==Dynamic) + m_matrixV.resize(m_cols, m_computeFullV ? m_cols : m_computeThinV ? m_diagSize : 0); + + return false; +} + +}// end namespace + +#endif // EIGEN_SVDBASE_H diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h index 40067682c..225b19e3c 100644 --- a/Eigen/src/SVD/UpperBidiagonalization.h +++ b/Eigen/src/SVD/UpperBidiagonalization.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2010 Benoit Jacob +// Copyright (C) 2013-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/unsupported/Eigen/BDCSVD b/unsupported/Eigen/BDCSVD new file mode 100644 index 000000000..44649dbd0 --- /dev/null +++ b/unsupported/Eigen/BDCSVD @@ -0,0 +1,26 @@ +#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/SVD b/unsupported/Eigen/SVD deleted file mode 100644 index 900a8aa60..000000000 --- a/unsupported/Eigen/SVD +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef EIGEN_SVD_MODULE_H -#define EIGEN_SVD_MODULE_H - -#include -#include -#include - -#include "../../Eigen/src/Core/util/DisableStupidWarnings.h" - -/** \defgroup SVD_Module SVD module - * - * - * - * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: - * - MatrixBase::jacobiSvd() - * - * \code - * #include - * \endcode - */ - -#include "../../Eigen/src/misc/Solve.h" -#include "../../Eigen/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 "../../Eigen/src/SVD/JacobiSVD_MKL.h" -#endif - -#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_SVD_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 new file mode 100644 index 000000000..a7c369633 --- /dev/null +++ b/unsupported/Eigen/src/BDCSVD/BDCSVD.h @@ -0,0 +1,949 @@ +// 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 +// +// 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 EPSILON 0.0000000000000001 + +#define ALGOSWAP 16 + +namespace Eigen { + +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; + + 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 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 Matrix MatrixX; + typedef Matrix MatrixXr; + typedef Matrix VectorType; + typedef Array ArrayXr; + + /** \brief Default Constructor. + * + * 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) + {} + + + /** \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) + : algoswap(ALGOSWAP), 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) + : algoswap(ALGOSWAP), 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"); + 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 + { + 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; + } + } + + using Base::computeU; + using Base::computeV; + +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 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); + +protected: + MatrixXr m_naiveU, m_naiveV; + MatrixXr m_computed; + Index nRec; + int algoswap; + bool isTranspose, compU, compV; + +public: + int m_numIters; +}; //end class BDCSVD + + +// Methode to allocate ans initialize matrix and attributs +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 ); + + if (compV) m_naiveV = MatrixXr::Zero(this->m_diagSize, this->m_diagSize); + + + //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; + } + } +}// 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); + this->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; + return *this; +} + + +// Methode which compute the BDCSVD +template +BDCSVD& BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) +{ + allocate(matrix.rows(), matrix.cols(), computationOptions); + using std::abs; + + //**** step 1 Bidiagonalization isTranspose = (matrix.cols()>matrix.rows()) ; + MatrixType copy; + if (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.template bottomRows<1>().setZero(); + divide(0, this->m_diagSize - 1, 0, 0, 0); + + //**** step 3 copy + for (int i=0; im_diagSize; i++) { + RealScalar a = abs(m_computed.coeff(i, i)); + this->m_singularValues.coeffRef(i) = a; + if (a == 0){ + this->m_nonzeroSingularValues = i; + this->m_singularValues.tail(this->m_diagSize - i - 1).setZero(); + break; + } + else if (i == this->m_diagSize - 1) + { + this->m_nonzeroSingularValues = i + 1; + break; + } + } + copyUV(bid.householderU(), bid.householderV()); + this->m_isInitialized = true; + return *this; +}// end compute + + +template +void BDCSVD::copyUV(const typename internal::UpperBidiagonalization::HouseholderUSequenceType& householderU, + const typename internal::UpperBidiagonalization::HouseholderVSequenceType& householderV) +{ + // 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 (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; + } +} + +// The divide algorithm is done "in place", we are always working on subsets of the same matrix. The divide methods takes as argument the +// place of the submatrix we are currently working on. + +//@param firstCol : The Index of the first column of the submatrix of m_computed and for m_naiveU; +//@param lastCol : The Index of the last column of the submatrix of m_computed and for m_naiveU; +// lastCol + 1 - firstCol is the size of the submatrix. +//@param firstRowW : The Index of the first row of the matrix W that we are to change. (see the reference paper section 1 for more information on W) +//@param firstRowW : Same as firstRowW with the column. +//@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) +{ + // 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; + 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(); + 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 (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= 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(); + } + 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(); + + + // Second part: try to deflate singular values in combined matrix + deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); + + // Third part: compute SVD of combined matrix + 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; + 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 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 (?) + ArrayXr col0 = m_computed.block(firstCol, firstCol, n, 1); + ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); + diag(0) = 0; + + // compute singular values and vectors (in decreasing order) + singVals.resize(n); + U.resize(n+1, n+1); + if (compV) V.resize(n, n); + + 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 (compV) V = V.rowwise().reverse().eval(); +} + +template +void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, + VectorType& singVals, ArrayXr& shifts, ArrayXr& mus) +{ + using std::abs; + using std::swap; + + Index n = col0.size(); + 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; + shifts(k) = diag(k); + continue; + } + + // 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()); + + // 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 shift; + if (k == n-1 || fMid > 0) shift = left; + else shift = 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 == n-1) muCur = right - left; + 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)) { + 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 = false; + while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (std::max)(abs(muCur), abs(muPrev)) && fCur != fPrev && !useBisection) { + ++m_numIters; + + RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); + RealScalar b = fCur - a / muCur; + + muPrev = muCur; + fPrev = fCur; + muCur = -a / b; + fCur = 1 + (col0.square() / ((diagShifted - muCur) * (diag + shift + muCur))).sum(); + + 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) { + 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 + } else { + leftShifted = -(right - left) * 0.6; + 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); + + while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (std::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) { + 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) + 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 VectorType& singVals, + const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) +{ + Index n = col0.size(); + for (Index k = 0; k < n; ++k) { + if (col0(k) == 0) + zhat(k) = 0; + else { + // see equation (3.6) + using std::sqrt; + RealScalar tmp = + sqrt( + (singVals(n-1) + diag(k)) * (mus(n-1) + (shifts(n-1) - diag(k))) + * ( + ((singVals.head(k).array() + diag(k)) * (mus.head(k) + (shifts.head(k) - diag(k)))) + / ((diag.head(k).array() + diag(k)) * (diag.head(k).array() - diag(k))) + ).prod() + * ( + ((singVals.segment(k, n-k-1).array() + diag(k)) * (mus.segment(k, n-k-1) + (shifts.segment(k, n-k-1) - diag(k)))) + / ((diag.tail(n-k-1) + diag(k)) * (diag.tail(n-k-1) - diag(k))) + ).prod() + ); + if (col0(k) > 0) zhat(k) = tmp; + else zhat(k) = -tmp; + } + } +} + +// compute singular vectors +template +void BDCSVD::computeSingVecs + (const ArrayXr& zhat, const ArrayXr& diag, const VectorType& singVals, + 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) { + U.col(k) = VectorType::Unit(n+1, k); + if (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) { + 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(); + } + } + } + U.col(n) = VectorType::Unit(n+1, n); +} + + +// page 12_13 +// 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){ + 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; + return; + } + c/=r; + s/=r; + m_computed(firstCol + shift, firstCol + shift) = r; + m_computed(i, firstCol + shift) = 0; + m_computed(i, i) = 0; + if (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); + } +}// end deflation 43 + + +// page 13 +// 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){ + using std::abs; + 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)); + 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 + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); + m_computed(firstColm + j, firstColm) = 0; + if (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); + } + if (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); + } +}// 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){ + //condition 4.1 + using std::sqrt; + 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; + } + + //condition 4.2 + for (Index i=firstCol + shift + 1;i<=lastCol + shift;i++){ + if (std::abs(m_computed(i, firstCol + shift)) < EPS){ + 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){ + 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]; + + 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++; + } + } + } + //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++){ + realCol[pos] = pos + firstCol + shift; + realInd[pos] = pos; + } + const Index Zero = firstCol + shift; + VectorType temp; + 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; + const Index J = realCol[j]; + + //diag displace + aux = m_computed(I, I); + m_computed(I, I) = m_computed(J, J); + m_computed(J, J) = aux; + + //firstrow displace + aux = m_computed(I, Zero); + m_computed(I, Zero) = m_computed(J, Zero); + m_computed(J, Zero) = aux; + + // change columns + if (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 + { + 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; + } + if (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; + } + + //update real pos + realCol[realI] = J; + realCol[j] = I; + realInd[J - Zero] = realI; + realInd[I - Zero] = j; + } + for (Index i = firstCol + shift + 1; i +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 + * BDC Algorithm + * + * \sa class BDCSVD + */ +/* +template +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 new file mode 100644 index 000000000..73b89ea18 --- /dev/null +++ b/unsupported/Eigen/src/BDCSVD/CMakeLists.txt @@ -0,0 +1,6 @@ +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 new file mode 100644 index 000000000..0bc9a46e6 --- /dev/null +++ b/unsupported/Eigen/src/BDCSVD/TODOBdcsvd.txt @@ -0,0 +1,29 @@ +TO DO LIST + + + +(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 new file mode 100644 index 000000000..8563ddab8 --- /dev/null +++ b/unsupported/Eigen/src/BDCSVD/doneInBDCSVD.txt @@ -0,0 +1,21 @@ +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: +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 8eb2808e3..654a2327f 100644 --- a/unsupported/Eigen/src/CMakeLists.txt +++ b/unsupported/Eigen/src/CMakeLists.txt @@ -12,3 +12,4 @@ ADD_SUBDIRECTORY(Skyline) ADD_SUBDIRECTORY(SparseExtra) ADD_SUBDIRECTORY(KroneckerProduct) ADD_SUBDIRECTORY(Splines) +ADD_SUBDIRECTORY(BDCSVD) diff --git a/unsupported/Eigen/src/SVD/BDCSVD.h b/unsupported/Eigen/src/SVD/BDCSVD.h deleted file mode 100644 index 80006fd60..000000000 --- a/unsupported/Eigen/src/SVD/BDCSVD.h +++ /dev/null @@ -1,937 +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 -// -// 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 EPSILON 0.0000000000000001 - -#define ALGOSWAP 16 - -namespace Eigen { -/** \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<_MatrixType> -{ - typedef SVDBase<_MatrixType> Base; - -public: - using Base::rows; - using Base::cols; - - 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 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 Matrix MatrixX; - typedef Matrix MatrixXr; - typedef Matrix VectorType; - typedef Array ArrayXr; - - /** \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via BDCSVD::compute(const MatrixType&). - */ - BDCSVD() - : SVDBase<_MatrixType>::SVDBase(), - algoswap(ALGOSWAP), 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) - : SVDBase<_MatrixType>::SVDBase(), - algoswap(ALGOSWAP), 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) - : SVDBase<_MatrixType>::SVDBase(), - algoswap(ALGOSWAP), 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. - */ - SVDBase& 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). - */ - SVDBase& 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"); - 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(SVDBase<_MatrixType>::computeU() && SVDBase<_MatrixType>::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 - { - 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; - } - } - -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 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); - -protected: - MatrixXr m_naiveU, m_naiveV; - MatrixXr m_computed; - Index nRec; - int algoswap; - bool isTranspose, compU, compV; - -public: - int m_numIters; -}; //end class BDCSVD - - -// Methode to allocate ans initialize matrix and attributs -template -void BDCSVD::allocate(Index rows, Index cols, unsigned int computationOptions) -{ - isTranspose = (cols > rows); - if (SVDBase::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 ); - - if (compV) m_naiveV = MatrixXr::Zero(this->m_diagSize, this->m_diagSize); - - - //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; - } - } -}// end allocate - -// Methode which compute the BDCSVD for the int -template<> -SVDBase >& -BDCSVD >::compute(const MatrixType& matrix, unsigned int computationOptions) { - allocate(matrix.rows(), matrix.cols(), computationOptions); - this->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; - return *this; -} - - -// Methode which compute the BDCSVD -template -SVDBase& -BDCSVD::compute(const MatrixType& matrix, unsigned int computationOptions) -{ - allocate(matrix.rows(), matrix.cols(), computationOptions); - using std::abs; - - //**** step 1 Bidiagonalization isTranspose = (matrix.cols()>matrix.rows()) ; - MatrixType copy; - if (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.template bottomRows<1>().setZero(); - divide(0, this->m_diagSize - 1, 0, 0, 0); - - //**** step 3 copy - for (int i=0; im_diagSize; i++) { - RealScalar a = abs(m_computed.coeff(i, i)); - this->m_singularValues.coeffRef(i) = a; - if (a == 0){ - this->m_nonzeroSingularValues = i; - this->m_singularValues.tail(this->m_diagSize - i - 1).setZero(); - break; - } - else if (i == this->m_diagSize - 1) - { - this->m_nonzeroSingularValues = i + 1; - break; - } - } - copyUV(bid.householderU(), bid.householderV()); - this->m_isInitialized = true; - return *this; -}// end compute - - -template -void BDCSVD::copyUV(const typename internal::UpperBidiagonalization::HouseholderUSequenceType& householderU, - const typename internal::UpperBidiagonalization::HouseholderVSequenceType& householderV) -{ - // 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 (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; - } -} - -// The divide algorithm is done "in place", we are always working on subsets of the same matrix. The divide methods takes as argument the -// place of the submatrix we are currently working on. - -//@param firstCol : The Index of the first column of the submatrix of m_computed and for m_naiveU; -//@param lastCol : The Index of the last column of the submatrix of m_computed and for m_naiveU; -// lastCol + 1 - firstCol is the size of the submatrix. -//@param firstRowW : The Index of the first row of the matrix W that we are to change. (see the reference paper section 1 for more information on W) -//@param firstRowW : Same as firstRowW with the column. -//@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) -{ - // 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; - 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(); - 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 (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= 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(); - } - 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(); - - - // Second part: try to deflate singular values in combined matrix - deflation(firstCol, lastCol, k, firstRowW, firstColW, shift); - - // Third part: compute SVD of combined matrix - 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; - 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 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 (?) - ArrayXr col0 = m_computed.block(firstCol, firstCol, n, 1); - ArrayXr diag = m_computed.block(firstCol, firstCol, n, n).diagonal(); - diag(0) = 0; - - // compute singular values and vectors (in decreasing order) - singVals.resize(n); - U.resize(n+1, n+1); - if (compV) V.resize(n, n); - - 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 (compV) V = V.rowwise().reverse().eval(); -} - -template -void BDCSVD::computeSingVals(const ArrayXr& col0, const ArrayXr& diag, - VectorType& singVals, ArrayXr& shifts, ArrayXr& mus) -{ - using std::abs; - using std::swap; - - Index n = col0.size(); - 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; - shifts(k) = diag(k); - continue; - } - - // 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()); - - // 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 shift; - if (k == n-1 || fMid > 0) shift = left; - else shift = 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 == n-1) muCur = right - left; - 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)) { - 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 = false; - while (abs(muCur - muPrev) > 8 * NumTraits::epsilon() * (std::max)(abs(muCur), abs(muPrev)) && fCur != fPrev && !useBisection) { - ++m_numIters; - - RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev); - RealScalar b = fCur - a / muCur; - - muPrev = muCur; - fPrev = fCur; - muCur = -a / b; - fCur = 1 + (col0.square() / ((diagShifted - muCur) * (diag + shift + muCur))).sum(); - - 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) { - 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 - } else { - leftShifted = -(right - left) * 0.6; - 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); - - while (rightShifted - leftShifted > 2 * NumTraits::epsilon() * (std::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) { - 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) - 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 VectorType& singVals, - const ArrayXr& shifts, const ArrayXr& mus, ArrayXr& zhat) -{ - Index n = col0.size(); - for (Index k = 0; k < n; ++k) { - if (col0(k) == 0) - zhat(k) = 0; - else { - // see equation (3.6) - using std::sqrt; - RealScalar tmp = - sqrt( - (singVals(n-1) + diag(k)) * (mus(n-1) + (shifts(n-1) - diag(k))) - * ( - ((singVals.head(k).array() + diag(k)) * (mus.head(k) + (shifts.head(k) - diag(k)))) - / ((diag.head(k).array() + diag(k)) * (diag.head(k).array() - diag(k))) - ).prod() - * ( - ((singVals.segment(k, n-k-1).array() + diag(k)) * (mus.segment(k, n-k-1) + (shifts.segment(k, n-k-1) - diag(k)))) - / ((diag.tail(n-k-1) + diag(k)) * (diag.tail(n-k-1) - diag(k))) - ).prod() - ); - if (col0(k) > 0) zhat(k) = tmp; - else zhat(k) = -tmp; - } - } -} - -// compute singular vectors -template -void BDCSVD::computeSingVecs - (const ArrayXr& zhat, const ArrayXr& diag, const VectorType& singVals, - 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) { - U.col(k) = VectorType::Unit(n+1, k); - if (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) { - 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(); - } - } - } - U.col(n) = VectorType::Unit(n+1, n); -} - - -// page 12_13 -// 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){ - 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; - return; - } - c/=r; - s/=r; - m_computed(firstCol + shift, firstCol + shift) = r; - m_computed(i, firstCol + shift) = 0; - m_computed(i, i) = 0; - if (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); - } -}// end deflation 43 - - -// page 13 -// 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){ - using std::abs; - 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)); - 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 + i, firstColm + i) = m_computed(firstColm + j, firstColm + j); - m_computed(firstColm + j, firstColm) = 0; - if (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); - } - if (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); - } -}// 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){ - //condition 4.1 - using std::sqrt; - 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; - } - - //condition 4.2 - for (Index i=firstCol + shift + 1;i<=lastCol + shift;i++){ - if (std::abs(m_computed(i, firstCol + shift)) < EPS){ - 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){ - 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]; - - 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++; - } - } - } - //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++){ - realCol[pos] = pos + firstCol + shift; - realInd[pos] = pos; - } - const Index Zero = firstCol + shift; - VectorType temp; - 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; - const Index J = realCol[j]; - - //diag displace - aux = m_computed(I, I); - m_computed(I, I) = m_computed(J, J); - m_computed(J, J) = aux; - - //firstrow displace - aux = m_computed(I, Zero); - m_computed(I, Zero) = m_computed(J, Zero); - m_computed(J, Zero) = aux; - - // change columns - if (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 - { - 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; - } - if (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; - } - - //update real pos - realCol[realI] = J; - realCol[j] = I; - realInd[J - Zero] = realI; - realInd[I - Zero] = j; - } - for (Index i = firstCol + shift + 1; i -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 - * BDC Algorithm - * - * \sa class BDCSVD - */ -/* -template -BDCSVD::PlainObject> -MatrixBase::bdcSvd(unsigned int computationOptions) const -{ - return BDCSVD(*this, computationOptions); -} -*/ - -} // end namespace Eigen - -#endif diff --git a/unsupported/Eigen/src/SVD/CMakeLists.txt b/unsupported/Eigen/src/SVD/CMakeLists.txt deleted file mode 100644 index b40baf092..000000000 --- a/unsupported/Eigen/src/SVD/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_SVD_SRCS "*.h") - -INSTALL(FILES - ${Eigen_SVD_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}unsupported/Eigen/src/SVD COMPONENT Devel - ) diff --git a/unsupported/Eigen/src/SVD/JacobiSVD.h b/unsupported/Eigen/src/SVD/JacobiSVD.h deleted file mode 100644 index 02fac409e..000000000 --- a/unsupported/Eigen/src/SVD/JacobiSVD.h +++ /dev/null @@ -1,782 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-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_JACOBISVD_H -#define EIGEN_JACOBISVD_H - -namespace Eigen { - -namespace internal { -// forward declaration (needed by ICC) -// the empty body is required by MSVC -template::IsComplex> -struct svd_precondition_2x2_block_to_be_real {}; - -/*** QR preconditioners (R-SVD) - *** - *** Their role is to reduce the problem of computing the SVD to the case of a square matrix. - *** This approach, known as R-SVD, is an optimization for rectangular-enough matrices, and is a requirement for - *** JacobiSVD which by itself is only able to work on square matrices. - ***/ - -enum { PreconditionIfMoreColsThanRows, PreconditionIfMoreRowsThanCols }; - -template -struct qr_preconditioner_should_do_anything -{ - enum { a = MatrixType::RowsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime <= MatrixType::RowsAtCompileTime, - b = MatrixType::RowsAtCompileTime != Dynamic && - MatrixType::ColsAtCompileTime != Dynamic && - MatrixType::RowsAtCompileTime <= MatrixType::ColsAtCompileTime, - ret = !( (QRPreconditioner == NoQRPreconditioner) || - (Case == PreconditionIfMoreColsThanRows && bool(a)) || - (Case == PreconditionIfMoreRowsThanCols && bool(b)) ) - }; -}; - -template::ret -> struct qr_preconditioner_impl {}; - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - void allocate(const JacobiSVD&) {} - bool run(JacobiSVD&, const MatrixType&) - { - return false; - } -}; - -/*** preconditioner using FullPivHouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - enum - { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime - }; - typedef Matrix WorkspaceType; - - void allocate(const JacobiSVD& svd) - { - if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.rows(), svd.cols()); - } - if (svd.m_computeFullU) m_workspace.resize(svd.rows()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.rows() > matrix.cols()) - { - m_qr.compute(matrix); - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace); - if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation(); - return true; - } - return false; - } -private: - typedef FullPivHouseholderQR QRType; - QRType m_qr; - WorkspaceType m_workspace; -}; - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - enum - { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - Options = MatrixType::Options - }; - typedef Matrix - TransposeTypeWithSameStorageOrder; - - void allocate(const JacobiSVD& svd) - { - if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.cols(), svd.rows()); - } - m_adjoint.resize(svd.cols(), svd.rows()); - if (svd.m_computeFullV) m_workspace.resize(svd.cols()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.cols() > matrix.rows()) - { - m_adjoint = matrix.adjoint(); - m_qr.compute(m_adjoint); - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace); - if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation(); - return true; - } - else return false; - } -private: - typedef FullPivHouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** preconditioner using ColPivHouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - - void allocate(const JacobiSVD& svd) - { - if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.rows(), svd.cols()); - } - if (svd.m_computeFullU) m_workspace.resize(svd.rows()); - else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.rows() > matrix.cols()) - { - m_qr.compute(matrix); - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace); - else if(svd.m_computeThinU) - { - svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace); - } - if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation(); - return true; - } - return false; - } - -private: - typedef ColPivHouseholderQR QRType; - QRType m_qr; - typename internal::plain_col_type::type m_workspace; -}; - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - enum - { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - Options = MatrixType::Options - }; - - typedef Matrix - TransposeTypeWithSameStorageOrder; - - void allocate(const JacobiSVD& svd) - { - if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.cols(), svd.rows()); - } - if (svd.m_computeFullV) m_workspace.resize(svd.cols()); - else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); - m_adjoint.resize(svd.cols(), svd.rows()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.cols() > matrix.rows()) - { - m_adjoint = matrix.adjoint(); - m_qr.compute(m_adjoint); - - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace); - else if(svd.m_computeThinV) - { - svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace); - } - if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation(); - return true; - } - else return false; - } - -private: - typedef ColPivHouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** preconditioner using HouseholderQR ***/ - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - - void allocate(const JacobiSVD& svd) - { - if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.rows(), svd.cols()); - } - if (svd.m_computeFullU) m_workspace.resize(svd.rows()); - else if (svd.m_computeThinU) m_workspace.resize(svd.cols()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.rows() > matrix.cols()) - { - m_qr.compute(matrix); - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView(); - if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace); - else if(svd.m_computeThinU) - { - svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace); - } - if(svd.computeV()) svd.m_matrixV.setIdentity(matrix.cols(), matrix.cols()); - return true; - } - return false; - } -private: - typedef HouseholderQR QRType; - QRType m_qr; - typename internal::plain_col_type::type m_workspace; -}; - -template -class qr_preconditioner_impl -{ -public: - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - enum - { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - Options = MatrixType::Options - }; - - typedef Matrix - TransposeTypeWithSameStorageOrder; - - void allocate(const JacobiSVD& svd) - { - if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols()) - { - m_qr.~QRType(); - ::new (&m_qr) QRType(svd.cols(), svd.rows()); - } - if (svd.m_computeFullV) m_workspace.resize(svd.cols()); - else if (svd.m_computeThinV) m_workspace.resize(svd.rows()); - m_adjoint.resize(svd.cols(), svd.rows()); - } - - bool run(JacobiSVD& svd, const MatrixType& matrix) - { - if(matrix.cols() > matrix.rows()) - { - m_adjoint = matrix.adjoint(); - m_qr.compute(m_adjoint); - - svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView().adjoint(); - if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace); - else if(svd.m_computeThinV) - { - svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows()); - m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace); - } - if(svd.computeU()) svd.m_matrixU.setIdentity(matrix.rows(), matrix.rows()); - return true; - } - else return false; - } - -private: - typedef HouseholderQR QRType; - QRType m_qr; - TransposeTypeWithSameStorageOrder m_adjoint; - typename internal::plain_row_type::type m_workspace; -}; - -/*** 2x2 SVD implementation - *** - *** JacobiSVD consists in performing a series of 2x2 SVD subproblems - ***/ - -template -struct svd_precondition_2x2_block_to_be_real -{ - typedef JacobiSVD SVD; - typedef typename SVD::Index Index; - static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {} -}; - -template -struct svd_precondition_2x2_block_to_be_real -{ - typedef JacobiSVD SVD; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename SVD::Index Index; - static void run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q) - { - using std::sqrt; - Scalar z; - JacobiRotation rot; - RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p))); - if(n==0) - { - z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); - work_matrix.row(p) *= z; - if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z); - z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); - work_matrix.row(q) *= z; - if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); - } - else - { - rot.c() = conj(work_matrix.coeff(p,p)) / n; - rot.s() = work_matrix.coeff(q,p) / n; - work_matrix.applyOnTheLeft(p,q,rot); - if(svd.computeU()) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint()); - if(work_matrix.coeff(p,q) != Scalar(0)) - { - Scalar z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); - work_matrix.col(q) *= z; - if(svd.computeV()) svd.m_matrixV.col(q) *= z; - } - if(work_matrix.coeff(q,q) != Scalar(0)) - { - z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); - work_matrix.row(q) *= z; - if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); - } - } - } -}; - -template -void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, - JacobiRotation *j_left, - JacobiRotation *j_right) -{ - using std::sqrt; - Matrix m; - m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)), - numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q)); - JacobiRotation rot1; - RealScalar t = m.coeff(0,0) + m.coeff(1,1); - RealScalar d = m.coeff(1,0) - m.coeff(0,1); - if(t == RealScalar(0)) - { - rot1.c() = RealScalar(0); - rot1.s() = d > RealScalar(0) ? RealScalar(1) : RealScalar(-1); - } - else - { - RealScalar u = d / t; - rot1.c() = RealScalar(1) / sqrt(RealScalar(1) + numext::abs2(u)); - rot1.s() = rot1.c() * u; - } - m.applyOnTheLeft(0,1,rot1); - j_right->makeJacobi(m,0,1); - *j_left = rot1 * j_right->transpose(); -} - -} // end namespace internal - -/** \ingroup SVD_Module - * - * - * \class JacobiSVD - * - * \brief Two-sided Jacobi SVD decomposition of a rectangular matrix - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * \param QRPreconditioner this optional parameter allows to specify the type of QR decomposition that will be used internally - * for the R-SVD step for non-square matrices. See discussion of possible values below. - * - * SVD decomposition consists in decomposing any n-by-p matrix \a A as a product - * \f[ A = U S V^* \f] - * where \a U is a n-by-n unitary, \a V is a p-by-p unitary, and \a S is a n-by-p real positive matrix which is zero outside of its main diagonal; - * the diagonal entries of S are known as the \em singular \em values of \a A and the columns of \a U and \a V are known as the left - * and right \em singular \em vectors of \a A respectively. - * - * Singular values are always sorted in decreasing order. - * - * This JacobiSVD decomposition computes only the singular values by default. If you want \a U or \a V, you need to ask for them explicitly. - * - * You can ask for only \em thin \a U or \a V to be computed, meaning the following. In case of a rectangular n-by-p matrix, letting \a m be the - * smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual - * singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix, - * and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving. - * - * Here's an example demonstrating basic usage: - * \include JacobiSVD_basic.cpp - * Output: \verbinclude JacobiSVD_basic.out - * - * This JacobiSVD class is a two-sided Jacobi R-SVD decomposition, ensuring optimal reliability and accuracy. The downside is that it's slower than - * bidiagonalizing SVD algorithms for large square matrices; however its complexity is still \f$ O(n^2p) \f$ where \a n is the smaller dimension and - * \a p is the greater dimension, meaning that it is still of the same order of complexity as the faster bidiagonalizing R-SVD algorithms. - * In particular, like any R-SVD, it takes advantage of non-squareness in that its complexity is only linear in the greater dimension. - * - * If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to - * terminate in finite (and reasonable) time. - * - * The possible values for QRPreconditioner are: - * \li ColPivHouseholderQRPreconditioner is the default. In practice it's very safe. It uses column-pivoting QR. - * \li FullPivHouseholderQRPreconditioner, is the safest and slowest. It uses full-pivoting QR. - * Contrary to other QRs, it doesn't allow computing thin unitaries. - * \li HouseholderQRPreconditioner is the fastest, and less safe and accurate than the pivoting variants. It uses non-pivoting QR. - * This is very similar in safety and accuracy to the bidiagonalization process used by bidiagonalizing SVD algorithms (since bidiagonalization - * is inherently non-pivoting). However the resulting SVD is still more reliable than bidiagonalizing SVDs because the Jacobi-based iterarive - * process is more reliable than the optimized bidiagonal SVD iterations. - * \li NoQRPreconditioner allows not to use a QR preconditioner at all. This is useful if you know that you will only be computing - * JacobiSVD decompositions of square matrices. Non-square matrices require a QR preconditioner. Using this option will result in - * faster compilation and smaller executable code. It won't significantly speed up computation, since JacobiSVD is always checking - * if QR preconditioning is needed before applying it anyway. - * - * \sa MatrixBase::jacobiSvd() - */ -template -class JacobiSVD : public SVDBase<_MatrixType> -{ - public: - - 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 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 Matrix - WorkMatrixType; - - /** \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via JacobiSVD::compute(const MatrixType&). - */ - JacobiSVD() - : SVDBase<_MatrixType>::SVDBase() - {} - - - /** \brief Default Constructor with memory preallocation - * - * Like the default constructor but with preallocation of the internal data - * according to the specified problem size. - * \sa JacobiSVD() - */ - JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) - : SVDBase<_MatrixType>::SVDBase() - { - 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. - */ - JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) - : SVDBase<_MatrixType>::SVDBase() - { - compute(matrix, computationOptions); - } - - /** \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. - */ - SVDBase& 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). - */ - SVDBase& compute(const MatrixType& matrix) - { - return compute(matrix, this->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$. - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(this->m_isInitialized && "JacobiSVD is not initialized."); - eigen_assert(SVDBase::computeU() && SVDBase::computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice)."); - return internal::solve_retval(*this, b.derived()); - } - - - - private: - void allocate(Index rows, Index cols, unsigned int computationOptions); - - protected: - WorkMatrixType m_workMatrix; - - template - friend struct internal::svd_precondition_2x2_block_to_be_real; - template - friend struct internal::qr_preconditioner_impl; - - internal::qr_preconditioner_impl m_qr_precond_morecols; - internal::qr_preconditioner_impl m_qr_precond_morerows; -}; - -template -void JacobiSVD::allocate(Index rows, Index cols, unsigned int computationOptions) -{ - if (SVDBase::allocate(rows, cols, computationOptions)) return; - - if (QRPreconditioner == FullPivHouseholderQRPreconditioner) - { - eigen_assert(!(this->m_computeThinU || this->m_computeThinV) && - "JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. " - "Use the ColPivHouseholderQR preconditioner instead."); - } - - m_workMatrix.resize(this->m_diagSize, this->m_diagSize); - - if(this->m_cols>this->m_rows) m_qr_precond_morecols.allocate(*this); - if(this->m_rows>this->m_cols) m_qr_precond_morerows.allocate(*this); -} - -template -SVDBase& -JacobiSVD::compute(const MatrixType& matrix, unsigned int computationOptions) -{ - using std::abs; - allocate(matrix.rows(), matrix.cols(), computationOptions); - - // currently we stop when we reach precision 2*epsilon as the last bit of precision can require an unreasonable number of iterations, - // only worsening the precision of U and V as we accumulate more rotations - const RealScalar precision = RealScalar(2) * NumTraits::epsilon(); - - // 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(); - - /*** 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)) - { - m_workMatrix = matrix.block(0,0,this->m_diagSize,this->m_diagSize); - if(this->m_computeFullU) this->m_matrixU.setIdentity(this->m_rows,this->m_rows); - if(this->m_computeThinU) this->m_matrixU.setIdentity(this->m_rows,this->m_diagSize); - if(this->m_computeFullV) this->m_matrixV.setIdentity(this->m_cols,this->m_cols); - if(this->m_computeThinV) this->m_matrixV.setIdentity(this->m_cols, this->m_diagSize); - } - - /*** step 2. The main Jacobi SVD iteration. ***/ - - bool finished = false; - while(!finished) - { - finished = true; - - // do a sweep: for all index pairs (p,q), perform SVD of the corresponding 2x2 sub-matrix - - for(Index p = 1; p < this->m_diagSize; ++p) - { - for(Index q = 0; q < p; ++q) - { - // 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. - using std::max; - RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), - abs(m_workMatrix.coeff(q,q)))); - if((max)(abs(m_workMatrix.coeff(p,q)),abs(m_workMatrix.coeff(q,p))) > threshold) - { - finished = false; - - // perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal - internal::svd_precondition_2x2_block_to_be_real::run(m_workMatrix, *this, p, q); - JacobiRotation j_left, j_right; - internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right); - - // accumulate resulting Jacobi rotations - m_workMatrix.applyOnTheLeft(p,q,j_left); - if(SVDBase::computeU()) this->m_matrixU.applyOnTheRight(p,q,j_left.transpose()); - - m_workMatrix.applyOnTheRight(p,q,j_right); - if(SVDBase::computeV()) this->m_matrixV.applyOnTheRight(p,q,j_right); - } - } - } - } - - /*** step 3. The work matrix is now diagonal, so ensure it's positive so its diagonal entries are the singular values ***/ - - for(Index i = 0; i < this->m_diagSize; ++i) - { - RealScalar a = abs(m_workMatrix.coeff(i,i)); - this->m_singularValues.coeffRef(i) = a; - if(SVDBase::computeU() && (a!=RealScalar(0))) this->m_matrixU.col(i) *= this->m_workMatrix.coeff(i,i)/a; - } - - /*** step 4. Sort singular values in descending order and compute the number of nonzero singular values ***/ - - this->m_nonzeroSingularValues = this->m_diagSize; - for(Index i = 0; i < this->m_diagSize; i++) - { - Index pos; - RealScalar maxRemainingSingularValue = this->m_singularValues.tail(this->m_diagSize-i).maxCoeff(&pos); - if(maxRemainingSingularValue == RealScalar(0)) - { - this->m_nonzeroSingularValues = i; - break; - } - if(pos) - { - pos += i; - std::swap(this->m_singularValues.coeffRef(i), this->m_singularValues.coeffRef(pos)); - if(SVDBase::computeU()) this->m_matrixU.col(pos).swap(this->m_matrixU.col(i)); - if(SVDBase::computeV()) this->m_matrixV.col(pos).swap(this->m_matrixV.col(i)); - } - } - - this->m_isInitialized = true; - return *this; -} - -namespace internal { -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 - { - 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 JacobiSVDType::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(); - } -}; -} // end namespace internal - -/** \svd_module - * - * \return the singular value decomposition of \c *this computed by two-sided - * Jacobi transformations. - * - * \sa class JacobiSVD - */ -template -JacobiSVD::PlainObject> -MatrixBase::jacobiSvd(unsigned int computationOptions) const -{ - return JacobiSVD(*this, computationOptions); -} - -} // end namespace Eigen - -#endif // EIGEN_JACOBISVD_H diff --git a/unsupported/Eigen/src/SVD/SVDBase.h b/unsupported/Eigen/src/SVD/SVDBase.h deleted file mode 100644 index fd8af3b8c..000000000 --- a/unsupported/Eigen/src/SVD/SVDBase.h +++ /dev/null @@ -1,236 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 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/. - -#ifndef EIGEN_SVD_H -#define EIGEN_SVD_H - -namespace Eigen { -/** \ingroup SVD_Module - * - * - * \class SVDBase - * - * \brief Mother class of SVD classes algorithms - * - * \param MatrixType the type of the matrix of which we are computing the SVD decomposition - * SVD decomposition consists in decomposing any n-by-p matrix \a A as a product - * \f[ A = U S V^* \f] - * where \a U is a n-by-n unitary, \a V is a p-by-p unitary, and \a S is a n-by-p real positive matrix which is zero outside of its main diagonal; - * the diagonal entries of S are known as the \em singular \em values of \a A and the columns of \a U and \a V are known as the left - * and right \em singular \em vectors of \a A respectively. - * - * Singular values are always sorted in decreasing order. - * - * - * You can ask for only \em thin \a U or \a V to be computed, meaning the following. In case of a rectangular n-by-p matrix, letting \a m be the - * smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual - * singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix, - * and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving. - * - * If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to - * terminate in finite (and reasonable) time. - * \sa MatrixBase::genericSvd() - */ -template -class SVDBase -{ - -public: - 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 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 Matrix - WorkMatrixType; - - - - - /** \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. - */ - SVDBase& 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). - */ - //virtual SVDBase& compute(const MatrixType& matrix) = 0; - SVDBase& compute(const MatrixType& matrix); - - /** \returns the \a U matrix. - * - * For the SVDBase decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU. - * - * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a U to be computed. - */ - const MatrixUType& matrixU() const - { - eigen_assert(m_isInitialized && "SVD is not initialized."); - eigen_assert(computeU() && "This SVD decomposition didn't compute U. Did you ask for it?"); - return m_matrixU; - } - - /** \returns the \a V matrix. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, - * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV. - * - * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed. - * - * This method asserts that you asked for \a V to be computed. - */ - const MatrixVType& matrixV() const - { - eigen_assert(m_isInitialized && "SVD is not initialized."); - eigen_assert(computeV() && "This SVD decomposition didn't compute V. Did you ask for it?"); - return m_matrixV; - } - - /** \returns the vector of singular values. - * - * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the - * returned vector has size \a m. Singular values are always sorted in decreasing order. - */ - const SingularValuesType& singularValues() const - { - eigen_assert(m_isInitialized && "SVD is not initialized."); - return m_singularValues; - } - - - - /** \returns the number of singular values that are not exactly 0 */ - Index nonzeroSingularValues() const - { - eigen_assert(m_isInitialized && "SVD is not initialized."); - return m_nonzeroSingularValues; - } - - - /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */ - inline bool computeU() const { return m_computeFullU || m_computeThinU; } - /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */ - inline bool computeV() const { return m_computeFullV || m_computeThinV; } - - - inline Index rows() const { return m_rows; } - inline Index cols() const { return m_cols; } - - -protected: - // return true if already allocated - bool allocate(Index rows, Index cols, unsigned int computationOptions) ; - - MatrixUType m_matrixU; - MatrixVType m_matrixV; - SingularValuesType m_singularValues; - bool m_isInitialized, m_isAllocated; - bool m_computeFullU, m_computeThinU; - bool m_computeFullV, m_computeThinV; - unsigned int m_computationOptions; - Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; - - - /** \brief Default Constructor. - * - * Default constructor of SVDBase - */ - SVDBase() - : m_isInitialized(false), - m_isAllocated(false), - m_computationOptions(0), - m_rows(-1), m_cols(-1) - {} - - -}; - - -template -bool SVDBase::allocate(Index rows, Index cols, unsigned int computationOptions) -{ - eigen_assert(rows >= 0 && cols >= 0); - - if (m_isAllocated && - rows == m_rows && - cols == m_cols && - computationOptions == m_computationOptions) - { - return true; - } - - m_rows = rows; - m_cols = cols; - m_isInitialized = false; - m_isAllocated = true; - m_computationOptions = computationOptions; - m_computeFullU = (computationOptions & ComputeFullU) != 0; - m_computeThinU = (computationOptions & ComputeThinU) != 0; - m_computeFullV = (computationOptions & ComputeFullV) != 0; - m_computeThinV = (computationOptions & ComputeThinV) != 0; - eigen_assert(!(m_computeFullU && m_computeThinU) && "SVDBase: you can't ask for both full and thin U"); - eigen_assert(!(m_computeFullV && m_computeThinV) && "SVDBase: you can't ask for both full and thin V"); - eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) && - "SVDBase: thin U and V are only available when your matrix has a dynamic number of columns."); - - m_diagSize = (std::min)(m_rows, m_cols); - m_singularValues.resize(m_diagSize); - if(RowsAtCompileTime==Dynamic) - m_matrixU.resize(m_rows, m_computeFullU ? m_rows - : m_computeThinU ? m_diagSize - : 0); - if(ColsAtCompileTime==Dynamic) - m_matrixV.resize(m_cols, m_computeFullV ? m_cols - : m_computeThinV ? m_diagSize - : 0); - - return false; -} - -}// end namespace - -#endif // EIGEN_SVD_H diff --git a/unsupported/Eigen/src/SVD/TODOBdcsvd.txt b/unsupported/Eigen/src/SVD/TODOBdcsvd.txt deleted file mode 100644 index 0bc9a46e6..000000000 --- a/unsupported/Eigen/src/SVD/TODOBdcsvd.txt +++ /dev/null @@ -1,29 +0,0 @@ -TO DO LIST - - - -(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/SVD/doneInBDCSVD.txt b/unsupported/Eigen/src/SVD/doneInBDCSVD.txt deleted file mode 100644 index 8563ddab8..000000000 --- a/unsupported/Eigen/src/SVD/doneInBDCSVD.txt +++ /dev/null @@ -1,21 +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 - -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: -http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf - diff --git a/unsupported/test/svd_common.h b/unsupported/test/svd_common.h index b40c23a2b..6a96e7c74 100644 --- a/unsupported/test/svd_common.h +++ b/unsupported/test/svd_common.h @@ -18,7 +18,7 @@ #define EIGEN_RUNTIME_NO_MALLOC #include "main.h" -#include +#include #include -- 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 9452eb38f812194a676edc1b9eb9d08b7bc0f297 Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Fri, 12 Sep 2014 14:52:35 +0100 Subject: Make UpperBidiagonalization accept row-major matrices (bug #769) * Give temporary workspace the same storage order as original matrix * Take storage order into account when determining inner stride of rows and columns * Change one test to use a row-major matrix. --- Eigen/src/SVD/UpperBidiagonalization.h | 29 ++++++++++++++++++++++------- test/upperbidiagonalization.cpp | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h index 225b19e3c..64906bf0c 100644 --- a/Eigen/src/SVD/UpperBidiagonalization.h +++ b/Eigen/src/SVD/UpperBidiagonalization.h @@ -154,14 +154,19 @@ void upperbidiagonalization_blocked_helper(MatrixType& A, typename MatrixType::RealScalar *diagonal, typename MatrixType::RealScalar *upper_diagonal, typename MatrixType::Index bs, - Ref > X, - Ref > Y) + Ref::Flags & RowMajorBit> > X, + Ref::Flags & RowMajorBit> > Y) { typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; - typedef Ref > SubColumnType; - typedef Ref, 0, InnerStride<> > SubRowType; - typedef Ref > SubMatType; + enum { StorageOrder = traits::Flags & RowMajorBit }; + typedef InnerStride ColInnerStride; + typedef InnerStride RowInnerStride; + typedef Ref, 0, ColInnerStride> SubColumnType; + typedef Ref, 0, RowInnerStride> SubRowType; + typedef Ref > SubMatType; Index brows = A.rows(); Index bcols = A.cols(); @@ -288,8 +293,18 @@ void upperbidiagonalization_inplace_blocked(MatrixType& A, BidiagType& bidiagona Index cols = A.cols(); Index size = (std::min)(rows, cols); - Matrix X(rows,maxBlockSize); - Matrix Y(cols,maxBlockSize); + // X and Y are work space + enum { StorageOrder = traits::Flags & RowMajorBit }; + Matrix X(rows,maxBlockSize); + Matrix Y(cols,maxBlockSize); Index blockSize = (std::min)(maxBlockSize,size); Index k = 0; diff --git a/test/upperbidiagonalization.cpp b/test/upperbidiagonalization.cpp index d15bf588b..847b34b55 100644 --- a/test/upperbidiagonalization.cpp +++ b/test/upperbidiagonalization.cpp @@ -35,7 +35,7 @@ void test_upperbidiagonalization() CALL_SUBTEST_1( upperbidiag(MatrixXf(3,3)) ); CALL_SUBTEST_2( upperbidiag(MatrixXd(17,12)) ); CALL_SUBTEST_3( upperbidiag(MatrixXcf(20,20)) ); - CALL_SUBTEST_4( upperbidiag(MatrixXcd(16,15)) ); + CALL_SUBTEST_4( upperbidiag(Matrix,Dynamic,Dynamic,RowMajor>(16,15)) ); CALL_SUBTEST_5( upperbidiag(Matrix()) ); CALL_SUBTEST_6( upperbidiag(Matrix()) ); CALL_SUBTEST_7( upperbidiag(Matrix()) ); -- 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