Eigne Matrix Class Library

Dependents:   Eigen_test Odometry_test AttitudeEstimation_usingTicker MPU9250_Quaternion_Binary_Serial ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CwiseBinaryOp.h Source File

CwiseBinaryOp.h

00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_CWISE_BINARY_OP_H
00012 #define EIGEN_CWISE_BINARY_OP_H
00013 
00014 namespace Eigen {
00015 
00016 /** \class CwiseBinaryOp
00017   * \ingroup Core_Module
00018   *
00019   * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions
00020   *
00021   * \param BinaryOp template functor implementing the operator
00022   * \param Lhs the type of the left-hand side
00023   * \param Rhs the type of the right-hand side
00024   *
00025   * This class represents an expression  where a coefficient-wise binary operator is applied to two expressions.
00026   * It is the return type of binary operators, by which we mean only those binary operators where
00027   * both the left-hand side and the right-hand side are Eigen expressions.
00028   * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp.
00029   *
00030   * Most of the time, this is the only way that it is used, so you typically don't have to name
00031   * CwiseBinaryOp types explicitly.
00032   *
00033   * \sa MatrixBase::binaryExpr(const MatrixBase<OtherDerived> &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp
00034   */
00035 
00036 namespace internal {
00037 template<typename BinaryOp, typename Lhs, typename Rhs>
00038 struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
00039 {
00040   // we must not inherit from traits<Lhs> since it has
00041   // the potential to cause problems with MSVC
00042   typedef typename remove_all<Lhs>::type Ancestor;
00043   typedef typename traits<Ancestor>::XprKind XprKind;
00044   enum {
00045     RowsAtCompileTime = traits<Ancestor>::RowsAtCompileTime,
00046     ColsAtCompileTime = traits<Ancestor>::ColsAtCompileTime,
00047     MaxRowsAtCompileTime = traits<Ancestor>::MaxRowsAtCompileTime,
00048     MaxColsAtCompileTime = traits<Ancestor>::MaxColsAtCompileTime
00049   };
00050 
00051   // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor),
00052   // we still want to handle the case when the result type is different.
00053   typedef typename result_of<
00054                      BinaryOp(
00055                        typename Lhs::Scalar,
00056                        typename Rhs::Scalar
00057                      )
00058                    >::type Scalar;
00059   typedef typename promote_storage_type<typename traits<Lhs>::StorageKind,
00060                                            typename traits<Rhs>::StorageKind>::ret StorageKind;
00061   typedef typename promote_index_type<typename traits<Lhs>::Index,
00062                                          typename traits<Rhs>::Index>::type Index;
00063   typedef typename Lhs::Nested LhsNested;
00064   typedef typename Rhs::Nested RhsNested;
00065   typedef typename remove_reference<LhsNested>::type _LhsNested;
00066   typedef typename remove_reference<RhsNested>::type _RhsNested;
00067   enum {
00068     LhsCoeffReadCost = _LhsNested::CoeffReadCost,
00069     RhsCoeffReadCost = _RhsNested::CoeffReadCost,
00070     LhsFlags = _LhsNested::Flags,
00071     RhsFlags = _RhsNested::Flags,
00072     SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value,
00073     StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit),
00074     Flags0 = (int(LhsFlags) | int(RhsFlags)) & (
00075         HereditaryBits
00076       | (int(LhsFlags) & int(RhsFlags) &
00077            ( AlignedBit
00078            | (StorageOrdersAgree ? LinearAccessBit : 0)
00079            | (functor_traits<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)
00080            )
00081         )
00082      ),
00083     Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
00084     Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost),
00085     CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits<BinaryOp>::Cost)
00086   };
00087 };
00088 } // end namespace internal
00089 
00090 // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor
00091 // that would take two operands of different types. If there were such an example, then this check should be
00092 // moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as
00093 // currently they take only one typename Scalar template parameter.
00094 // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths.
00095 // So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to
00096 // add together a float matrix and a double matrix.
00097 #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \
00098   EIGEN_STATIC_ASSERT((internal::functor_is_product_like<BINOP>::ret \
00099                         ? int(internal::scalar_product_traits<LHS, RHS>::Defined) \
00100                         : int(internal::is_same<LHS, RHS>::value)), \
00101     YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
00102 
00103 template<typename BinaryOp, typename Lhs, typename Rhs, typename StorageKind>
00104 class CwiseBinaryOpImpl;
00105 
00106 template<typename BinaryOp, typename Lhs, typename Rhs>
00107 class CwiseBinaryOp : internal::no_assignment_operator,
00108   public CwiseBinaryOpImpl<
00109           BinaryOp, Lhs, Rhs,
00110           typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
00111                                            typename internal::traits<Rhs>::StorageKind>::ret>
00112 {
00113   public:
00114 
00115     typedef typename CwiseBinaryOpImpl<
00116         BinaryOp, Lhs, Rhs,
00117         typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
00118                                          typename internal::traits<Rhs>::StorageKind>::ret>::Base Base;
00119     EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp)
00120 
00121     typedef typename internal::nested<Lhs>::type LhsNested;
00122     typedef typename internal::nested<Rhs>::type RhsNested;
00123     typedef typename internal::remove_reference<LhsNested>::type _LhsNested;
00124     typedef typename internal::remove_reference<RhsNested>::type _RhsNested;
00125 
00126     EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp())
00127       : m_lhs(aLhs), m_rhs(aRhs), m_functor(func)
00128     {
00129       EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar);
00130       // require the sizes to match
00131       EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs)
00132       eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols());
00133     }
00134 
00135     EIGEN_STRONG_INLINE Index rows() const {
00136       // return the fixed size type if available to enable compile time optimizations
00137       if (internal::traits<typename internal::remove_all<LhsNested>::type>::RowsAtCompileTime==Dynamic)
00138         return m_rhs.rows();
00139       else
00140         return m_lhs.rows();
00141     }
00142     EIGEN_STRONG_INLINE Index cols() const {
00143       // return the fixed size type if available to enable compile time optimizations
00144       if (internal::traits<typename internal::remove_all<LhsNested>::type>::ColsAtCompileTime==Dynamic)
00145         return m_rhs.cols();
00146       else
00147         return m_lhs.cols();
00148     }
00149 
00150     /** \returns the left hand side nested expression */
00151     const _LhsNested& lhs () const { return m_lhs; }
00152     /** \returns the right hand side nested expression */
00153     const _RhsNested& rhs () const { return m_rhs; }
00154     /** \returns the functor representing the binary operation */
00155     const BinaryOp& functor () const { return m_functor; }
00156 
00157   protected:
00158     LhsNested m_lhs;
00159     RhsNested m_rhs;
00160     const BinaryOp m_functor;
00161 };
00162 
00163 template<typename BinaryOp, typename Lhs, typename Rhs>
00164 class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Dense>
00165   : public internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type
00166 {
00167     typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> Derived;
00168   public:
00169 
00170     typedef typename internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type Base;
00171     EIGEN_DENSE_PUBLIC_INTERFACE( Derived )
00172 
00173     EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const
00174     {
00175       return derived().functor()(derived().lhs().coeff(rowId, colId),
00176                                  derived().rhs().coeff(rowId, colId));
00177     }
00178 
00179     template<int LoadMode>
00180     EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const
00181     {
00182       return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(rowId, colId),
00183                                           derived().rhs().template packet<LoadMode>(rowId, colId));
00184     }
00185 
00186     EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
00187     {
00188       return derived().functor()(derived().lhs().coeff(index),
00189                                  derived().rhs().coeff(index));
00190     }
00191 
00192     template<int LoadMode>
00193     EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
00194     {
00195       return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(index),
00196                                           derived().rhs().template packet<LoadMode>(index));
00197     }
00198 };
00199 
00200 /** replaces \c *this by \c *this - \a other.
00201   *
00202   * \returns a reference to \c *this
00203   */
00204 template<typename Derived>
00205 template<typename OtherDerived>
00206 EIGEN_STRONG_INLINE Derived &
00207 MatrixBase<Derived>::operator-=(const MatrixBase<OtherDerived> &other)
00208 {
00209   SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived());
00210   tmp = other.derived();
00211   return derived();
00212 }
00213 
00214 /** replaces \c *this by \c *this + \a other.
00215   *
00216   * \returns a reference to \c *this
00217   */
00218 template<typename Derived>
00219 template<typename OtherDerived>
00220 EIGEN_STRONG_INLINE Derived &
00221 MatrixBase<Derived>::operator+=(const MatrixBase<OtherDerived>& other)
00222 {
00223   SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived());
00224   tmp = other.derived();
00225   return derived();
00226 }
00227 
00228 } // end namespace Eigen
00229 
00230 #endif // EIGEN_CWISE_BINARY_OP_H