diff options
author | Gael Guennebaud <g.gael@free.fr> | 2014-02-17 16:11:55 +0100 |
---|---|---|
committer | Gael Guennebaud <g.gael@free.fr> | 2014-02-17 16:11:55 +0100 |
commit | d595fd31f544009e62a55d6ffc26e0b62f3147d5 (patch) | |
tree | d65354f2693e90a686ba6f31a4a57a5dbec7b9c8 | |
parent | bffa15142c4271313a70801e6bb7d01365a00bc9 (diff) |
Deal with automatic transposition in call_assignment, fix a few shortcomings
-rw-r--r-- | Eigen/src/Core/Assign.h | 27 | ||||
-rw-r--r-- | Eigen/src/Core/AssignEvaluator.h | 59 | ||||
-rw-r--r-- | Eigen/src/Core/PlainObjectBase.h | 19 | ||||
-rw-r--r-- | Eigen/src/Core/TriangularMatrix.h | 2 | ||||
-rw-r--r-- | 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<Derived> namespace internal { +#ifdef EIGEN_TEST_EVALUATORS + +// TODO remove this class which is now useless + +template<typename Derived, typename OtherDerived> +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<typename OtherDerived::Scalar>()); + return dst; + } + template<typename ActualDerived, typename ActualOtherDerived> + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } +}; + +#else // EIGEN_TEST_EVALUATORS template<typename Derived, typename OtherDerived, bool EvalBeforeAssigning = (int(internal::traits<OtherDerived>::Flags) & EvalBeforeAssigningBit) != 0, bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) @@ -566,7 +583,7 @@ struct assign_selector<Derived,OtherDerived,true,true> { 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<typename Derived> @@ -604,7 +621,11 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const EigenBase<OtherDerived>& other) { +#ifdef EIGEN_TEST_EVALUATORS + return internal::assign_selector<Derived,OtherDerived>::evalTo(derived(), other.derived()); +#else return internal::assign_selector<Derived,OtherDerived,false>::evalTo(derived(), other.derived()); +#endif } template<typename Derived> @@ -612,7 +633,11 @@ template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other) { +#ifdef EIGEN_TEST_EVALUATORS + return internal::assign_selector<Derived,OtherDerived>::evalTo(derived(), other.derived()); +#else return internal::assign_selector<Derived,OtherDerived,false>::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<typename Dst, typename Src> 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<NeedToTranspose, Transpose<Dst>, Dst>::type type; +}; + +template<typename Dst, typename Src> +void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op<typename Dst::Scalar>()); +} +template<typename Dst, typename Src> +void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op<typename Dst::Scalar>()); +} + +// Deal with AssumeAliasing +template<typename Dst, typename Src, typename Func> +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if<evaluator_traits<Src>::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<evaluator_traits<Src>::AssumeAliasing==1, EvalToTemp<Src>, Src>::type ActualSrc; + // Assignment<Dst,ActualSrc,Func>::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<typename Dst, typename Src, typename Func> -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<evaluator_traits<Src>::AssumeAliasing==0, void*>::type = 0) { - typedef typename internal::conditional<evaluator_traits<Src>::AssumeAliasing==1, EvalToTemp<Src>, Src>::type ActualSrc; - Assignment<Dst,ActualSrc,Func>::run(dst, src, func); + Assignment<typename transpose_to_match<Dst,Src>::type,Src,Func>::run(dst, src, func); } // by-pass AssumeAliasing +// FIXME the const version should probably not be needed template<typename Dst, template <typename> class StorageBase, typename Src, typename Func> void call_assignment(const NoAlias<Dst,StorageBase>& dst, const Src& src, const Func& func) { - Assignment<Dst,Src,Func>::run(dst.expression(), src, func); + Assignment<typename transpose_to_match<Dst,Src>::type,Src,Func>::run(dst.expression(), src, func); } template<typename Dst, template <typename> class StorageBase, typename Src, typename Func> void call_assignment(NoAlias<Dst,StorageBase>& dst, const Src& src, const Func& func) { - Assignment<Dst,Src,Func>::run(dst.expression(), src, func); + Assignment<typename transpose_to_match<Dst,Src>::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<Derived>::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<typename OtherDerived> + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& _set(const DenseBase<OtherDerived>& other) + { + internal::call_assignment(this->derived(), other.derived()); + return this->derived(); + return this->derived(); + } +#else template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase<OtherDerived>& other) @@ -654,7 +666,7 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type template<typename OtherDerived> 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<Derived>::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<Derived,OtherDerived,false>::run(this->derived(), other.derived()); +#endif } template<typename T0, typename T1> 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<Kernel, Mode, Dynamic, SetOpposite> } // 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<typename Derived> @@ -1244,6 +1245,7 @@ void TriangularBase<Derived>::evalToLazy(MatrixBase<DenseDerived> &other) const other.derived().resize(this->rows(), this->cols()); internal::call_triangular_assignment_loop<Derived::Mode,(Derived::Mode&SelfAdjoint)==0 /* SetOpposite */>(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<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> > 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, |