diff --git a/Eigen/Core b/Eigen/Core index 28ed09035..ff56c6ca2 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -154,6 +154,7 @@ namespace Eigen { #include "src/Core/NestByValue.h" #include "src/Core/ReturnByValue.h" #include "src/Core/Flagged.h" +#include "src/Core/NoAlias.h" #include "src/Core/Matrix.h" #include "src/Core/Cwise.h" #include "src/Core/CwiseBinaryOp.h" diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index 4bd1046a7..b0e69224e 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h @@ -434,7 +434,7 @@ EIGEN_STRONG_INLINE Derived& MatrixBase } template clas ExpressionTypeNested m_matrix; }; -/** \returns an expression of *this with added flags +/** \deprecated it is only used by lazy() which is deprecated * - * \addexample MarkExample \label How to mark a triangular matrix as triangular + * \returns an expression of *this with added flags * * Example: \include MatrixBase_marked.cpp * Output: \verbinclude MatrixBase_marked.out @@ -128,8 +130,9 @@ MatrixBase::marked() const return derived(); } -/** \returns an expression of *this with the following flags removed: - * EvalBeforeNestingBit and EvalBeforeAssigningBit. +/** \deprecated use MatrixBase::noalias() + * + * \returns an expression of *this with the MayAliasBit flag removed. * * Example: \include MatrixBase_lazy.cpp * Output: \verbinclude MatrixBase_lazy.out @@ -137,7 +140,7 @@ MatrixBase::marked() const * \sa class Flagged, marked() */ template -inline const Flagged +inline const Flagged MatrixBase::lazy() const { return derived(); diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 51e041db6..b9e9374be 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -179,11 +179,11 @@ template class MapBase // explicitly add these two overloads. // Maybe there exists a better solution though. template - Derived& operator+=(const Flagged, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) + Derived& operator+=(const Flagged, 0, MayAliasBit>& other) { return Base::operator+=(other); } template - Derived& operator-=(const Flagged, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) + Derived& operator-=(const Flagged, 0, MayAliasBit>& other) { return Base::operator-=(other); } template diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index f58424ba2..d129535b6 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -577,7 +577,7 @@ class Matrix template EIGEN_STRONG_INLINE Matrix& _set(const MatrixBase& other) { - _set_selector(other.derived(), typename ei_meta_if(int(OtherDerived::Flags) & EvalBeforeAssigningBit), ei_meta_true, ei_meta_false>::ret()); + _set_selector(other.derived(), typename ei_meta_if(int(OtherDerived::Flags) & MayAliasBit), ei_meta_true, ei_meta_false>::ret()); return *this; } diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 52d5f680c..a554de8e3 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -326,9 +326,10 @@ template class MatrixBase template Derived& lazyAssign(const MatrixBase& other); - /** Overloaded for cache friendly product evaluation */ + /** \deprecated because .lazy() is deprecated + * Overloaded for cache friendly product evaluation */ template - Derived& lazyAssign(const Flagged& other) + Derived& lazyAssign(const Flagged& other) { return lazyAssign(other._expression()); } template @@ -336,11 +337,11 @@ template class MatrixBase template Derived& operator+=(const Flagged, 0, - EvalBeforeNestingBit | EvalBeforeAssigningBit>& other); + MayAliasBit>& other); template Derived& operator-=(const Flagged, 0, - EvalBeforeNestingBit | EvalBeforeAssigningBit>& other); + MayAliasBit>& other); #endif // not EIGEN_PARSED_BY_DOXYGEN CommaInitializer operator<< (const Scalar& s); @@ -614,7 +615,9 @@ template class MatrixBase template const Flagged marked() const; - const Flagged lazy() const; + const Flagged lazy() const; + + NoAlias noalias(); /** \returns number of elements to skip to pass from one row (resp. column) to another * for a row-major (resp. column-major) matrix. diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h new file mode 100644 index 000000000..5c2b6e3ca --- /dev/null +++ b/Eigen/src/Core/NoAlias.h @@ -0,0 +1,94 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_NOALIAS_H +#define EIGEN_NOALIAS_H + +/** \class NoAlias + * + * \brief Pseudo expression providing an operator = assuming no aliasing + * + * \param ExpressionType the type of the object on which to do the lazy assignment + * + * This class represents an expression with a special assignment operator (operator=) + * assuming no aliasing between the target expression and the source expression. + * It is the return type of MatrixBase::noalias() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::noalias() + */ +template +class NoAlias +{ + public: + NoAlias(ExpressionType& expression) : m_expression(expression) {} + + /** Behaves like MatrixBase::lazyAssign() */ + template + ExpressionType& operator=(const MatrixBase& other) + { + return m_expression.lazyAssign(other.derived()); + } + + // TODO could be removed if we decide that += is noalias by default + template + ExpressionType& operator+=(const MatrixBase& other) + { + return m_expression.lazyAssign(m_expression + other.derived()); + } + + // TODO could be removed if we decide that += is noalias by default + template + ExpressionType& operator-=(const MatrixBase& other) + { + return m_expression.lazyAssign(m_expression - other.derived()); + } + + // TODO could be removed if we decide that += is noalias by default + template + ExpressionType& operator+=(const ProductBase& other) + { other.derived().addTo(m_expression); return m_expression; } + + // TODO could be removed if we decide that += is noalias by default + template + ExpressionType& operator-=(const ProductBase& other) + { other.derived().subTo(m_expression); return m_expression; } + + protected: + ExpressionType& m_expression; +}; + + +/** \returns a pseudo expression of \c *this with an operator= assuming + * no aliasing between \c *this and the source expression + * + * \sa class NoAlias + */ +template +NoAlias MatrixBase::noalias() +{ + return derived(); +} + +#endif // EIGEN_NOALIAS_H diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index b5ed5ae8f..867aa7a15 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -39,7 +39,7 @@ struct ei_traits > ColsAtCompileTime = ei_traits::ColsAtCompileTime, MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = ei_traits::MaxColsAtCompileTime, - Flags = EvalBeforeNestingBit | EvalBeforeAssigningBit, + Flags = EvalBeforeNestingBit | MayAliasBit, CoeffReadCost = 0 // FIXME why is it needed ? }; }; @@ -119,7 +119,7 @@ class ProductBase : public MatrixBase return res; } - const Flagged lazy() const + const Flagged lazy() const { return *this; } @@ -228,7 +228,7 @@ Derived& MatrixBase::lazyAssign(const ProductBase template Derived& MatrixBase::operator+=(const Flagged, 0, - EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) + MayAliasBit>& other) { other._expression().derived().addTo(derived()); return derived(); } @@ -238,7 +238,7 @@ Derived& MatrixBase::operator+=(const Flagged template Derived& MatrixBase::operator-=(const Flagged, 0, - EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) + MayAliasBit>& other) { other._expression().derived().subTo(derived()); return derived(); } diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index b0362f20c..cfaf89733 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -477,7 +477,7 @@ template inline TriangularView& TriangularView::operator=(const MatrixBase& other) { - if(OtherDerived::Flags & EvalBeforeAssigningBit) + if(OtherDerived::Flags & MayAliasBit) { typename OtherDerived::PlainMatrixType other_evaluated(other.rows(), other.cols()); other_evaluated.template triangularView().lazyAssign(other.derived()); @@ -512,7 +512,7 @@ inline TriangularView& TriangularView::operator=(const TriangularBase& other) { ei_assert(Mode == OtherDerived::Mode); - if(ei_traits::Flags & EvalBeforeAssigningBit) + if(ei_traits::Flags & MayAliasBit) { typename OtherDerived::PlainMatrixType other_evaluated(other.rows(), other.cols()); other_evaluated.template triangularView().lazyAssign(other.derived()); @@ -548,7 +548,7 @@ template template void TriangularBase::evalToDense(MatrixBase &other) const { - if(ei_traits::Flags & EvalBeforeAssigningBit) + if(ei_traits::Flags & MayAliasBit) { typename Derived::PlainMatrixType other_evaluated(rows(), cols()); evalToDenseLazy(other_evaluated); diff --git a/Eigen/src/Core/products/GeneralUnrolled.h b/Eigen/src/Core/products/GeneralUnrolled.h index 7241976a8..2961d9452 100644 --- a/Eigen/src/Core/products/GeneralUnrolled.h +++ b/Eigen/src/Core/products/GeneralUnrolled.h @@ -76,7 +76,7 @@ struct ei_traits > RemovedBits = ~(EvalToRowMajor ? 0 : RowMajorBit), Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & RemovedBits) - | EvalBeforeAssigningBit + | MayAliasBit | EvalBeforeNestingBit | (CanVectorizeLhs || CanVectorizeRhs ? PacketAccessBit : 0) | (LhsFlags & RhsFlags & AlignedBit), diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 21e7f62c3..1d55217f5 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -76,8 +76,10 @@ const unsigned int EvalBeforeNestingBit = 0x2; /** \ingroup flags * - * means the expression should be evaluated before any assignement */ -const unsigned int EvalBeforeAssigningBit = 0x4; + * Means the expression cannot be evaluated safely if the result alias one + * of the operands of the expression. Therefore it should be evaluated + * before any assignement. */ +const unsigned int MayAliasBit = 0x4; /** \ingroup flags * @@ -182,7 +184,7 @@ const unsigned int SparseBit = 0x1000; // list of flags that are inherited by default const unsigned int HereditaryBits = RowMajorBit | EvalBeforeNestingBit - | EvalBeforeAssigningBit + | MayAliasBit | SparseBit; // Possible values for the Mode parameter of part() diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index c9ce174d2..6f3e6a788 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -35,6 +35,7 @@ template class Matrix; template class Flagged; +template class NoAlias; template class NestByValue; template class SwapWrapper; template class Minor; diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp index d5d996e49..f6e8f4101 100644 --- a/test/product_notemporary.cpp +++ b/test/product_notemporary.cpp @@ -71,15 +71,19 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1); VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0); + // NOTE in this case the slow product is used: // FIXME: -// VERIFY_EVALUATION_COUNT( m3 = s1 * (m1 * m2.transpose()).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0); VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * m2.adjoint()).lazy(), 0); VERIFY_EVALUATION_COUNT( m3 = (s1 * m1 * s2 * (m1*s3+m2*s2).adjoint()).lazy(), 1); VERIFY_EVALUATION_COUNT( m3 = ((s1 * m1).adjoint() * s2 * m2).lazy(), 0); - VERIFY_EVALUATION_COUNT( m3 -= (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3 += (s1 * (-m1*s3).adjoint() * (s2 * m2 * s3)).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0); VERIFY_EVALUATION_COUNT( m3 -= (s1 * (m1.transpose() * m2)).lazy(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) += (-m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint()).lazy() ), 0); VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1) -= (s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1)).lazy() ), 0); diff --git a/test/submatrices.cpp b/test/submatrices.cpp index fc7fd09ea..a819cadc2 100644 --- a/test/submatrices.cpp +++ b/test/submatrices.cpp @@ -86,7 +86,8 @@ template void submatrices(const MatrixType& m) //check row() and col() VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1)); - VERIFY_IS_APPROX(m1.col(c1).dot(square.row(r1)), (square.lazy() * m1.conjugate()).eval()(r1,c1)); + // FIXME perhaps we should re-enable that without the .eval() + VERIFY_IS_APPROX(m1.col(c1).dot(square.row(r1)), (square * m1.conjugate()).eval()(r1,c1)); //check operator(), both constant and non-constant, on row() and col() m1.row(r1) += s1 * m1.row(r2); m1.col(c1) += s1 * m1.col(c2);