From d595fd31f544009e62a55d6ffc26e0b62f3147d5 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 17 Feb 2014 16:11:55 +0100 Subject: [PATCH] Deal with automatic transposition in call_assignment, fix a few shortcomings --- Eigen/src/Core/Assign.h | 27 ++++++++- Eigen/src/Core/AssignEvaluator.h | 61 ++++++++++++++++++--- Eigen/src/Core/PlainObjectBase.h | 19 ++++++- Eigen/src/Core/TriangularMatrix.h | 2 + Eigen/src/Core/products/CoeffBasedProduct.h | 4 +- 5 files changed, 102 insertions(+), 11 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 -void call_assignment(Dst& dst, const Src& src, const Func& func) +template struct transpose_to_match { - typedef typename internal::conditional::AssumeAliasing==1, EvalToTemp, Src>::type ActualSrc; - Assignment::run(dst, src, func); + 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, typename enable_if::AssumeAliasing==0, void*>::type = 0) +{ + 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,