1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr> 5 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> 6 // 7 // This Source Code Form is subject to the terms of the Mozilla 8 // Public License v. 2.0. If a copy of the MPL was not distributed 9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 11 #ifndef EIGEN_CWISE_BINARY_OP_H 12 #define EIGEN_CWISE_BINARY_OP_H 13 14 namespace Eigen { 15 16 /** \class CwiseBinaryOp 17 * \ingroup Core_Module 18 * 19 * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions 20 * 21 * \param BinaryOp template functor implementing the operator 22 * \param Lhs the type of the left-hand side 23 * \param Rhs the type of the right-hand side 24 * 25 * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. 26 * It is the return type of binary operators, by which we mean only those binary operators where 27 * both the left-hand side and the right-hand side are Eigen expressions. 28 * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. 29 * 30 * Most of the time, this is the only way that it is used, so you typically don't have to name 31 * CwiseBinaryOp types explicitly. 32 * 33 * \sa MatrixBase::binaryExpr(const MatrixBase<OtherDerived> &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp 34 */ 35 36 namespace internal { 37 template<typename BinaryOp, typename Lhs, typename Rhs> 38 struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > 39 { 40 // we must not inherit from traits<Lhs> since it has 41 // the potential to cause problems with MSVC 42 typedef typename remove_all<Lhs>::type Ancestor; 43 typedef typename traits<Ancestor>::XprKind XprKind; 44 enum { 45 RowsAtCompileTime = traits<Ancestor>::RowsAtCompileTime, 46 ColsAtCompileTime = traits<Ancestor>::ColsAtCompileTime, 47 MaxRowsAtCompileTime = traits<Ancestor>::MaxRowsAtCompileTime, 48 MaxColsAtCompileTime = traits<Ancestor>::MaxColsAtCompileTime 49 }; 50 51 // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), 52 // we still want to handle the case when the result type is different. 53 typedef typename result_of< 54 BinaryOp( 55 typename Lhs::Scalar, 56 typename Rhs::Scalar 57 ) 58 >::type Scalar; 59 typedef typename promote_storage_type<typename traits<Lhs>::StorageKind, 60 typename traits<Rhs>::StorageKind>::ret StorageKind; 61 typedef typename promote_index_type<typename traits<Lhs>::Index, 62 typename traits<Rhs>::Index>::type Index; 63 typedef typename Lhs::Nested LhsNested; 64 typedef typename Rhs::Nested RhsNested; 65 typedef typename remove_reference<LhsNested>::type _LhsNested; 66 typedef typename remove_reference<RhsNested>::type _RhsNested; 67 enum { 68 LhsCoeffReadCost = _LhsNested::CoeffReadCost, 69 RhsCoeffReadCost = _RhsNested::CoeffReadCost, 70 LhsFlags = _LhsNested::Flags, 71 RhsFlags = _RhsNested::Flags, 72 SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value, 73 StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), 74 Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( 75 HereditaryBits 76 | (int(LhsFlags) & int(RhsFlags) & 77 ( AlignedBit 78 | (StorageOrdersAgree ? LinearAccessBit : 0) 79 | (functor_traits<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) 80 ) 81 ) 82 ), 83 Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), 84 CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost 85 }; 86 }; 87 } // end namespace internal 88 89 // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor 90 // that would take two operands of different types. If there were such an example, then this check should be 91 // moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as 92 // currently they take only one typename Scalar template parameter. 93 // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. 94 // So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to 95 // add together a float matrix and a double matrix. 96 #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ 97 EIGEN_STATIC_ASSERT((internal::functor_is_product_like<BINOP>::ret \ 98 ? int(internal::scalar_product_traits<LHS, RHS>::Defined) \ 99 : int(internal::is_same<LHS, RHS>::value)), \ 100 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) 101 102 template<typename BinaryOp, typename Lhs, typename Rhs, typename StorageKind> 103 class CwiseBinaryOpImpl; 104 105 template<typename BinaryOp, typename Lhs, typename Rhs> 106 class CwiseBinaryOp : internal::no_assignment_operator, 107 public CwiseBinaryOpImpl< 108 BinaryOp, Lhs, Rhs, 109 typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind, 110 typename internal::traits<Rhs>::StorageKind>::ret> 111 { 112 public: 113 114 typedef typename CwiseBinaryOpImpl< 115 BinaryOp, Lhs, Rhs, 116 typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind, 117 typename internal::traits<Rhs>::StorageKind>::ret>::Base Base; 118 EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) 119 120 typedef typename internal::nested<Lhs>::type LhsNested; 121 typedef typename internal::nested<Rhs>::type RhsNested; 122 typedef typename internal::remove_reference<LhsNested>::type _LhsNested; 123 typedef typename internal::remove_reference<RhsNested>::type _RhsNested; 124 125 EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) 126 : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) 127 { 128 EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); 129 // require the sizes to match 130 EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) 131 eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); 132 } 133 134 EIGEN_STRONG_INLINE Index rows() const { 135 // return the fixed size type if available to enable compile time optimizations 136 if (internal::traits<typename internal::remove_all<LhsNested>::type>::RowsAtCompileTime==Dynamic) 137 return m_rhs.rows(); 138 else 139 return m_lhs.rows(); 140 } 141 EIGEN_STRONG_INLINE Index cols() const { 142 // return the fixed size type if available to enable compile time optimizations 143 if (internal::traits<typename internal::remove_all<LhsNested>::type>::ColsAtCompileTime==Dynamic) 144 return m_rhs.cols(); 145 else 146 return m_lhs.cols(); 147 } 148 149 /** \returns the left hand side nested expression */ 150 const _LhsNested& lhs() const { return m_lhs; } 151 /** \returns the right hand side nested expression */ 152 const _RhsNested& rhs() const { return m_rhs; } 153 /** \returns the functor representing the binary operation */ 154 const BinaryOp& functor() const { return m_functor; } 155 156 protected: 157 LhsNested m_lhs; 158 RhsNested m_rhs; 159 const BinaryOp m_functor; 160 }; 161 162 template<typename BinaryOp, typename Lhs, typename Rhs> 163 class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Dense> 164 : public internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type 165 { 166 typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> Derived; 167 public: 168 169 typedef typename internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type Base; 170 EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) 171 172 EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const 173 { 174 return derived().functor()(derived().lhs().coeff(rowId, colId), 175 derived().rhs().coeff(rowId, colId)); 176 } 177 178 template<int LoadMode> 179 EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const 180 { 181 return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(rowId, colId), 182 derived().rhs().template packet<LoadMode>(rowId, colId)); 183 } 184 185 EIGEN_STRONG_INLINE const Scalar coeff(Index index) const 186 { 187 return derived().functor()(derived().lhs().coeff(index), 188 derived().rhs().coeff(index)); 189 } 190 191 template<int LoadMode> 192 EIGEN_STRONG_INLINE PacketScalar packet(Index index) const 193 { 194 return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(index), 195 derived().rhs().template packet<LoadMode>(index)); 196 } 197 }; 198 199 /** replaces \c *this by \c *this - \a other. 200 * 201 * \returns a reference to \c *this 202 */ 203 template<typename Derived> 204 template<typename OtherDerived> 205 EIGEN_STRONG_INLINE Derived & 206 MatrixBase<Derived>::operator-=(const MatrixBase<OtherDerived> &other) 207 { 208 SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived()); 209 tmp = other.derived(); 210 return derived(); 211 } 212 213 /** replaces \c *this by \c *this + \a other. 214 * 215 * \returns a reference to \c *this 216 */ 217 template<typename Derived> 218 template<typename OtherDerived> 219 EIGEN_STRONG_INLINE Derived & 220 MatrixBase<Derived>::operator+=(const MatrixBase<OtherDerived>& other) 221 { 222 SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived()); 223 tmp = other.derived(); 224 return derived(); 225 } 226 227 } // end namespace Eigen 228 229 #endif // EIGEN_CWISE_BINARY_OP_H 230