mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-12 11:49:02 +08:00
Deal with automatic transposition in call_assignment, fix a few shortcomings
This commit is contained in:
parent
bffa15142c
commit
d595fd31f5
@ -531,6 +531,23 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>
|
|||||||
|
|
||||||
namespace internal {
|
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,
|
template<typename Derived, typename OtherDerived,
|
||||||
bool EvalBeforeAssigning = (int(internal::traits<OtherDerived>::Flags) & EvalBeforeAssigningBit) != 0,
|
bool EvalBeforeAssigning = (int(internal::traits<OtherDerived>::Flags) & EvalBeforeAssigningBit) != 0,
|
||||||
bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1)
|
bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1)
|
||||||
@ -566,7 +583,7 @@ struct assign_selector<Derived,OtherDerived,true,true> {
|
|||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); }
|
static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); }
|
||||||
};
|
};
|
||||||
|
#endif // EIGEN_TEST_EVALUATORS
|
||||||
} // end namespace internal
|
} // end namespace internal
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
@ -604,7 +621,11 @@ template <typename OtherDerived>
|
|||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const EigenBase<OtherDerived>& other)
|
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());
|
return internal::assign_selector<Derived,OtherDerived,false>::evalTo(derived(), other.derived());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
@ -612,7 +633,11 @@ template<typename OtherDerived>
|
|||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
|
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());
|
return internal::assign_selector<Derived,OtherDerived,false>::evalTo(derived(), other.derived());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace Eigen
|
} // end namespace Eigen
|
||||||
|
@ -656,28 +656,75 @@ template< typename DstXprType, typename SrcXprType, typename Functor,
|
|||||||
struct Assignment;
|
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.
|
// 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
|
// So this intermediate function removes everything related to AssumeAliasing such that Assignment
|
||||||
// does not has to bother about these annoying details.
|
// does not has to bother about these annoying details.
|
||||||
|
|
||||||
template<typename Dst, typename Src, typename Func>
|
template<typename Dst, typename Src> struct transpose_to_match
|
||||||
void call_assignment(Dst& dst, const Src& src, const Func& func)
|
|
||||||
{
|
{
|
||||||
typedef typename internal::conditional<evaluator_traits<Src>::AssumeAliasing==1, EvalToTemp<Src>, Src>::type ActualSrc;
|
enum {
|
||||||
Assignment<Dst,ActualSrc,Func>::run(dst, src, func);
|
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, typename enable_if<evaluator_traits<Src>::AssumeAliasing==0, void*>::type = 0)
|
||||||
|
{
|
||||||
|
Assignment<typename transpose_to_match<Dst,Src>::type,Src,Func>::run(dst, src, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// by-pass AssumeAliasing
|
// by-pass AssumeAliasing
|
||||||
|
// FIXME the const version should probably not be needed
|
||||||
template<typename Dst, template <typename> class StorageBase, typename Src, typename Func>
|
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)
|
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>
|
template<typename Dst, template <typename> class StorageBase, typename Src, typename Func>
|
||||||
void call_assignment(NoAlias<Dst,StorageBase>& dst, const Src& src, const Func& 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
|
// Generic Dense to Dense assignment
|
||||||
|
@ -639,6 +639,18 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
|
|||||||
*
|
*
|
||||||
* \internal
|
* \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>
|
template<typename OtherDerived>
|
||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
EIGEN_STRONG_INLINE Derived& _set(const DenseBase<OtherDerived>& other)
|
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>
|
template<typename OtherDerived>
|
||||||
EIGEN_DEVICE_FUNC
|
EIGEN_DEVICE_FUNC
|
||||||
EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); }
|
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
|
/** \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.
|
* 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);
|
//_resize_to_match(other);
|
||||||
// the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because
|
// 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.
|
// 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());
|
return internal::assign_selector<Derived,OtherDerived,false>::run(this->derived(), other.derived());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T0, typename T1>
|
template<typename T0, typename T1>
|
||||||
|
@ -1235,6 +1235,7 @@ struct triangular_assignment_loop<Kernel, Mode, Dynamic, SetOpposite>
|
|||||||
|
|
||||||
} // end namespace internal
|
} // end namespace internal
|
||||||
|
|
||||||
|
#ifdef EIGEN_TEST_EVALUATORS
|
||||||
/** Assigns a triangular or selfadjoint matrix to a dense matrix.
|
/** Assigns a triangular or selfadjoint matrix to a dense matrix.
|
||||||
* If the matrix is triangular, the opposite part is set to zero. */
|
* If the matrix is triangular, the opposite part is set to zero. */
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
@ -1244,6 +1245,7 @@ void TriangularBase<Derived>::evalToLazy(MatrixBase<DenseDerived> &other) const
|
|||||||
other.derived().resize(this->rows(), this->cols());
|
other.derived().resize(this->rows(), this->cols());
|
||||||
internal::call_triangular_assignment_loop<Derived::Mode,(Derived::Mode&SelfAdjoint)==0 /* SetOpposite */>(other.derived(), derived().nestedExpression());
|
internal::call_triangular_assignment_loop<Derived::Mode,(Derived::Mode&SelfAdjoint)==0 /* SetOpposite */>(other.derived(), derived().nestedExpression());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // EIGEN_ENABLE_EVALUATORS
|
#endif // EIGEN_ENABLE_EVALUATORS
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ struct traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> >
|
|||||||
typename traits<_RhsNested>::Index>::type Index;
|
typename traits<_RhsNested>::Index>::type Index;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
LhsCoeffReadCost = _LhsNested::CoeffReadCost,
|
LhsCoeffReadCost = traits<_LhsNested>::CoeffReadCost,
|
||||||
RhsCoeffReadCost = _RhsNested::CoeffReadCost,
|
RhsCoeffReadCost = traits<_RhsNested>::CoeffReadCost,
|
||||||
LhsFlags = traits<_LhsNested>::Flags,
|
LhsFlags = traits<_LhsNested>::Flags,
|
||||||
RhsFlags = traits<_RhsNested>::Flags,
|
RhsFlags = traits<_RhsNested>::Flags,
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user