Home | History | Annotate | Download | only in Core
      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 (at) inria.fr>
      5 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1 (at) 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_allows_mixing_real_and_complex<BINOP>::ret \
     98                         ? int(internal::is_same<typename NumTraits<LHS>::Real, typename NumTraits<RHS>::Real>::value) \
     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& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
    126       : m_lhs(lhs), m_rhs(rhs), 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(lhs.rows() == rhs.rows() && lhs.cols() == rhs.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 row, Index col) const
    173     {
    174       return derived().functor()(derived().lhs().coeff(row, col),
    175                                  derived().rhs().coeff(row, col));
    176     }
    177 
    178     template<int LoadMode>
    179     EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
    180     {
    181       return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(row, col),
    182                                           derived().rhs().template packet<LoadMode>(row, col));
    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